From 3b76ff1f2ad395a89fff18266f8326638c561b2d Mon Sep 17 00:00:00 2001 From: Ellpeck Date: Wed, 11 Sep 2019 20:50:21 +0200 Subject: [PATCH] added a uniform texture atlas class --- Demos/AnimationDemo.cs | 23 +++++++++++++------- Demos/Content/Textures/Anim.png | Bin 894 -> 710 bytes Demos/GameImpl.cs | 4 ++-- MLEM/Textures/UniformTextureAtlas.cs | 31 +++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 10 deletions(-) create mode 100644 MLEM/Textures/UniformTextureAtlas.cs diff --git a/Demos/AnimationDemo.cs b/Demos/AnimationDemo.cs index abfccf8..d394575 100644 --- a/Demos/AnimationDemo.cs +++ b/Demos/AnimationDemo.cs @@ -19,13 +19,20 @@ namespace Demos { public override void LoadContent() { base.LoadContent(); - var tex = LoadContent("Textures/Anim"); + // create a uniform texture atlas with a width and height of 4 + // this means that, no matter how many pixels the texture has, it will always have 4 * 4 regions in total + // this allows for texture artists to change the resolution of a texture atlas without every texture region + // using it having wrong coordinates and/or sizes + // the regions that are part of the atlas are then referenced by region coordinates rather than texture coordinates + // (as seen below) + var atlas = new UniformTextureAtlas(LoadContent("Textures/Anim"), 4, 4); - // create the four animations by supplying the time per frame, the texture and the four regions used - var downAnim = new SpriteAnimation(0.2F, tex, new Rectangle(0, 0, 8, 8), new Rectangle(0, 8, 8, 8), new Rectangle(0, 16, 8, 8), new Rectangle(0, 24, 8, 8)) {Name = "Down"}; - var upAnim = new SpriteAnimation(0.2F, tex, new Rectangle(8, 0, 8, 8), new Rectangle(8, 8, 8, 8), new Rectangle(8, 16, 8, 8), new Rectangle(8, 24, 8, 8)) {Name = "Up"}; - var leftAnim = new SpriteAnimation(0.2F, tex, new Rectangle(16, 0, 8, 8), new Rectangle(16, 8, 8, 8), new Rectangle(16, 16, 8, 8), new Rectangle(16, 24, 8, 8)) {Name = "Left"}; - var rightAnim = new SpriteAnimation(0.2F, tex, new Rectangle(24, 0, 8, 8), new Rectangle(24, 8, 8, 8), new Rectangle(24, 16, 8, 8), new Rectangle(24, 24, 8, 8)) {Name = "Right"}; + // create the four animations by supplying the time per frame, and the four regions used + // note that you don't need to use a texture atlas for this, you can also simply supply the texture and the regions manually here + var downAnim = new SpriteAnimation(0.2F, atlas[0, 0], atlas[0, 1], atlas[0, 2], atlas[0, 3]) {Name = "Down"}; + var upAnim = new SpriteAnimation(0.2F, atlas[1, 0], atlas[1, 1], atlas[1, 2], atlas[1, 3]) {Name = "Up"}; + var leftAnim = new SpriteAnimation(0.2F, atlas[2, 0], atlas[2, 1], atlas[2, 2], atlas[2, 3]) {Name = "Left"}; + var rightAnim = new SpriteAnimation(0.2F, atlas[3, 0], atlas[3, 1], atlas[3, 2], atlas[3, 3]) {Name = "Right"}; // create a sprite animation group which manages a list of animations and figures out which one should // be playing right now based on supplied conditions @@ -41,7 +48,7 @@ namespace Demos { // you can also add a priority to an animation in the group (10 in this case, which is higher than the default of 0) // if two animations' playing conditions are both true, then the one with the higher priority will be picked to play // in this instance, a standing "animation" is displayed when we're facing down and also holding the space key - this.group.Add(new SpriteAnimation(1F, tex, new Rectangle(0, 0, 8, 8)) {Name = "DownStanding"}, () => this.facing == Direction2.Down && this.InputHandler.IsKeyDown(Keys.Space), 10); + this.group.Add(new SpriteAnimation(1F, atlas[0, 0]) {Name = "DownStanding"}, () => this.facing == Direction2.Down && this.InputHandler.IsKeyDown(Keys.Space), 10); // you can also add a callback to see when the animation used changes this.group.OnAnimationChanged += (anim, newAnim) => { @@ -67,7 +74,7 @@ namespace Demos { } public override void DoDraw(GameTime gameTime) { - this.GraphicsDevice.Clear(Color.Black); + this.GraphicsDevice.Clear(Color.CornflowerBlue); this.SpriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.PointClamp, transformMatrix: Matrix.CreateScale(10)); // draw the group's current region diff --git a/Demos/Content/Textures/Anim.png b/Demos/Content/Textures/Anim.png index adba8829d898d0ab16fcf121d125b18bb554c474..d4ddb1ee6eb8e769cdafb929793b9e801205bbed 100644 GIT binary patch literal 710 zcmV;%0y+JOP)Px%fJsC_R9J=WSHEl9P!Rqkgh5yj*NY8rRl!h*@nE_nlt2k|G1)rw&&U|a5IiTe zOUEpM4kmVkllPsnXkxk&N25V_uwFHdOb%^ir^d#GD2<_r;(c`|md#4|F?~{c& zr00<9*tnl10D#fYnFRy>vjW}E61a{H0J!@;we)xZ;2dWBqWmeRVXs5Hezp59l|&S5 z5(QiN<`u~CW-J%b|NIF6@ci}LOe}-OgDwG}JW_fNNzWlsuyc8iH+@9GCh0l3xz#O6 zDQP_DB94Dx*y}(_nR1j;Qanu%PZRhr>KPsY#)B>ZVD6{xGM*+@JWWzQ3=05iwHn27 z4Bz)30^%4^6hR1qFbu6)twyfvLI|OFAq1i*LKuc>qei1adYrxy?@_5#5CnnZY);5m zUYqu1JVP(g1l!mrRlv=~3Hqn+k$5cxL0~0bOWBxDyjF^z(6-_kY`eKQ$rQl(CbXU5 z008A`lZqvu%=Mr0%j}F|$)|F)nc`D@yq*JC&jDi&0KjN8vhw&Rp97UjCDrG88!nmy zUp}_gdf4lb5JKfK!FvcHQs0_2e=M}KcMSlzy=q(KYLmW=zp5(d?+!bA*SNiETlK92 zVqf-Q8vtA$Zvp_SFW*>ZJVTEKu)2qr`If6q)!)UEpPNUw>;CIGU}8N79s>TM9&k9J zepQugcGqq!{d;kCd literal 894 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-HD>V7BmdaSW-L z^Y->eZ|Ovd;~($03UJ)(F7KFprjy{VmOR;C=@wjkk8(1n_r-F_x*XwS zb&PQl*Oa)!w2SNHrCZs8O?PfD+;{x$%wt~Bd%x|QuX_CVp7+%<`F(eO-x2l~XWF0j z`fAs?bIG2UPF^qew|qEvmaTPv==v}f&*SsiWd2JzBn3IOuCY_HAlpi>u|s%5!Z>o{_g8Bd{wqPZuQkoU#nt| z%}~kf3EY1_eEV%*v8t@BQ_GGo^?!2iVus0;mnA7?%F@#AR@~NOGg9W+l=CI~Jd0%BetPnfd;gZr zoqd0@itIbRYM@QOSAI9#>8)S4+thsj^22vi^NZ3h?%KDmKYQ|$wc`A$o@d$p_x!0) zw-sY8xGGl{a=-Ig$)^4C(){h`Cg=HoKmJyUKcMId;{->!1t}+(r^tL|Pz|4|xBq+j zrMF+J{x1KxC-5tS#x(mVeu3X_wO=zP?XP8?-kQBwZowRo>Pm)`3G5n@K<_;F^b-4Q zRoRgEyY>^q|9NN34F2x3{~K5T{H?a<;{W0WTlQvM4-;FrhCL!Wa)I0e2cz;wH!3pr z&y`bu|NHv%ck28(FQpnz&UD?quOxnw-qE>0w;O+Dcp1fDe*XSWl|S27e_}ZNE0`ac d`l$lCURfVF-F~%GHA)O*o~Nsy%Q~loCII`%ibwze diff --git a/Demos/GameImpl.cs b/Demos/GameImpl.cs index 38c5b40..a54cacd 100644 --- a/Demos/GameImpl.cs +++ b/Demos/GameImpl.cs @@ -17,8 +17,8 @@ namespace Demos { static GameImpl() { Demos.Add("Ui", game => new UiDemo(game)); - Demos.Add("Animation", game => new AnimationDemo(game)); - Demos.Add("AutoTiling", game => new AutoTilingDemo(game)); + Demos.Add("Animation and Texture Atlas", game => new AnimationDemo(game)); + Demos.Add("Auto Tiling", game => new AutoTilingDemo(game)); Demos.Add("Pathfinding", game => new PathfindingDemo(game)); } diff --git a/MLEM/Textures/UniformTextureAtlas.cs b/MLEM/Textures/UniformTextureAtlas.cs new file mode 100644 index 0000000..9197314 --- /dev/null +++ b/MLEM/Textures/UniformTextureAtlas.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace MLEM.Textures { + public class UniformTextureAtlas { + + public readonly Texture2D Texture; + public readonly int RegionAmountX; + public readonly int RegionAmountY; + public TextureRegion this[Point point] => this.regions.TryGetValue(point, out var region) ? region : null; + public TextureRegion this[int x, int y] => this[new Point(x, y)]; + + private readonly Dictionary regions = new Dictionary(); + + public UniformTextureAtlas(Texture2D texture, int regionAmountX, int regionAmountY) { + this.Texture = texture; + this.RegionAmountX = regionAmountX; + this.RegionAmountY = regionAmountY; + + var regionWidth = texture.Width / regionAmountX; + var regionHeight = texture.Height / regionAmountY; + for (var x = 0; x < regionAmountX; x++) { + for (var y = 0; y < regionAmountY; y++) { + this.regions.Add(new Point(x, y), new TextureRegion(texture, x * regionWidth, y * regionHeight, regionWidth, regionHeight)); + } + } + } + + } +} \ No newline at end of file