These would be the base classes like Npc and NpcTask.
public abstract class NpcTask
{
public Npc Npc { get; private set; }
public NpcTask(Npc npc)
{
Npc = npc;
}
public abstract void Update();
}
public abstract class Npc : MonoBehaviour
{
[HideInInspector]
public NavMeshAgent NavMeshAgent;
public NpcTask CurrentTask;
private void InitializeComponents()
{
NavMeshAgent = GetComponent<NavMeshAgent>();
}
protected virtual void Initialize()
{
InitializeComponents();
}
protected abstract void SetDefaultCurrentTask();
public void Log(object text)
{
Debug.Log("[" + name + "] " + text);
}
private void Start()
{
Initialize();
}
private void Update()
{
CurrentTask?.Update();
}
}
The next classes would be concrete and abstract implementations of the above to provide more flexibility to Npc's classes.
public class NpcEnemy : Npc
{
protected override void SetDefaultCurrentTask()
{
CurrentTask = new NpcEnemyTaskWander(this);
}
}
public abstract class NpcEnemyTask : NpcTask
{
public new NpcEnemy Npc { get { return base.Npc as NpcEnemy; } }
public NpcEnemyTask(Npc npc) : base(npc)
{
}
}
public class NpcEnemyTaskWander : NpcEnemyTask
{
public NpcEnemyTaskWander(Npc npc) : base(npc)
{
}
public override void Update()
{
// Wandering logic.
Debug.Log("NpcEnemyTaskWander.Update()");
}
}
public class NpcAllie : Npc
{
public List<NpcEnemy> Enemies;
private void Awake()
{
Enemies = new List<NpcEnemy>();
}
protected override void SetDefaultCurrentTask()
{
CurrentTask = new NpcAllieTaskFightEnemies(this);
}
}
public abstract class NpcAllieTask : NpcTask
{
public new NpcAllie Npc { get { return base.Npc as NpcAllie; } }
public NpcAllieTask(Npc npc) : base(npc)
{
}
}
public class NpcAllieTaskFightEnemies : NpcAllieTask
{
public NpcAllieTaskFightEnemies(Npc npc) : base(npc)
{
}
public override void Update()
{
// Fighting logic.
Npc.NavMeshAgent.SetDestination(Npc.Enemies[0].transform.position);
}
}
But then there would be the player which will not need pre-coded fighting logic as the fighting would be done by the person playing the game, but still would need a list of enemies to later know which enemies the player can attack or something like that.
public class Player : MonoBehaviour
{
public List<NpcEnemy> Enemies;
private void Awake()
{
Enemies = new List<NpcEnemy>();
}
private void Move()
{
// Whatever used to listen for input to move (just an example).
}
private void Attack()
{
// Whatever used to listen for input to attack (just an example).
}
private void Update()
{
Move();
Attack();
}
}
So as you can see both NpcAllies and the Player have list of NpcEnemies. I think the most feasible/simple solution would be to centralize the List in a singleton placed on the scene?
Lets say also each enemy could have a target which could be either the Player or a NpcAllie(i guess i would need to use GameObject class here to be more general?), so the Player and NpcAllie classes would need to know wheter they are a target or not to attack the right NpcEnemies.
public class NpcEnemy : Npc
{
public GameObject Target;
protected override void SetDefaultCurrentTask()
{
CurrentTask = new NpcEnemyTaskWander(this);
}
}