Sprite Rotation XNA - PullRequest
       17

Sprite Rotation XNA

1 голос
/ 02 марта 2012

Я пытаюсь повернуть спрайт лицом к мыши, увеличивая и уменьшая вращение с помощью радиуса поворота. Он работает до тех пор, пока мышь не окажется в верхнем левом углу и не переместится в верхний правый. У меня так, что если разность углов больше, чем текущее значение поворота, вращение спрайта увеличивается, в противном случае уменьшается. Поэтому, когда он идет от 6,5 радиана до 0, он вращается против часовой стрелки на 350 градусов, а не по часовой стрелке на 15 градусов. Я и другие работали над этим весь день и понятия не имеем, как это решить. Мой код ниже:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using System.IO;

namespace Physics
{
public class Ship
{
    public Texture2D Texture { get; set; }
    public Vector2 Position { get; set; }
    public double Rotation { get; set; }
    MouseState prevState, currState;

    Vector2 A, B;

    public const double NINETY_DEGREES = 1.57079633;

    double turningRadius = 2 * (Math.PI / 180);
    double targetRotation, rotationDifferential;

    public Ship(Texture2D texture, Vector2 position)
    {
        Texture = texture;
        Position = position;
        A = new Vector2(Position.X, Position.Y);
        B = new Vector2(Mouse.GetState().X, Mouse.GetState().Y);
        Rotation = 0;
    }

    public void Update()
    {
        currState = Mouse.GetState();
        A.X = Position.X;
        A.Y = Position.Y;
        B.X = currState.X;
        B.Y = currState.Y;

        if (B.Y > A.Y)
            if (B.X > A.X) //Bottom-right
                targetRotation = Math.Atan((B.Y - A.Y) / (B.X - A.X)) + NINETY_DEGREES;
            else //Bottom-left
                targetRotation = (Math.Atan((A.X - B.X) / (B.Y - A.Y))) + (NINETY_DEGREES * 2);
        else
            if (B.X > A.X) //Top-right
                targetRotation = Math.Atan((B.X - A.X) / (A.Y - B.Y));
            else //Top-Left
                targetRotation = Math.Atan((A.Y - B.Y) / (A.X - B.X)) + (NINETY_DEGREES * 3);

        if (Rotation > targetRotation)
            Rotation -= turningRadius;
        else
            Rotation += turningRadius;

        prevState = currState;
    }

    public void Draw(SpriteBatch spriteBatch)
    {
        spriteBatch.Draw(Texture, Position, null, Color.White, (float)Rotation, new Vector2(Texture.Width / 2, Texture.Height / 2), 0.5f,
            SpriteEffects.None, 0.0f);
    }
}

}

Ответы [ 4 ]

3 голосов
/ 02 марта 2012

Позвольте мне убедиться, что я понимаю.У вас есть вектор (Cos(Rotation), Sin(Rotation), представляющий, в каком направлении направлен ваш объект;другой вектор (B.X-A.X, B.Y-A.Y), представляющий направление, в котором вы хотите повернуть свой объект;и вы хотите знать, вращать ли ваш объект (первый вектор) по часовой стрелке или против часовой стрелки, чтобы повернуть его в направлении второго вектора?

Простой, просто трактует их обоих как трехмерные векторы (установите Z = 0) и возьмите их перекрестное произведение .

  • Если результирующий вектор содержит положительный компонент Z, повернитепротив часовой стрелки
  • Если он имеет положительный компонент Z, поверните по часовой стрелке
  • Если компонент Z равен 0, оба вектора параллельны, поэтому просто проверьте, не стоят ли они напротивнаправления (и вращаются в любую сторону) или в том же направлении (ничего не делать!)

Это работает из-за правила для правой руки, который определяет перекрестные продукты.

1 голос
/ 02 марта 2012

Это должно просто изменить направление к тому, что быстрее.

spin = targetRotation - Rotation;  
if (abs(spin) > Math.PI) 
  spin *= -1;
if (spin > 0
  Rotation += turningRadius;
else
  Rotation -= turningRadius;

Редактировать: 180 изменен на Math.PI

0 голосов
/ 02 марта 2012

Попробуйте следующее (это некоторый код из игры про танки, которую я сделал, но не уверен, что он все еще применяется в этом сценарии). Я урезал его до самого необходимого:

using System;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace Physics
{
    public class Ship
    {
        public Texture2D Texture { get; set; }
        public Vector2 Position { get; set; }
        public double Rotation { get; set; }
        private MouseState currState;

        public Ship(Texture2D texture, Vector2 position)
        {
            Texture = texture;
            Position = position;
            Rotation = 0;
        }

        public void Update()
        {
            currState = Mouse.GetState();

            var mouseloc = new Vector2(currState.X, currState.Y);
            Vector2 direction = Position - mouseloc;
            Rotation = Math.Atan2(direction.Y, direction.X) + MathHelper.PiOver2;
        }

        public void Draw(SpriteBatch spriteBatch)
        {
            spriteBatch.Draw(Texture, Position, null, Color.White, (float) Rotation,
                             new Vector2(Texture.Width/2, Texture.Height/2), 0.5f,
                             SpriteEffects.None, 0.0f);
        }
    }
}

Я думаю, вам нужно немного больше математики, чтобы изменить скорость вращения, я вернусь, если найду решение. Кроме того, этот код будет отличаться в зависимости от поворота спрайта по умолчанию. В моем примере предполагается, что спрайт направлен вниз (6 часов). Надеюсь, это направит вас в правильном направлении!

0 голосов
/ 02 марта 2012

Отредактируйте мои извинения. Я убрал свою голову с моей задней стороны и фактически прочитал вопрос на этот раз. Итак, вот хороший маленький метод, который я потратил ~ 3 часа на написание сегодня вечером.

private float AngleLerp(float nowrap, float wraps, float lerp) {

    float c, d;

    if (wraps < nowrap) {
        c = wraps + MathHelper.TwoPi;
        //c > nowrap > wraps
        d = c - nowrap > nowrap - wraps
            ? MathHelper.Lerp(nowrap, wraps, lerp)
            : MathHelper.Lerp(nowrap, c, lerp);

    } else if (wraps > nowrap) {
        c = wraps - MathHelper.TwoPi;
        //wraps > nowrap > c
        d = wraps - nowrap > nowrap - c
            ? MathHelper.Lerp(nowrap, c, lerp)
            : MathHelper.Lerp(nowrap, wraps, lerp);

    } else { return nowrap; } //Same angle already

    return MathHelper.WrapAngle(d);
}

Он перелистывает nowrap к значению wraps. Угол wraps может быть тем, который прыгает от 0 до TwoPi и обратно, так что в этом случае угол мыши. nowrap должен быть углом ваших объектов.

Надеюсь, на этот раз я был на самом деле полезен.

...