XNA 2d вращение вокруг центра - PullRequest
2 голосов
/ 29 июня 2011

Я пытаюсь включить поддержку масштабирования и поворота класса моей камеры вокруг центра области просмотра.

В моем приложении я уже разместил спрайты вручную перед вводом кода SpriteBatch.Begin,в зависимости от того, где расположена камера (чтобы облегчить выборку).Хотя каждый спрайт располагается вручную, я бы не стал поворачивать и масштабировать каждый спрайт индивидуально.

Поэтому я пытаюсь использовать аргумент matrixTransform в методе SpriteBatch.Begin.

Ниже приведен трудныйприложение, которое я сделал, чтобы проиллюстрировать проблему (используя изображение контента Car.png).Вращение не такое быстрое, как я ожидал (вращение на 10 градусов в каждом кадре?), И оно вращается / приближается к верхнему левому углу.Я бы хотел, чтобы он вращался вокруг центра экрана, который всегда держал бы среднюю машину в центре, а также масштабировал с этой точки.

Я пробовал несколько комбинаций создания матричных переводов, переупорядочения / добавления/ умножение / перевод на половину расстояния области просмотра, но я не совсем понимаю, как работают матрицы.Я также пробовал решения на нескольких веб-сайтах, которые мне не удавалось сделать для меня.

Может кто-нибудь сказать мне матричные переводы, которые я должен создать, или указать мне направление на веб-сайт, который выдумаете, будет работать для моей установки?

Приложение Windows XNA для демонстрации проблемы:

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace RenderTest
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        Texture2D _carTexture;
        float _zoom = 1.0f;
        float _rotationInDegrees = 0.0f;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            _carTexture = Content.Load<Texture2D>("Car");
        }

        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Up)) // Zoom in key
                _zoom *= 1.1f;

            if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Down)) // Zoom out key
                _zoom /= 1.1f;

            if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Left)) // Rotate anticlockwise key
                _rotationInDegrees -= 10;

            if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Right)) // Rotate clockwise key
                _rotationInDegrees += 10;

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.None, RasterizerState.CullNone, null, GetMatrix(GraphicsDevice));

            spriteBatch.Draw(_carTexture, new Rectangle(0, 0, 50, 50), Color.White);//Square car placed top left
            spriteBatch.Draw(_carTexture, new Rectangle(GraphicsDevice.Viewport.Width / 2 - 25, GraphicsDevice.Viewport.Height / 2 - 50, 50, 100), Color.Green);//Car placed centre
            spriteBatch.Draw(_carTexture, new Rectangle(GraphicsDevice.Viewport.Width / 2 + 100, GraphicsDevice.Viewport.Height / 2 + 100, 50, 50), Color.Black);//Off centre but always within screen

            spriteBatch.End();

            base.Draw(gameTime);
        }

        Matrix GetMatrix(GraphicsDevice graphicsDevice)
        {
            Matrix translationMatrix = Matrix.CreateTranslation(0, 0, 0);
            Matrix rotationMatrix = Matrix.CreateRotationZ(MathHelper.ToRadians(MathHelper.ToRadians(_rotationInDegrees)));
            Matrix zoomMatrix = Matrix.CreateScale(_zoom);

            Matrix compositeMatrix = translationMatrix * rotationMatrix * zoomMatrix;

            return compositeMatrix;
        }
    }
}

Спасибо,

Ли

Решение

    Matrix GetMatrix(GraphicsDevice graphicsDevice)
    {
        Matrix translateToOrigin = Matrix.CreateTranslation(-graphicsDevice.Viewport.Width / 2, -graphicsDevice.Viewport.Height / 2, 0);
        Matrix rotationMatrix = Matrix.CreateRotationZ(MathHelper.ToRadians(_rotationInDegrees));
        Matrix zoomMatrix = Matrix.CreateScale(_zoom);
        Matrix translateBackToPosition = Matrix.CreateTranslation(graphicsDevice.Viewport.Width / 2, graphicsDevice.Viewport.Height / 2, 0);

        Matrix compositeMatrix = translateToOrigin * rotationMatrix * zoomMatrix * translateBackToPosition;

        return compositeMatrix;
    }

1 Ответ

2 голосов
/ 29 июня 2011

Вы должны использовать один и тот же прямоугольник каждый раз и выполнять позиционирование в матрице.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...