【问题标题】:Triggers and Actions for Creature AI生物 AI 的触发器和操作
【发布时间】:2019-05-15 03:21:56
【问题描述】:

尽管我的生物 AI 工作(大部分情况下),但我觉得我设置它的方式非常低效,并且可能犯了一些编程罪。我想重写它以使其更干净、更高效且更易于维护,但我不确定从哪里开始。

在我的生物 AI 中,我有一个触发器列表,例如 OnSpawn、OnDeath 或 OnCollisionEnter。每个触发器中都有一个动作列表,例如“施放咒语”或“播放动画”。当触发器的条件满足时,它的动作列表被处理以检查它是否已经在我们的处理列表中,添加它,然后播放它们的关联动作。当触发器的条件不满足时,动作列表会从这个进程列表中移除,同样通过一些移除函数来清理行为。

我已经简化的一些代码:

    void Update()
    {
        if (canAct && !dead)
        {
            CheckTriggers();
            PlayAllActions();
       }
     }


   private void CheckTriggers()
    {
        for (int i = 0; i < actions.Length; i++)
        {
            switch (actions[i].trigger)
            {
                case ActionTrigger.Trigger.OnCollisionEnter:
                    if (isColliding)
                        AddActionList(actions[i].actionSetList);
                    else
                        RemoveActionList(actions[i].actionSetList);
                    break;

                case ActionTrigger.Trigger.UponBeingAttacked:
                    if (hasBeenAttacked)
                        AddActionList(actions[i].actionSetList);
                    break;
            }
        }
    }

    public void AddActionList(ActionSetList actionSetList)
    {
        bool containsItem = existingActionsList.Any(item => item == actionSetList);
        if (containsItem)
            return;

        existingActionsList.Add(actionSetList);
    }

    private void PlayAllActions()
    {
        if (existingActionsList.Count > 0)
            for (int i = 0; i < existingActionsList.Count; i++)
                ActionPlayEffect(existingActionsList[i]);
    }

    public void ActionPlayEffect(ActionSetList actionSetList)
    {
        for (int i = 0; i < actionSetList.Length; i++)
        {
            switch (actionSetList[i].type)
            {
                case ActionSet.Type.CastSpell:
                    if (spellRoutine == null && actionSetList[i].cooldownTimeRemaining <= 0)
                        spellRoutine = StartCoroutine(Cast(actionSetList[i]));
                    break;

                case ActionSet.Type.PlayAnim:
                    if (!isInActionPose)
                    {
                        animator.SetTrigger("ActionTrigger");
                        animator.SetInteger("Action", (int)actionSetList[i].animToPlay+1);
                        isInActionPose = true;
                    }
                    break;
            }
        }
    }

    public void RemoveActionList(ActionSetList actionSetList)
    {
        bool containsItem = existingActionsList.Any(item => item == actionSetList);
        if (containsItem)
        {
            ActionRemoveEffect(actionSetList);
            existingActionsList.Remove(actionSetList);
        }
    }

    public void ActionRemoveEffect(ActionSetList actionSetList)
    {
        for (int i = 0; i < actionSetList.Length; i++)
        {
            switch (actionSetList[i].type)
            {
                case ActionSet.Type.CastSpell:
                    CancelCast();
                    break;

                case ActionSet.Type.PlayAnim:
                    animator.SetTrigger("ActionTrigger");
                    animator.SetInteger("Action", 0);
                    isInActionPose = false;
                    break;
            }
        }
    }

我可以做些什么来构建更高效的生物 AI?

【问题讨论】:

  • 看到这个不完整(非功能性)的例子,很难提出任何建议。什么对你来说“更有效率”?什么样的游戏引擎驱动这个?这听起来就像是在基于循环的游戏中运行的简单的事件驱动 AI,但您没有详细说明问题。什么不适用于您当前的操作队列?在大多数应用程序中,队列处理时间是微不足道的。

标签: c# unity3d artificial-intelligence


【解决方案1】:

我可能会使用delegates 编写一个类似的系统。

委托在某种程度上可以被认为是一个包含方法列表的变量。如果您执行该委托,那么您将执行它拥有的所有方法。

这将允许您将这样的方法添加到方法列表中,然后在需要时调用。

delegate void OnSpawn(GameObject gameObject); //Create delegate type
public OnSpawn onSpawn; //Create variable from delegate type

void SetUpStats(Gameobject gameObject){
    //Set hp, initialize spells
}

void SetUpAnimations(GameObject gameObject){
    //Initialize animations
}

void PlaySpawnSound(GameObject gameObject){
    //Play a spawn sound
}

void Start(){
    if (onSpawn == null) //Add content to delegate
    {
        onSpawn = new OnSpawn(SetUpStats); //You may be able to write onSpawn = SetUpStats; instead, for shorter code. But please test it.
        onSpawn += SetUpAnimations;
        onSpawn += PlaySpawnSound;
    }
}

void Spawn(){
    onSpawn(gameObject); 

    //Call delegate, invoking all methods stored in it. 
    //Note that they all receive the same input. In this case the gameObject.
    //You can give them any input you want, so long as you define it in the delegate type.
    //I chose a gameObject as you can get all components and more from it.
}

如果您有任何疑问或想知道的事情,请告诉我。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-14
    • 2021-07-06
    • 1970-01-01
    • 2019-11-04
    • 2021-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多