我正致力于在我的统一项目中为敌人AI执行上下文引导运动,并在确定每个角度的兴趣时遇到问题。
我有两门课: ContextMap和DirectionContext。DirectionContext是一个数据存储类。它包含一个角度,一个将该角度与移动方向相关联的Vector3,以及一个从0到1的浮动,这取决于该角度移动的有趣程度。
contextmap包含一个依赖于ContextMap的“细节”的DirectionContext列表。因此,如果我将细节设置为4,它将生成4 DirectionContexts,如果我将细节设置为8,它将生成8 DirectionContexts。角度从-180到+180。
我想要做的是编写一个函数,确定敌方游戏对象和玩家游戏对象之间的角度,然后将其与上下文地图中的每个DirectionContext进行比较。我希望它为每个DirectionContext设置利息浮动,这取决于对象和DirectionContexts角度之间的角度的相似性。我希望它把兴趣设置为1,如果方向是相同的,并将兴趣设置为0,如果角度之间的差异很大,它们可以是(360)。
我的问题是,我的脚本没有正确地设置角度的兴趣。如果玩家是在敌人的正上方,它就像预期的那样工作,但是如果玩家在对角线或对角线上,它就开始相反的工作。
这是一张正在发生的事情的图片:黑色物体是敌人,红色是人类。根据兴趣有多高,排队的时间会更长。
正如你在图像中所看到的,如果方向是向上/向下的,那么它工作的很好,但是当它是对角的或向两边的时候,事情就变得奇怪了。
下面是我在代码中得出的结论:
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;
}
}
背景地图:
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是玩家的位置,家长是对敌人的参考。
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;
}
}
我用这个函数调用来寻求:
private void PopulateInterestMap()
{
interestMap.Clear();
foreach (SteeringBehavior behavior in interestBehaviors)
{
interestMap = behavior.AddContext(interestMap, steeringContext);
}
}
谢谢你的帮助!
发布于 2021-02-10 03:13:10
我解决了。我将回答我自己的问题,因为网上没有真正涉及上下文引导行为的源代码,所以这里发布的代码可能会为其他人省去我遇到的麻烦。
现在我已经开始工作了,任何人乱搞我的指导行为,我强烈建议查看上下文指导(如果你谷歌上有一些很好的博客文章和关于它的好处的文章)。它完全解决了抖动问题与我的指导行为,并解决了所有问题的混合行为抵消自己在古怪的情况下。
问题不在于确定权重,而在于DirectionContext中将角度转换为方向向量的部分。
this.direction = new Vector3(Mathf.Sin(angle * Mathf.Deg2Rad), Mathf.Cos(angle * Mathf.Deg2Rad), 0).normalized;
应该是
this.direction = new Vector3(Mathf.Cos(angle * Mathf.Deg2Rad), Mathf.Sin(angle * Mathf.Deg2Rad), 0);
标准化并不是毁掉它的原因,而是因为对罪恶。归一化只是不必要的。
https://stackoverflow.com/questions/66123113
复制相似问题