In my Unity game, I have one player and one enemy (it's a card game so this is always true).
I use a basic Singleton base class to access them from any sub-system in the game, like this:
public abstract class Singleton<T> : MonoBehaviour where T : Component
{
public static T instance;
protected virtual void Awake()
{
if (instance != null) {
string typename = typeof(T).Name;
Debug.LogWarning($"More that one instance of {typename} found.");
}
instance = this as T;
}
}
public class Player : Singleton<Player>
{
public void DoSomething();
}
public class Enemy : Singleton<Enemy>
{
public void DoSomething();
}
public class OtherPartOfGame : MonoBehaviour
{
void Start() {
Player.instance.DoSomething();
Enemy.instance.DoSomething();
}
}
But I want to pull out some common functionality into a base class CharacterBase.
Of course normally I'd just do this:
public abstract class CharacterBase : MonoBehaviour
{
public abstract void DoSomething();
}
public class Player : CharacterBase
{
public override void DoSomething() {}
}
public class Enemy : CharacterBase
{
public override void DoSomething() {}
}
But how do I also keep my generic Singleton in the mix, without using multiple inheritance?
Well the easiest way would be to just let your CharacterBase class inherit from Singleton like this
public abstract class CharacterBase<T> : Singleton<T> where T : Component
{
public abstract void DoSomething();
}
and then do
public class Player : CharacterBase<Player>
{
public override void DoSomething() { ... }
}
public class Enemy : CharacterBase<Enemy>
{
public override void DoSomething() { ... }
}
Everything else would just complicate it for no good reason.
Related
I have a problem,
I have 3 classes, one is a base class from which two other inherit,
the base class has a method with a counter,
if the time runs out it should destroy gameObject,
but other classes should have this method but in this conditional statement you could was to add anything
I just want to add an extra command to if from another class.
If you don't understand, feel free to ask, because I'm not good at explaining.
public class A : MonoBehaviour
{
public virtual void DestroyByTime()
{
timeLeft -= Time.deltaTime;
if (timeLeft <= 0)
{
/*
This statement should only be added in class B
|
v
gameSession.GameOver();
*/
Destroy(gameObject);
}
}
private void Update()
{
DestroyByTime();
}
}
public class B : A
{
public override void DestroyByTime()
{
/*
I want the base class if to be saved, but in if statement time runs out you lose
(gameSession.GameOver())
*/
}
}
You can create an OnTimeOut method an override only in derived class:
public class A : MonoBehaviour
{
public virtual void DestroyByTime()
{
timeLeft -= Time.deltaTime;
if (timeLeft <= 0)
{
OnTimeOut();
Destroy(gameObject);
}
}
protected virtual void OnTimeOut()
{
// Do nothing here
}
private void Update()
{
DestroyByTime();
}
}
public class B : A
{
protected override void OnTimeOut()
{
gameSession.GameOver();
}
}
What i wanted to do
I have a class (BlackBoard) that holdes data. and class NPC Gets the data from (BlackBoard). (NPC_Guard) inherits from (NPC) which uses (NPC_Movement) to move by using the data from (BlackBoard).
BlackBoard class
public sealed class BlackBoard : MonoBehaviour
{
#region Singleton
private static BlackBoard instance = null;
public static BlackBoard Instance
{
get
{
if (instance == null)
{
instance = new BlackBoard();
}
return instance;
}
}
#endregion
[SerializeField] List<Transform> NavigationPoints = new List<Transform>();
public List<Transform> Get_NavigationPoints() => NavigationPoints;
public void Set_NavigationPoints(List<Transform> T) => NavigationPoints = T;
}
NPC_Movement class
public class NPC_Movement
{
Vector3 direction;
List<Transform> _navigationPoints = null;
[SerializeField] public List<Transform> NavigationPoints;
{
get
{
if (_navigationPoints == null)
{
_navigationPoints = BlackBoard.Get_NavigationPoints();
}
return _navigationPoints;
}
}
BlackBoard BlackBoard = BlackBoard.Instance;
public void Move()
{
// A complex movement function which uses NavigationPoints
}
}
NPC class
public abstract class NPC : MonoBehaviour
{
[SerializeField] protected NPC_Movement Movement;
}
NPC_Guard class
public class NPC_Guard : NPC
{
void Update()
{
Movement.Move();
}
}
Problem
NPC_Movement class does not get the NavigationPoints List .
What am i doing wrong
please help
Here is my code. I keep getting the same error and I can't seem to resolve it.
using System.Collections;
using UnityEngine;
namespace CreatingCharacters.Abilities
{
[RequireComponent(typeof(PlayerMovementController))]
public class genjidash : Ability
{
[SerializeField] private float dashForce;
[SerializeField] private float dashDuration;
private PlayerMovementController playerMovementController;
private void Awake()
{
playerMovementController = GetComponent<PlayerMovementController>();
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.LeftShift))
{
StartCoroutine(Cast());
}
}
public override IEnumerator Cast()
{
playerMovementController.AddForce(Camera.main.transform.forward, dashForce);
yield return new WaitForSeconds(dashDuration);
playerMovementController.ResetImpact()
}
}
}
Here is the code that it is parented to:
using UnityEngine;
namespace CreatingCharacters.Abilities
{
public abstract class Ability : MonoBehaviour
{
public abstract void Cast();
}
}
Any advise would be great and thank you in advance.
class genjidash is derived from Ability, the return of Cast() in Ability is void, but in genjidash it's IEnumerator, so maybe you should change your base Cast() to
public abstract class Ability : MonoBehaviour
{
public abstract IEnumerator Cast();
}
If you can't change Ability's Cast(), you need
private void Update()
{
if (Input.GetKeyDown(KeyCode.LeftShift))
{
StartCoroutine(CastAndReset());
}
}
private IEnumrator CastAndReset()
{
Cast();
yield return new WaitForSeconds(dashDuration);
playerMovementController.ResetImpact()
}
public override void Cast()
{
playerMovementController.AddForce(Camera.main.transform.forward, dashForce);
}
I have a base class that has a function that does not know what one of the functions it calls will do. That behavior is defined in the child. The parents function is then called from the child. What is the correct syntax/method to make this work? Particularly what must I put instead of FunctionToBeDefinedLater Example follows:
public class ToolScript : MonoBehaviour {
public void isActive()
{
if (Input.GetKeyDown("space"))
{
Use();
}
}
FunctionToBeDefinedLater Use();
}
public class GunController : ToolScript
{
public void Use()
{
//Spawn bullet at this direction, this speed, give it spiral, tons of behavior etc. etc.
}
private void Update()
{
isActive();
}
}
public class FlamethrowerController : ToolScript
{
public void Use()
{
//Spawn fire at this direction, this speed, set tip of flamethrower to be red etc etc
}
private void Update()
{
isActive();
}
}
The Update function is from unity and is called every frame. Please let me know if I can clarify my question any further and I will do so as soon as possible. I do not know if this is referencing overriding, interfacing, or abstraction so I have tagged them all. I will fix this as soon as I know.
Based on what #Michael Curtiss directed me to I have updated my code to be:
public **abstract** class ToolScript : MonoBehaviour {
public void isActive()
{
if (Input.GetKeyDown("space"))
{
Use();
}
}
**public abstract void** Use();
}
public class GunController : ToolScript
{
public **override** void Use()
{
//Spawn bullet at this direction, this speed, give it spiral, tons of behavior etc. etc.
}
private void Update()
{
isActive();
}
}
public class FlamethrowerController : ToolScript
{
public **override** void Use()
{
//Spawn fire at this direction, this speed, set tip of flamethrower to be red etc etc
}
private void Update()
{
isActive();
}
}
Stars are not in code and are simply for emphasis. This code solved my problem.
I want to run metod in the class from another class and both of them atached to different obj
Two classes. the first is:
public class NewScore: MonoBehaviour {
public void updateScoreBy( int intr) {
Debug.Log("intr+4"+intr+4);
}
}
and the second is:
public class NewPlus: MonoBehaviour {
public NewScore newscore;
public void OnTriggerEnter2D(Collider2D obj) {
newscore.updateScoreBy(+1);
}
}
When I run my code I recive an arror "NullReferenceException: Object reference not set to an instance of an object" and it points on newscore.updateScoreBy(+1);
How can I fix it?
You need to initialize public NewScore newscore;: drag drop the object that contains that script on that variable in the Inspector panel
depending on what you want to do you could make the function static like:
public static void updateScoreBy(int intr)
{
Debug.Log("intr+4"+intr+4);
}
and call it with:
NewScore.updateScoreBy(1);
You didn't initialize newscore.
Change your NewPlus class like this so it will initialize newscore on construction.
public class NewPlus: MonoBehaviour {
public NewScore newscore;
public NewPlus(){
newscore=NewScore();
}
public void OnTriggerEnter2D(Collider2D obj) {
newscore.updateScoreBy(+1);
}
}