首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >避免播放器和npc类之间的重复代码,这些代码派生于Unity的MonoBehaviour

避免播放器和npc类之间的重复代码,这些代码派生于Unity的MonoBehaviour
EN

Software Engineering用户
提问于 2020-05-10 20:56:09
回答 2查看 248关注 0票数 1

这些是像Npc和NpcTask这样的基类。

代码语言:javascript
复制
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();
    }
}

接下来的类将是上述的具体和抽象的实现,以便为Npc的类提供更大的灵活性。

代码语言:javascript
复制
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);
    }
}

但是这样的玩家将不需要预先编码的战斗逻辑,因为战斗将由玩游戏的人来完成,但仍然需要一个敌人列表,以便稍后知道玩家可以攻击哪些敌人或诸如此类的东西。

代码语言:javascript
复制
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();
    }
}

因此,您可以看到,NpcAllies和播放器都有NpcEnemies列表。我认为最可行/最简单的解决办法,是把名单集中在现场的单身人士身上?

我们还可以说,每个敌人都可能有一个目标,可以是玩家,也可以是NpcAllie (我想我需要在这里使用GameObject类才能更通用?),所以玩家和NpcAllie类需要知道他们是目标还是不攻击正确的NpcEnemies。

代码语言:javascript
复制
public class NpcEnemy : Npc
{
    public GameObject Target;

    protected override void SetDefaultCurrentTask()
    {
        CurrentTask = new NpcEnemyTaskWander(this);
    }
}
EN

回答 2

Software Engineering用户

发布于 2020-05-10 21:18:16

你会把这两类分开。你应该把这看作是一种“有行为”的关系,而不是“是”的关系。

创建一个类Npc和一个类FightingBehaviour。你把他们都加到战斗中去了。如果您需要从Fighter访问Npc中的方法,您将使用GetComponent<Npc>()

FightingBehaviour甚至不必继承MonoBehaviour。

所以你得到了类似的东西:

代码语言:javascript
复制
public interface IFighter
{
    GameObject gameObject;
    void Shoot();
}


public class PlayerFighter : MonoBehaviour, IFighter
{
    FightingBehaviour _FightingBehaviour;

    private void Awake()
    {
        _FightingBehaviour = new FighterBehaviour(this);
    }
}



public class FightingBehaviour
{
    IFighter _Fighter;

    public List<Enemy> Enemies { get; private set; }


    public FightingBehaviour(IFighter fighter)
    {
        _Fighter = fighter;
    }


    public Enemy GetClosestEnemy()
    {
        // implement using _Fighter
    }


    public Enemy GetEnemiesInView()
    {
        // implement using _Fighter
    }


    // etc


    public Enemy AttackClosestEnemy()
    {
        var enemy = GetClosestEnemy();

        var direction = _Fighter.gameObject.transform.position - enemy.gameObject.transform.position; // get direction to enemy

        _Fighter.RotateTo(direction);
        _Fighter.Shoot();
    }
}
票数 2
EN

Software Engineering用户

发布于 2021-06-07 01:37:43

备选办法:

代码语言:javascript
复制
public class Character : MonoBehavior
{
// put the common behavior here
}

public class NPC : Character
{
}

public class NPCEnemy : NPC
{
}

public class NPCAlly : NPC
{
}

public class Player : Character
{
}
票数 0
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/409972

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档