如何使纹理旋转以面对 Vector2?

How do I make a texture rotate to face a Vector2?

我正在用 C# XNA 4.0 制作游戏,我希望游戏中的枪支可以旋转以面对玩家并向他们射击。我在下面附上一张图片来总结这一点。

我已经实现了射击 AI,但我想知道如何让枪旋转以面向玩家。玩家 class 使用 Vector2 来表示它的位置,而枪 class 有一个浮点值来表示它的旋转,那么如何让枪旋转指向向量? (我很确定我知道如何画旋转的枪,我只需要知道如何改变枪的旋转。)

编辑:

这是我的枪 class 的全部。构造函数需要一个位置(它将被放置在关卡中的位置)、射速(大约每秒发射多少次)和子弹速度(子弹行进的速度)。有一颗单独的子弹 class,但这不是解释枪支的必要条件 class。

Vector2 m_position;
decimal m_fireRate;
decimal timer;
double m_bulletSpeed;
double rotation;
List<Bullet> bullets;

public Gun(Vector2 position, decimal fireRate, double bulletSpeed)
{
    m_position = position;
    m_fireRate = fireRate;
    timer = 0.0m;
    m_bulletSpeed = bulletSpeed;
    bullets = new List<Bullet>();
    rotation = 0.0;
}

public void Update()
{
    timer += 0.025m;

    if (timer % m_fireRate == 0)
    {
        //Create a new bullet based on the rate of fire (Obtain the gun texture from the main game class)
        bullets.Add(new Bullet(m_bulletSpeed, rotation, new Vector2(m_position.X + (MyGame.GunTex.Width / 3), m_position.Y + MyGame.GunTex.Height)));
    }

    foreach (Bullet bullet in bullets.ToList())
    {
        bullet.Update();

        //Delete the bullet if it is offscreen
        if (bullet.Position.X >= MyGame.WindowWidth || bullet.Position.X <= 0 || bullet.Position.Y >= MyGame.WindowHeight)
        {
            bullets.Remove(bullet);
        }
    }

    //ROTATE TO FOLLOW PLAYER POSITION
}

public void Draw(SpriteBatch spriteBatch)
{
    spriteBatch.Draw(MyGame.GunTex, m_position, Color.White);

    foreach(Bullet bullet in bullets)
    {
        bullet.Draw(spriteBatch);
    }
}

如果你只是想要炮塔旋转中心之间的角度,它由Math.Atan2() (in radians给出):

        var diffVec = playerPos - m_position;
        var angle = (float)Math.Atan2(diffVec.Y, diffVec.X);

        float newRotation;

        // To make the gun point at the player:
        newRotation = MathHelper.WrapAngle(angle); // Adjust to between -PI and PI.  Actually Atan2() returns in this range anyway.

如果您想将炮塔的旋转限制在某个最大 angular 速度,您可以这样做:

    const double maxAngularVelocity = Math.PI / 18.0; // 10 degrees per second.  Or whatever, your choice

    void UpdateRotation(Vector2 playerPos, decimal timeStep)
    {
        UpdateRotation(playerPos, timeStep, maxAngularVelocity);
    }

    void UpdateRotation(Vector2 playerPos, decimal timeStep, double maxAngularVelocity)
    {
        var diffVec = playerPos - m_position;
        var angle = (float)Math.Atan2(diffVec.Y, diffVec.X);

        float newRotation;

        // To make the gun point at the player:
        newRotation = MathHelper.WrapAngle(angle); // Adjust to between -PI and PI.  Actually Atan2() returns in this range anyway.

        // To make rotate towards the player with a maximum angular rotation, using the smallest direction
        var timeStepf = (float)timeStep;
        var diffAng = MathHelper.WrapAngle(newRotation - (float)rotation); // Adjust difference to between -PI and PI.
        diffAng = timeStepf * MathHelper.Clamp(diffAng / timeStepf, (float)-maxAngularVelocity, (float)maxAngularVelocity); // Clamp the difference by the maximum angular velocity.
        newRotation = MathHelper.WrapAngle((float)rotation + diffAng); // Adjust to between -PI and PI.

        rotation = newRotation;
    }

请注意,使用此方案,如果玩家大致位于枪手身后,并在枪手身后小于 180 度和大于 180 度之间来回跳动,则枪可以在不同方向之间振动。如果玩家在枪后接近 180 度,您可以通过记住之前的旋转速度并继续沿该方向继续解决此问题。

另一种可能性是

  • 定义炮手的反应时间(比如 0.25 秒)
  • 让枪手瞄准 0.25 秒前玩家的位置,并根据当时(0.25 秒前)与玩家的距离和子弹到达时的速度线性推断子弹到达时他们的位置当时的玩家,可能被炮塔的最大angular速度所限制。
  • 为了让游戏更简单或更难,在炮手的距离估计中引入更大或更小的误差。