我有一个玩家精灵通过旋转移动并且它的旋转不断变化但是如果目标位于其左侧或右侧并且不在前方或后方45度范围内,我还需要确定转动。
我已经编写了这段代码,我认为该代码应该可行,但似乎只是偶尔选择一方而另一方稍微提高。
public void GrappleCheck(AsteroidSprite target)
{
float targetTragectory = (float)Math.Atan2(Position.Y - target.Position.Y, Position.X - target.Position.X);
if (targetTragectory < 0)
targetTragectory += (float)(Math.PI * 2);
if (Rotation < 0)
Rotation += (float)(Math.PI * 2);
if ((targetTragectory > Rotation + (float)(MathHelper.PiOver4 / 2)) && (targetTragectory < Rotation + (float)(Math.PI - (MathHelper.PiOver4 / 2))))
{
target.Distance = Vector2.Distance(Position, target.Position);
if (RightTarget != null)
{
if (RightTarget.Distance > target.Distance)
{
RightTarget.isTarget = false;
RightTarget = target;
RightTarget.ColorTint = Color.Blue;
RightTarget.isTarget = true;
}
}
else
{
RightTarget = target;
RightTarget.ColorTint = Color.Blue;
RightTarget.isTarget = true;
}
}
else if ((targetTragectory < Rotation - (float)(MathHelper.PiOver4 / 2)) && (targetTragectory > Rotation - (float)(Math.PI - (MathHelper.PiOver4 / 2))))
{
target.Distance = Vector2.Distance(Position, target.Position);
if (LeftTarget != null)
{
if (LeftTarget.Distance > target.Distance)
{
LeftTarget.isTarget = false;
LeftTarget = target;
LeftTarget.ColorTint = Color.Red;
LeftTarget.isTarget = true;
}
}
else
{
LeftTarget = target;
LeftTarget.ColorTint = Color.Red;
LeftTarget.isTarget = true;
}
}
else
{
target.isTarget = false;
}
if (controlInput.IsHeld(Keys.X))
{
Speed = Speed;
}
答案 0 :(得分:1)
使用角度可能非常烦人。以下是一些在不使用角度的情况下解决问题的方法:
首先,我们需要目标方向和运动方向:
var targetDirection = target.Positon - Position;
// Update this to match the actual direction. The following line assumes that
// a rotation of 0 results in the right direction.
var movementDirection = new Vector2((float)Math.Cos(Rotation), (float)Math.Sin(Rotation));
您要解决的第一个问题是确定目标是否在45°锥形范围内。您可以使用以下公式计算实际角度:
var dot = Vector2.Dot(myDirection, targetDirection);
//if dot is negative, then target is behind me, so just use the absolute value
var cos = Math.Abs(dot) / myDirection.Length() / targetDirection.Length();
var angle = Math.Acos(cos);
if(angle < MathHelper.PiOver4 / 2) //45° opening angle
; // within cone
else
; // outside cone
如果目标位于左侧或右侧,则第二个问题是确定。我们使用一个与myDirection
正交的向量,并指向左侧:
//assuming that +x is the right axis and +y is the down axis
var normal = new Vector2(myDirection.Y, -myDirection.X);
dot = Vector2.Dot(normal, targetDirection);
if(dot > 0)
; // target is on the left side
else
; // target is on the right side
我希望这会使您的代码清理更容易,更易于理解。您应该考虑在单独的方法中提取一些代码,以使其更具可读性。
答案 1 :(得分:0)
好的我已经解决了,玩家轮换可以是0到2 x PI +或 - ,保持+ +虽然我放入
if (Rotation < 0)
Rotation += (float)Math.PI * 2;
对目标的旋转可以是0-PI或0 - 负PI,具体取决于您声明atan2的方式以及玩家所在的位置。
//This works out the difference from the targets rotation to the players rotation.
RotationDif = TargetRotation - PlayerRotation;
//If the difference is greater than PI then when we check to see if its is within
//the range 0-PI or 0-Negative PI it will be missed whilst still possibly being on
//either side of the player, adding PI * 2 to the targets rotation basically spins
//it past the player so the Difference will be the shortest angle.
if(Math.Abs(RotationDif) > Math.PI)
RotationDif = TargetRotation + (float)(Math.PI * 2) - PlayerRotation;
//Next we check to see if the target is left(negative) or
//the right(positive), the negative/positive assignment will depend
//on which way round you did the atan2 to get the target rotation.
if ((RotationDif > 0) && (RotationDif < (float)Math.PI))
//Insert right target code here
else if ((RotationDif < 0) && (RotationDif > -(float)Math.PI))
//Insert left target code here
else
//Insert no target code here to cover all basis
就是这样,我已经使If(RotationDif> 0)等不同,所以通过制作它可以忽略前后45度角
If ((RotationDif > (float)(Math.PI / 8) &&
(RotationDif < (float)(Math.PI - (Math.PI / 8)))
与另一方相反,希望这对其他人有所帮助,因为我花了将近两个星期的时间来解决问题:/