如何旋转一组精灵

示范如何通过一个旋转Matrix (矩阵)以一点为中心来旋转一组精灵。它使用两个方法,在Update中旋转精灵位置,并创建一个旋转矩阵用于Draw的SpriteBatch。源码下载

程序截图

在屏幕上绘制一组旋转的精灵

在屏幕上绘制一组旋转的精灵

  1. 按照如何绘制精灵 所讲的1-4步进行操作。

  2. 创建一组Vector2对象来表示为旋转精灵的位置,再创建一组 Vector2对象来保存旋转值。

    private Vector2[] myVectors;
    private Vector2[] drawVectors;
    protected override void Initialize()
    {
        myVectors = new Vector2[9];
        drawVectors = new Vector2[9];
    
        base.Initialize();
    }
  3. 加载完精灵之后,基于精灵的高度(假设我们使用的是一个正方形的纹理)来计算未旋转的初始精灵组中各个精灵的位置。

    private Texture2D SpriteTexture;
    private Vector2 origin;
    private Vector2 screenpos;
    protected override void LoadContent()
    {
        // Create a new SpriteBatch, which can be used to draw textures.
        spriteBatch = new SpriteBatch(GraphicsDevice);
    
        SpriteTexture = Content.Load<Texture2D>("ship");
        origin.X = SpriteTexture.Width / 2;
        origin.Y = SpriteTexture.Height / 2;
        Viewport viewport = graphics.GraphicsDevice.Viewport;
        screenpos.X = viewport.Width / 2;
        screenpos.Y = viewport.Height / 2;
    }
  4. 在你的Update 方法中,将未旋转的向量数组克隆一份副本传给drawVectors,然后确定向量旋转后的各个精灵在屏幕的位置保存在drawVectors向量中。

    private float RotationAngle = 0f;
    private bool batchAutoRotate = false;
    private Matrix rotationMatrix = Matrix.Identity;
    protected override void Update(GameTime gameTime)
    {
        ...
        float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
    
        RotationAngle += elapsed;
        float circle = MathHelper.Pi * 2;
        RotationAngle = RotationAngle % circle;
    
        // Copy and rotate the sprite positions.
        drawVectors = (Vector2[])myVectors.Clone();
    
        if (!batchAutoRotate)
            RotatePoints(ref screenpos, RotationAngle, ref drawVectors);
        else
            UpdateMatrix(ref screenpos, RotationAngle);
    
        base.Update(gameTime);
    }

    使用一个用旋转角度创建的旋转矩阵来转换每一个向量的位置信息。

  5. 为了让这些精灵相对于原点旋转,应该使用每个精灵的drawVectors向量减去屏幕原点向量。

  6. 等转换完以后再与屏幕原点向量相加 ,这样我们最终就得到了一个旋转后的向量了。

    private static void RotatePoints(ref Vector2 origin, float radians, ref Vector2[] Vectors)
    {
        Matrix myRotationMatrix = Matrix.CreateRotationZ(radians);
    
        for (int i = 0; i < 9; i++)
        {
            // Rotate relative to origin.
            Vector2 rotatedVector = Vector2.Transform(Vectors[i] - origin, myRotationMatrix);
    
            // Add origin to get final location.
            Vectors[i] = rotatedVector + origin;
        }
    }
  7. 使用旋转后的向量作为屏幕位置绘制每一个精灵。

    private void DrawPoints()
    {
        // Draw using manually rotated vectors
        spriteBatch.Begin();
        for (int i = 0; i < drawVectors.Length; i++)
            spriteBatch.Draw(SpriteTexture, drawVectors[i], null, Color.White, RotationAngle,
                origin, 1.0f, SpriteEffects.None, 0f);
        spriteBatch.End();
    }
  8. 当所有精灵绘制完毕以后,调用End

使用SpriteBatch变换旋转一组精灵

  1. 按照 如何绘制精灵 所讲的1-4步进行操作。

  2. 创建一组 Vector2对象来表示为旋转精灵的位置,再创建一组 Vector2 对象来保存旋转值。

    private Vector2[] myVectors;
    private Vector2[] drawVectors;
    protected override void Initialize()
    {
        myVectors = new Vector2[9];
        drawVectors = new Vector2[9];
    
        base.Initialize();
    }
  3. 加载完精灵之后,基于精灵的高度(假设我们使用的是一个正方形的纹理)来计算未旋转的初始精灵组中各个精灵的位置。

    private Texture2D SpriteTexture;
    private Vector2 origin;
    private Vector2 screenpos;
    protected override void LoadContent()
    {
        // Create a new SpriteBatch, which can be used to draw textures.
        spriteBatch = new SpriteBatch(GraphicsDevice);
    
        SpriteTexture = Content.Load<Texture2D>("ship");
        origin.X = SpriteTexture.Width / 2;
        origin.Y = SpriteTexture.Height / 2;
        Viewport viewport = graphics.GraphicsDevice.Viewport;
        screenpos.X = viewport.Width / 2;
        screenpos.Y = viewport.Height / 2;
    }
  4. 在你的Update方法中,将未旋转的向量数组克隆一份副本传给drawVectors,然后确定向量旋转后的各个精灵在屏幕的位置保存在drawVectors向量中。

    private float RotationAngle = 0f;
    private bool batchAutoRotate = false;
    private Matrix rotationMatrix = Matrix.Identity;
    protected override void Update(GameTime gameTime)
    {
        ...
        float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
    
        RotationAngle += elapsed;
        float circle = MathHelper.Pi * 2;
        RotationAngle = RotationAngle % circle;
    
        // Copy and rotate the sprite positions.
        drawVectors = (Vector2[])myVectors.Clone();
    
        if (!batchAutoRotate)
            RotatePoints(ref screenpos, RotationAngle, ref drawVectors);
        else
            UpdateMatrix(ref screenpos, RotationAngle);
    
        base.Update(gameTime);
    }
  5. 在Draw方法中为SpriteBatch创建一个旋转矩阵。

  6. 为了绕一个不在左上角的点旋转,首先要使用一个平移矩阵减去旋转原点。

  7. 将平移矩阵乘以旋转矩阵。

  8. 将结果乘以加上旋转原点的平移矩阵。

    这是因为旋转矩阵必须围绕 (0,0,0)旋转。

    private void UpdateMatrix(ref Vector2 origin, float radians)
    {
        // Translate sprites to center around screen (0,0), rotate them, and
        // translate them back to their original positions
        Vector3 matrixorigin = new Vector3(origin, 0);
        rotationMatrix = Matrix.CreateTranslation(-matrixorigin) *
            Matrix.CreateRotationZ(radians) *
            Matrix.CreateTranslation(matrixorigin);
    }
  9. 在Draw方法中,调用SpriteBatch.Begin,指定旋转矩阵作为第四个参数。

    private void DrawMatrix()
    {
        // Draw using a rotation matrix with SpriteBatch
        spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Deferred,
            SaveStateMode.None, rotationMatrix);
        for (int j = 0; j < myVectors.Length; j++)
            spriteBatch.Draw(SpriteTexture, myVectors[j], null, Color.White, 0,
                origin, 1.0f, SpriteEffects.None, 0f);
        spriteBatch.End();
    }
  10. 当所有精灵绘制完毕以后,调用End。


发布时间:2009/2/23 上午9:52:40  阅读次数:5115

2006 - 2024,推荐分辨率 1024*768 以上,推荐浏览器 Chrome、Edge 等现代浏览器,截止 2021 年 12 月 5 日的访问次数:1872 万 9823 站长邮箱

沪 ICP 备 18037240 号-1

沪公网安备 31011002002865 号