【问题标题】:How do I make a texture rotate to face a Vector2?如何使纹理旋转以面对 Vector2?
【发布时间】:2015-05-02 00:51:08
【问题描述】:

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

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

编辑:

这是我的枪类的全部。构造函数获取一个位置(它将被放置在关卡中的位置)、一个射速(它每秒发射多少次)和一个子弹速度(子弹移动的速度)。有一个单独的子弹类,但这对于解释枪类是不必要的。

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);
    }
}

【问题讨论】:

  • 你能发布你的Gun课程吗?
  • 是的。枪类已发布。
  • @MickyDuncan - OP 正在执行 bullets.ToList(),因为他正在循环内执行 bullets.Remove(bullet)。所以 OP 需要做类似for (var i = bullets.Count - 1; i &gt;= 0; i--) 的事情,然后是bullets.RemoveAt(i);
  • @dbc 好地方,我的坏。

标签: c# rotation xna


【解决方案1】:

如果你只想要炮塔旋转中心之间的角度,它由Math.Atan2()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.

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

    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 秒前的位置,再加上子弹到达时他们的位置的线性推断在那个时候,可能被炮塔的最大角速度夹住了。
  • 为了使游戏更容易或更难,在炮手的距离估计中引入更大或更小的误差。

【讨论】:

  • 干杯。像魅力一样工作。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-19
  • 1970-01-01
相关资源
最近更新 更多