EnemyAI 在 Y 轴上以相反方向旋转
EnemyAI rotating on Y-axis in opposite direction
在战旗消失并且玩家进入敌人的战区后,我想在玩家移动时跟踪玩家并确保敌人的 Z 轴始终指向玩家。
当玩家进入战斗区域后,敌人会自动将玩家标记为目标,但有可能在战斗刚开始时Z轴未指向敌人的目标。我决定在战旗熄灭时从敌人的 Z 轴投射一条射线,然后旋转敌人直到射线和玩家相交,这告诉我敌人的 Z 轴已正确对齐。
敌人总是有一个指向其当前目标的引用。我的想法是,一旦敌人最初发现了它的目标,它就可以保存最近发现的位置,然后取 CurrentTargetPosition.x 和 LastSpottingPosition.x 的增量,如果增量为正,则向右旋转,如果增量为负向左旋转。
问题:我的数学或逻辑一定有缺陷,因为虽然它有时有效,但有时敌人会随机向相反方向旋转,光线投射基本上会走很长的路来击中玩家而不是预期的最短路线。下面的代码。
//create ray from enemy position orgin and point it on the Z-Axis
Ray ray = new Ray(CurrentEnemyTransform.position, CurrentEnemyTransform.forward);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, 50f))
{
Debug.DrawLine(ray.origin, hit.point);
//ray hits current enemy target
if (hit.transform == CurrentTargetTransform)
{
//check if enemy has seen its target before while in this battle
//or is it the first time
if (enemy.hasTargetLastPosition)
//replace old last seen position with most recent spotting
enemy.ReplaceTargetLastPosition(hit.transform.position);
//or add the first spotting of target while in this battle
else enemy.AddTargetLastPosition(hit.transform.position);
}
//ray is not intersectiing with the enemy's current target so rotate to look for it
if (hit.transform != CurrentTargetTransform)
{
//check if enemy has seen its target once before in battle
if (enemy.hasTargetLastPosition)
{
//since last spotting has my target moved more to the left or right?
if (enemy.targetLastPosition.value.x > CurrentTargetTransform.position.x)
{
//rotate right
CurrentEnemyTransform.Rotate(-Vector3.up, 5f, Space.Self);
}
//rotate left
else CurrentEnemyTransform.Rotate(Vector3.up, 5f, Space.Self);
}
//never seen target yet during this battle so default rotation to right till you found it
else CurrentEnemyTransform.Rotate(-Vector3.up, 5f, Space.Self);
}
一个明显的问题是这一行:
if (enemy.targetLastPosition.value.x > CurrentTargetTransform.position.x)
这应该会检查目标是否在敌人瞄准位置的右侧。但它并不适用于所有可能的职位。 (图片翻转 Z-axis 中的坐标 - 那么它仍然有效吗?)
正确的方法是使用 2D cross-product:
(Ax, Az) x (Bx, Bz) = Ax * Bz - Az * Bx
如果矢量 A
相对于 B
顺时针旋转,则为正,反之亦然。
(此外,我们需要检查相对于敌人的 相对 位置,而不是他们的世界位置;要做到这一点,只需减去 CurrentEnemyTransform.position
)
private static bool isOnRight(Vector3 a, Vector3 b)
{
return a.x * b.z - a.z * b.x > 0.0f;
}
//...
// is last known position on the right of the actual position?
if (isOnRight(enemy.targetLastPosition - CurrentEnemyTransform.position,
CurrentTargetTransform.position - CurrentEnemyTransform.position))
{
// rotate *left*, not right
CurrentEnemyTransform.Rotate(Vector3.up, -5f, Space.Self);
}
else CurrentEnemyTransform.Rotate(Vector3.up, 5f, Space.Self);
还有其他可以对此进行的改进,例如让敌人 准确地 瞄准目标,而不是在 5 度范围内这样做。但这应该是一种粗略的方法。
在战旗消失并且玩家进入敌人的战区后,我想在玩家移动时跟踪玩家并确保敌人的 Z 轴始终指向玩家。
当玩家进入战斗区域后,敌人会自动将玩家标记为目标,但有可能在战斗刚开始时Z轴未指向敌人的目标。我决定在战旗熄灭时从敌人的 Z 轴投射一条射线,然后旋转敌人直到射线和玩家相交,这告诉我敌人的 Z 轴已正确对齐。
敌人总是有一个指向其当前目标的引用。我的想法是,一旦敌人最初发现了它的目标,它就可以保存最近发现的位置,然后取 CurrentTargetPosition.x 和 LastSpottingPosition.x 的增量,如果增量为正,则向右旋转,如果增量为负向左旋转。
问题:我的数学或逻辑一定有缺陷,因为虽然它有时有效,但有时敌人会随机向相反方向旋转,光线投射基本上会走很长的路来击中玩家而不是预期的最短路线。下面的代码。
//create ray from enemy position orgin and point it on the Z-Axis
Ray ray = new Ray(CurrentEnemyTransform.position, CurrentEnemyTransform.forward);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, 50f))
{
Debug.DrawLine(ray.origin, hit.point);
//ray hits current enemy target
if (hit.transform == CurrentTargetTransform)
{
//check if enemy has seen its target before while in this battle
//or is it the first time
if (enemy.hasTargetLastPosition)
//replace old last seen position with most recent spotting
enemy.ReplaceTargetLastPosition(hit.transform.position);
//or add the first spotting of target while in this battle
else enemy.AddTargetLastPosition(hit.transform.position);
}
//ray is not intersectiing with the enemy's current target so rotate to look for it
if (hit.transform != CurrentTargetTransform)
{
//check if enemy has seen its target once before in battle
if (enemy.hasTargetLastPosition)
{
//since last spotting has my target moved more to the left or right?
if (enemy.targetLastPosition.value.x > CurrentTargetTransform.position.x)
{
//rotate right
CurrentEnemyTransform.Rotate(-Vector3.up, 5f, Space.Self);
}
//rotate left
else CurrentEnemyTransform.Rotate(Vector3.up, 5f, Space.Self);
}
//never seen target yet during this battle so default rotation to right till you found it
else CurrentEnemyTransform.Rotate(-Vector3.up, 5f, Space.Self);
}
一个明显的问题是这一行:
if (enemy.targetLastPosition.value.x > CurrentTargetTransform.position.x)
这应该会检查目标是否在敌人瞄准位置的右侧。但它并不适用于所有可能的职位。 (图片翻转 Z-axis 中的坐标 - 那么它仍然有效吗?)
正确的方法是使用 2D cross-product:
(Ax, Az) x (Bx, Bz) = Ax * Bz - Az * Bx
如果矢量 A
相对于 B
顺时针旋转,则为正,反之亦然。
(此外,我们需要检查相对于敌人的 相对 位置,而不是他们的世界位置;要做到这一点,只需减去 CurrentEnemyTransform.position
)
private static bool isOnRight(Vector3 a, Vector3 b)
{
return a.x * b.z - a.z * b.x > 0.0f;
}
//...
// is last known position on the right of the actual position?
if (isOnRight(enemy.targetLastPosition - CurrentEnemyTransform.position,
CurrentTargetTransform.position - CurrentEnemyTransform.position))
{
// rotate *left*, not right
CurrentEnemyTransform.Rotate(Vector3.up, -5f, Space.Self);
}
else CurrentEnemyTransform.Rotate(Vector3.up, 5f, Space.Self);
还有其他可以对此进行的改进,例如让敌人 准确地 瞄准目标,而不是在 5 度范围内这样做。但这应该是一种粗略的方法。