1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
namespace CompositeSprite
{
    using System;
    using System.Collections.Generic;
    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Graphics;

    public class Sprite
    {
        public Sprite(Texture2D texture)
        {
            Texture = texture;
            Scale = 1f;
            Origin = new Vector2(texture.Width/2f, texture.Height/2f);
            Children = new List<Sprite>();
        }

        public Vector2 Position { get; set; }
        public float Rotation { get; set; }
        public float Scale { get; set; }
        public Vector2 Origin { get; set; }
        public Texture2D Texture { get; private set; }
        public List<Sprite> Children { get; private set; }

        public void Draw(SpriteBatch spriteBatch)
        {
            Draw(spriteBatch, Matrix.Identity);
        }

        private Matrix CalculateLocalTransform()
        {
            return Matrix.CreateTranslation(-Origin.X, -Origin.Y, 0f) * Matrix.CreateScale(Scale, Scale, 1f) * Matrix.CreateRotationZ(Rotation) * Matrix.CreateTranslation(Position.X, Position.Y, 0f); 
        }

        private void Draw(SpriteBatch spriteBatch, Matrix parentTransform)
        {
            Matrix globalTransform = CalculateLocalTransform() * parentTransform;
            Vector2 position, scale;
            float rotation;
            DecomposeMatrix(ref globalTransform, out position, out rotation, out scale);
            spriteBatch.Draw(Texture, position, null, Color.White, rotation, Vector2.Zero, scale, SpriteEffects.None, 0.0f);
            Children.ForEach(c => c.Draw(spriteBatch, globalTransform));
        }

        private static void DecomposeMatrix(ref Matrix matrix, out Vector2 position, out float rotation, out Vector2 scale)
        {
            Vector3 position3, scale3;
            Quaternion rotationQ;
            matrix.Decompose(out scale3, out rotationQ, out position3);
            Vector2 direction = Vector2.Transform(Vector2.UnitX, rotationQ);
            rotation = (float)Math.Atan2(direction.Y, direction.X);
            position = new Vector2(position3.X, position3.Y);
            scale = new Vector2(scale3.X, scale3.Y);
        }
    }
}