如何添加概率来评估行为树节点?

问题描述 投票:0回答:1

我正在 Unity 中开发一款游戏,并决定使用 BehaviourTrees 来管理敌人 AI。 其中一名敌人有能力躲避玩家的攻击。不过这个能力应该只会出现几次,所以我就考虑让它出现的概率更大。 也可以使用冷却来做到这一点。但我在这两种方法的实施上都面临着困难。

为了实现该树,我创建了以下脚本: Node.cs

public enum NodeState
    {
        RUNNING,
        SUCCESS,
        FAILURE
    }

    public class Node
    {

        protected NodeState state;

        public Node parent;
        protected List<Node> children = new List<Node>();

        private Dictionary<string, object> dataContext = new Dictionary<string, object>();

        public Node()
        {
            parent = null;
        }

        public Node(List<Node> children)
        {
            foreach (Node child in children)
            {
                Attach(child);
            }
        }

        private void Attach(Node node)
        {
            node.parent = this;
            children.Add(node);
        }

        public virtual NodeState Evaluate() => NodeState.FAILURE;

            public void SetData(string key, object value)
        {
            dataContext[key] = value;
        }

        public object GetData(string key)
        {
            object value = null;

            if (dataContext.TryGetValue(key, out value))
                return value;

            Node node = parent;

            while (node != null)
            {
                value = node.GetData(key);
            
                if (value != null)
                    return value;
            
                node = node.parent;
            }

            return null;
        }
    
        public bool ClearData(string key)
        {

            if (dataContext.ContainsKey(key))
            {
                dataContext.Remove(key);
                return true;
            }

            Node node = parent;

            while (node != null)
            {
                bool cleared = node.ClearData(key);
            
                if (cleared)
                    return true;
            
                node = node.parent;
            }

            return false;
        }

    }

Tree.cs

public abstract class Tree : MonoBehaviour
    {
        private Node root = null;

        public virtual void Start()
        {
            root = SetupTree();
        }

        private void Update()
        {
            if (root != null)
            {
                root.Evaluate();
            }
        }

        protected abstract Node SetupTree();
    }

我还实现了一些从节点派生的其他类,例如Selector.csSequence.cs 为了创建一个依赖于概率的节点,我考虑创建另一个从该节点派生的类,如下所示:

public class Probability : Node
{
    private Node child;
    private float probability;
    
    public Probability(Node child, float probability)
    {
        this.child = child;
        this.probability = probability;
    }

    public override NodeState Evaluate()
    {
        if (probability <= Random.value)
        { 
            return child.Evaluate();
        }

        return NodeState.FAILURE;
    }
}

我在敌人控制器中使用这些类如下: 敌人剑圣BT.cs

public class EnemySwordmasterBT : EnemyBT
{
    
    [SerializeField] public float evasionDistance = 2f;
    [SerializeField] public float evasionProbability = 0.3f;

    protected override Node SetupTree()
    {
        
        Node root = new Selector(new List<Node>
        {
            new Sequence(new List<Node>
            {
                new CheckTargetAttacking(Player.Instance.GetHolder().GetHoldableObject().GetComponent<IWeapon>()),
                new Probability(new TaskEvade(targetTransform, movementNavMesh, evasionDistance), evasionProbability),
            }),
            new Sequence(new List<Node>
            {
                new CheckTargetInAttackRange(transform, targetTransform, attackTargetDistance),
                new TaskAttack(weapon)
            }),
            new Sequence(new List<Node>
            {
                new CheckIsNotAttacking(weapon),
                new TaskChase(targetTransform, movementNavMesh)
            })
        });

        return root;
    }
}

但是当 Evaluate() 方法在 Update() 中运行时,它会在每帧生成几个随机数。这就是为什么闪避动作,TaskEvade,总是发生的原因。

我很难解决这个问题。

所以我想寻求帮助来解决这个问题。任何改进我当前设计的建议也将不胜感激 =)

我还尝试了一些使用冷却想法的解决方案,但所以问题不会变得太大,我还不会添加它们。但如果您发现相关,请告诉我。

c# unity-game-engine tree artificial-intelligence game-development
1个回答
0
投票

您在 Unity 中使用行为树来管理敌人 AI 真是太棒了。为了解决概率节点始终触发的问题,您只需在每个决策周期生成一次随机数,并为所有基于概率的节点一致地使用该数字。

您可以尝试生成一个随机数一次:在您的 Tree 类中,在每个决策周期开始时生成一个随机数。在该周期内,该随机数将在树中所有基于概率的节点之间共享。

public class Tree : MonoBehaviour
    {
    private Node root = null;
    private float randomValue;

    public virtual void Start()
    {
        root = SetupTree();
    }

    private void Update()
    {
        randomValue = Random.value; // Generate a random number for this decision-making cycle

        if (root != null)
        {
            root.Evaluate();
        }
    }

    // Rest of your Tree class...
}

使用相同的随机数:修改概率节点以使用决策周期开始时生成的共享随机数。

public class Probability : Node
{
    private Node child;
    private float probability;

    public Probability(Node child, float probability)
    {
        this.child = child;
        this.probability = probability;
    }

    public override NodeState Evaluate()
    {
        if (probability <= randomValue) // Use the random number generated in the Tree class
        {
            return child.Evaluate();
        }

        return NodeState.FAILURE;
    }
}

通过在每个决策周期生成一次随机数,您可以确保树中所有基于概率的节点都使用相同的随机值进行评估。这种方法应该有助于防止闪避动作在每一帧中发生,并使其根据指定的概率发生。

让我知道这是否有效!

© www.soinside.com 2019 - 2024. All rights reserved.