首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >确定角度相似性的问题

确定角度相似性的问题
EN

Stack Overflow用户
提问于 2021-02-09 16:33:35
回答 1查看 48关注 0票数 0

我正致力于在我的统一项目中为敌人AI执行上下文引导运动,并在确定每个角度的兴趣时遇到问题。

我有两门课: ContextMap和DirectionContext。DirectionContext是一个数据存储类。它包含一个角度,一个将该角度与移动方向相关联的Vector3,以及一个从0到1的浮动,这取决于该角度移动的有趣程度。

contextmap包含一个依赖于ContextMap的“细节”的DirectionContext列表。因此,如果我将细节设置为4,它将生成4 DirectionContexts,如果我将细节设置为8,它将生成8 DirectionContexts。角度从-180到+180。

我想要做的是编写一个函数,确定敌方游戏对象和玩家游戏对象之间的角度,然后将其与上下文地图中的每个DirectionContext进行比较。我希望它为每个DirectionContext设置利息浮动,这取决于对象和DirectionContexts角度之间的角度的相似性。我希望它把兴趣设置为1,如果方向是相同的,并将兴趣设置为0,如果角度之间的差异很大,它们可以是(360)。

我的问题是,我的脚本没有正确地设置角度的兴趣。如果玩家是在敌人的正上方,它就像预期的那样工作,但是如果玩家在对角线或对角线上,它就开始相反的工作。

这是一张正在发生的事情的图片:黑色物体是敌人,红色是人类。根据兴趣有多高,排队的时间会更长。

链接到图像

正如你在图像中所看到的,如果方向是向上/向下的,那么它工作的很好,但是当它是对角的或向两边的时候,事情就变得奇怪了。

下面是我在代码中得出的结论:

代码语言:javascript
运行
复制
    public class DirectionContext
    {
        [SerializeField] private Vector3 direction;
        [SerializeField] private float interest;
        [SerializeField] private float angle;
        [SerializeField] private bool isExcluded = false;
        public Vector3 GetDirection() { return direction; }
        public float GetInterest() { return interest; }
        public void SetInterest(float value) { interest = value; }
        public void CheckInterestAndSet(float newInterest)
        {
            if (newInterest > interest)
                interest = newInterest;
        }
 
        public float GetAngle() { return angle; }
 
        public DirectionContext(float angle)
        {
            this.angle = angle;
            this.direction = new Vector3(Mathf.Sin(angle * Mathf.Deg2Rad), Mathf.Cos(angle * Mathf.Deg2Rad), 0).normalized;
        }
}

背景地图:

代码语言:javascript
运行
复制
    public class ContextMap
    {
        [SerializeField] private List<DirectionContext> contextMap = new List<DirectionContext>();
        public List<DirectionContext> GetContext()
        {
            return contextMap;
        }
 
        public void GenerateMap(int detail)
        {
            contextMap.Clear();
 
            for (int i = 0; i < detail; i++)
            {
                float angle = (360 / detail * i) - 180;
                contextMap.Add(new DirectionContext(angle));
            }
        }
 
        public void UpdateContext(int index, float interest)
        {
            contextMap[index].CheckInterestAndSet(interest);
        }
 
        public void DebugDrawMap(Vector3 position, Color color)
        {
            foreach (DirectionContext direction in contextMap)
            {
                Debug.DrawLine(position, (position + direction.GetDirection()).normalized * direction.GetInterest());
            }
        }
 
        public void Clear()
        {
            foreach (DirectionContext dir in contextMap)
                dir.Clear();
        }
    }

查找:(我忽略了SteeringContext,因为它是一个超级简单的类。它只包含可能很有趣的变量。在seek中使用的两个是parent和targetDestination。TargetDestination是玩家的位置,家长是对敌人的参考。

代码语言:javascript
运行
复制
    public class Seek : SteeringBehavior
    {
        public override ContextMap AddContext(ContextMap contextMap, SteeringContext steeringContext)
        {
            float angleToTarget = AngleBetween(Vector3.up, steeringContext.targetDestination - steeringContext.parent.transform.position);
            //Debug.Log(angleToTarget);
 
            for (int i = 0; i < contextMap.GetContext().Count; i++)
            {
 
                float delta = Mathf.Abs(Mathf.Max(angleToTarget, contextMap.GetContext()[i].GetAngle()) - Mathf.Min(angleToTarget, contextMap.GetContext()[i].GetAngle()));
                if (delta > 180)
                {
                    delta = 360f - delta;
                }
                float interest = 1f - delta / 180f;
 
                contextMap.UpdateContext(i, interest);
            }
 
            return contextMap;
        }
 
        private float AngleBetween(Vector3 vector1, Vector3 vector2)
        {
            float sin = vector1.x * vector2.y - vector2.x * vector1.y;
            float cos = vector1.x * vector2.x + vector1.y * vector2.y;
            return Mathf.Atan2(sin, cos) * (180) / Mathf.PI;
        }
    }

我用这个函数调用来寻求:

代码语言:javascript
运行
复制
        private void PopulateInterestMap()
        {
            interestMap.Clear();
 
            foreach (SteeringBehavior behavior in interestBehaviors)
            {
                interestMap = behavior.AddContext(interestMap, steeringContext);
            }
        }

谢谢你的帮助!

EN

回答 1

Stack Overflow用户

发布于 2021-02-10 03:13:10

我解决了。我将回答我自己的问题,因为网上没有真正涉及上下文引导行为的源代码,所以这里发布的代码可能会为其他人省去我遇到的麻烦。

现在我已经开始工作了,任何人乱搞我的指导行为,我强烈建议查看上下文指导(如果你谷歌上有一些很好的博客文章和关于它的好处的文章)。它完全解决了抖动问题与我的指导行为,并解决了所有问题的混合行为抵消自己在古怪的情况下。

问题不在于确定权重,而在于DirectionContext中将角度转换为方向向量的部分。

代码语言:javascript
运行
复制
        this.direction = new Vector3(Mathf.Sin(angle * Mathf.Deg2Rad), Mathf.Cos(angle * Mathf.Deg2Rad), 0).normalized;

应该是

代码语言:javascript
运行
复制
        this.direction = new Vector3(Mathf.Cos(angle * Mathf.Deg2Rad), Mathf.Sin(angle * Mathf.Deg2Rad), 0);

标准化并不是毁掉它的原因,而是因为对罪恶。归一化只是不必要的。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66123113

复制
相关文章

相似问题

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