From 844efbc322c837d6f5d31e06c29aa7f93b65259e Mon Sep 17 00:00:00 2001 From: loodakrawa Date: Tue, 6 Jun 2017 09:12:47 +1000 Subject: [PATCH] Calculate Box and Point positions in MonoGame coordinates. (#81) --- .../MonoGameDebugAnimator.cs | 75 ++++++++++++++---- .../SpriterGameState.cs | 20 +++-- SpriterDotNet.MonoGame/Box.cs | 12 +++ SpriterDotNet.MonoGame/ISprite.cs | 2 + SpriterDotNet.MonoGame/MonoGameAnimator.cs | 79 ++++++++++++++----- .../SpriterDotNet.MonoGame.csproj | 1 + .../Sprites/TexturePackerSprite.cs | 3 + .../Sprites/TextureSprite.cs | 3 + 8 files changed, 154 insertions(+), 41 deletions(-) create mode 100644 SpriterDotNet.MonoGame/Box.cs diff --git a/SpriterDotNet.MonoGame.Example/MonoGameDebugAnimator.cs b/SpriterDotNet.MonoGame.Example/MonoGameDebugAnimator.cs index adfcacc..4f92630 100644 --- a/SpriterDotNet.MonoGame.Example/MonoGameDebugAnimator.cs +++ b/SpriterDotNet.MonoGame.Example/MonoGameDebugAnimator.cs @@ -3,18 +3,23 @@ // This software may be modified and distributed under the terms // of the zlib license. See the LICENSE file for details. -using System.Collections.Generic; using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Audio; -using SpriterDotNet.MonoGame.Sprites; +using Microsoft.Xna.Framework.Graphics; +using System; +using System.Collections.Generic; namespace SpriterDotNet.MonoGame.Example { public class MonoGameDebugAnimator : MonoGameAnimator { - private IDictionary boxTextures = new Dictionary(); - private ISprite pointTexture; + public bool DrawSpriteOutlines { get; set; } + public Color DebugColor { get; set; } = Color.Red; + + private readonly List> lines = new List>(); + private readonly Texture2D whiteDot; + + private static readonly float PointBoxSize = 2.5f; public MonoGameDebugAnimator ( @@ -24,27 +29,63 @@ public MonoGameDebugAnimator Stack drawInfoPool = null ) : base(entity, providerFactory, drawInfoPool) { - pointTexture = new TextureSprite(TextureUtil.CreateCircle(graphicsDevice, 5, Color.Cyan)); + whiteDot = TextureUtil.CreateRectangle(graphicsDevice, 1, 1, Color.White); + } - if (entity.ObjectInfos != null) - { - foreach (SpriterObjectInfo objInfo in entity.ObjectInfos) - { - if (objInfo.ObjectType != SpriterObjectType.Box) continue; - boxTextures[objInfo.Name] = new TextureSprite(TextureUtil.CreateRectangle(graphicsDevice, (int)objInfo.Width, (int)objInfo.Height, Color.Cyan)); - } - } + protected override void ApplySpriteTransform(ISprite drawable, SpriterObject info) + { + base.ApplySpriteTransform(drawable, info); + if (DrawSpriteOutlines) AddForDrawing(GetBoundingBox(info, drawable.Width, drawable.Height)); } protected override void ApplyPointTransform(string name, SpriterObject info) { - if (pointTexture == null) return; - ApplySpriteTransform(pointTexture, info); + Vector2 position = GetPosition(info); + Box box = new Box + { + Point1 = position + new Vector2(-PointBoxSize, -PointBoxSize), + Point2 = position + new Vector2(PointBoxSize, -PointBoxSize), + Point3 = position + new Vector2(PointBoxSize, PointBoxSize), + Point4 = position + new Vector2(-PointBoxSize, PointBoxSize) + }; + AddForDrawing(box); } protected override void ApplyBoxTransform(SpriterObjectInfo objInfo, SpriterObject info) { - ApplySpriteTransform(boxTextures[objInfo.Name], info); + Box bounds = GetBoundingBox(info, objInfo.Width, objInfo.Height); + AddForDrawing(bounds); + } + + public override void Draw(SpriteBatch spriteBatch) + { + base.Draw(spriteBatch); + + foreach (var pair in lines) DrawLine(spriteBatch, pair.Key, pair.Value); + lines.Clear(); + } + + public void AddForDrawing(Box cb) + { + AddForDrawing(cb.Point1, cb.Point2); + AddForDrawing(cb.Point2, cb.Point3); + AddForDrawing(cb.Point3, cb.Point4); + AddForDrawing(cb.Point4, cb.Point1); + } + + public void AddForDrawing(Vector2 v1, Vector2 v2) + { + lines.Add(new KeyValuePair(v1, v2)); + } + + private void DrawLine(SpriteBatch batch, Vector2 start, Vector2 end) + { + Vector2 edge = end - start; + float angle = (float)Math.Atan2(edge.Y, edge.X); + + Rectangle rec = new Rectangle((int)start.X, (int)start.Y, (int)edge.Length(), 1); + + batch.Draw(whiteDot, rec, null, DebugColor, angle, new Vector2(0, 0), SpriteEffects.None, 0); } } } diff --git a/SpriterDotNet.MonoGame.Example/SpriterGameState.cs b/SpriterDotNet.MonoGame.Example/SpriterGameState.cs index 0a42ff4..e6c4293 100644 --- a/SpriterDotNet.MonoGame.Example/SpriterGameState.cs +++ b/SpriterDotNet.MonoGame.Example/SpriterGameState.cs @@ -41,7 +41,8 @@ public class SpriterGameState : GameState "Q/E = Rotate", "N/M = Scale", "F/G = Flip", - "J = Toggle Colour" + "J = Toggle Colour", + "~ = Toggle Sprite Outlines" }; private static readonly Config config = new Config @@ -67,11 +68,11 @@ public class SpriterGameState : GameState private string metadata = string.Empty; private Stats stats = new Stats(); - private Vector2 centre; + private float elapsedTime; protected override void Load() { - centre = new Vector2(Width / 2.0f, Height / 2.0f); + Vector2 centre = new Vector2(Width / 2.0f, Height / 2.0f); oldState = Keyboard.GetState(); spriteBatch = new SpriteBatch(GraphicsDevice); @@ -142,14 +143,21 @@ public override void Update(float deltaTime) if (IsPressed(Keys.M)) currentAnimator.Scale += new Vector2(Math.Sign(scale.X) * 0.2f, Math.Sign(scale.Y) * 0.2f); if (IsPressed(Keys.F)) currentAnimator.Scale *= new Vector2(-1, 1); if (IsPressed(Keys.G)) currentAnimator.Scale *= new Vector2(1, -1); + if (IsPressed(Keys.OemTilde)) (currentAnimator as MonoGameDebugAnimator).DrawSpriteOutlines = !(currentAnimator as MonoGameDebugAnimator).DrawSpriteOutlines; + oldState = Keyboard.GetState(); currentAnimator.Update(deltaTime); - string entity = currentAnimator.Entity.Name; - status = string.Format("{0} : {1}", entity, currentAnimator.Name); - metadata = "Variables:\n" + GetVarValues() + "\nTags:\n" + GetTagValues(); + elapsedTime += deltaTime; + if(elapsedTime >= 100) + { + elapsedTime -= 100; + string entity = currentAnimator.Entity.Name; + status = string.Format("{0} : {1}", entity, currentAnimator.Name); + metadata = string.Format("Variables:\n{0}\nTags:\n", GetVarValues(), GetTagValues()); + } } private void DrawText(string text, Vector2 position, float size, Color color) diff --git a/SpriterDotNet.MonoGame/Box.cs b/SpriterDotNet.MonoGame/Box.cs new file mode 100644 index 0000000..09da0ce --- /dev/null +++ b/SpriterDotNet.MonoGame/Box.cs @@ -0,0 +1,12 @@ +using Microsoft.Xna.Framework; + +namespace SpriterDotNet.MonoGame +{ + public struct Box + { + public Vector2 Point1; + public Vector2 Point2; + public Vector2 Point3; + public Vector2 Point4; + } +} diff --git a/SpriterDotNet.MonoGame/ISprite.cs b/SpriterDotNet.MonoGame/ISprite.cs index 167f9c3..3ec20f3 100644 --- a/SpriterDotNet.MonoGame/ISprite.cs +++ b/SpriterDotNet.MonoGame/ISprite.cs @@ -5,6 +5,8 @@ namespace SpriterDotNet.MonoGame { public interface ISprite { + float Width { get; } + float Height { get; } void Draw(SpriteBatch spriteBatch, Vector2 pivot, Vector2 position, Vector2 scale, float rotation, Color color, float depth); } } diff --git a/SpriterDotNet.MonoGame/MonoGameAnimator.cs b/SpriterDotNet.MonoGame/MonoGameAnimator.cs index bdfa454..4e4e79d 100644 --- a/SpriterDotNet.MonoGame/MonoGameAnimator.cs +++ b/SpriterDotNet.MonoGame/MonoGameAnimator.cs @@ -79,8 +79,8 @@ public virtual float Rotation public MonoGameAnimator ( - SpriterEntity entity, - IProviderFactory providerFactory = null, + SpriterEntity entity, + IProviderFactory providerFactory = null, Stack drawInfoPool = null ) : base(entity, providerFactory) { @@ -111,10 +111,63 @@ public override void Update(float deltaTime) } protected override void ApplySpriteTransform(ISprite drawable, SpriterObject info) + { + float posX, posY, rotation; + GetPositionAndRotation(info, out posX, out posY, out rotation); + + SpriteDrawInfo di = DrawInfoPool.Count > 0 ? DrawInfoPool.Pop() : new SpriteDrawInfo(); + + di.Drawable = drawable; + di.Pivot = new Vector2(info.PivotX, (1 - info.PivotY)); + di.Position = new Vector2(posX, posY); + di.Scale = new Vector2(info.ScaleX, info.ScaleY) * Scale; + di.Rotation = rotation; + di.Color = Color * info.Alpha; + di.Depth = Depth + DeltaDepth * DrawInfos.Count; + + DrawInfos.Add(di); + } + + protected override void PlaySound(SoundEffect sound, SpriterSound info) + { + sound.Play(info.Volume, 0.0f, info.Panning); + } + + public Box GetBoundingBox(SpriterObject info, float width, float height) + { + float posX, posY, rotation; + GetPositionAndRotation(info, out posX, out posY, out rotation); + + float w = width * info.ScaleX * Scale.X; + float h = height * info.ScaleY * Scale.Y; + + float rs = (float)Math.Sin(rotation); + float rc = (float)Math.Cos(rotation); + + Vector2 originDelta = Rotate(new Vector2(-info.PivotX * w, -(1 - info.PivotY) * h), rs, rc); + + Box cb = new Box(); + Vector2 horizontal = Rotate(new Vector2(w, 0), rs, rc); + cb.Point1 = new Vector2(posX, posY) + originDelta; + cb.Point2 = cb.Point1 + horizontal; + cb.Point4 = cb.Point1 + Rotate(new Vector2(0, h), rs, rc); + cb.Point3 = cb.Point4 + horizontal; + + return cb; + } + + public Vector2 GetPosition(SpriterObject info) + { + float posX, posY, rotation; + GetPositionAndRotation(info, out posX, out posY, out rotation); + return new Vector2(posX, posY); + } + + private void GetPositionAndRotation(SpriterObject info, out float posX, out float posY, out float rotation) { float px = info.X; float py = -info.Y; - float rotation = MathHelper.ToRadians(-info.Angle); + rotation = MathHelper.ToRadians(-info.Angle); if (Scale.X < 0) { @@ -131,25 +184,15 @@ protected override void ApplySpriteTransform(ISprite drawable, SpriterObject inf px *= scaleAbs.X; py *= scaleAbs.Y; - float posX = px * rotationCos - py * rotationSin; - float posY = px * rotationSin + py * rotationCos; - - SpriteDrawInfo di = DrawInfoPool.Count > 0 ? DrawInfoPool.Pop() : new SpriteDrawInfo(); - - di.Drawable = drawable; - di.Pivot = new Vector2(info.PivotX, (1 - info.PivotY)); - di.Position = new Vector2(posX, posY) + Position; - di.Scale = new Vector2(info.ScaleX, info.ScaleY) * Scale; - di.Rotation = rotation + Rotation; - di.Color = Color * info.Alpha; - di.Depth = Depth + DeltaDepth * DrawInfos.Count; + rotation += Rotation; - DrawInfos.Add(di); + posX = px * rotationCos - py * rotationSin + Position.X; + posY = px * rotationSin + py * rotationCos + Position.Y; } - protected override void PlaySound(SoundEffect sound, SpriterSound info) + private static Vector2 Rotate(Vector2 v, float s, float c) { - sound.Play(info.Volume, 0.0f, info.Panning); + return new Vector2(v.X * c - v.Y * s, v.X * s + v.Y * c); } } } diff --git a/SpriterDotNet.MonoGame/SpriterDotNet.MonoGame.csproj b/SpriterDotNet.MonoGame/SpriterDotNet.MonoGame.csproj index 95419b6..3b0c792 100644 --- a/SpriterDotNet.MonoGame/SpriterDotNet.MonoGame.csproj +++ b/SpriterDotNet.MonoGame/SpriterDotNet.MonoGame.csproj @@ -34,6 +34,7 @@ 4 + diff --git a/SpriterDotNet.MonoGame/Sprites/TexturePackerSprite.cs b/SpriterDotNet.MonoGame/Sprites/TexturePackerSprite.cs index 3a8a209..36703ae 100644 --- a/SpriterDotNet.MonoGame/Sprites/TexturePackerSprite.cs +++ b/SpriterDotNet.MonoGame/Sprites/TexturePackerSprite.cs @@ -14,6 +14,9 @@ namespace SpriterDotNet.MonoGame.Sprites /// public class TexturePackerSprite : ISprite { + public float Width => width; + public float Height => height; + private static readonly float SpriteAtlasRotation = MathHelper.ToRadians(-90); public Texture2D texture; diff --git a/SpriterDotNet.MonoGame/Sprites/TextureSprite.cs b/SpriterDotNet.MonoGame/Sprites/TextureSprite.cs index 7bdbd7c..ee301b0 100644 --- a/SpriterDotNet.MonoGame/Sprites/TextureSprite.cs +++ b/SpriterDotNet.MonoGame/Sprites/TextureSprite.cs @@ -14,6 +14,9 @@ namespace SpriterDotNet.MonoGame.Sprites /// public class TextureSprite : ISprite { + public float Width => texture.Width; + public float Height => texture.Height; + private readonly Texture2D texture; public TextureSprite(Texture2D texture)