mirror of
https://github.com/Ellpeck/MLEM.git
synced 2024-12-24 17:29:23 +01:00
added sprite sheet animations
This commit is contained in:
parent
75deef068a
commit
482244df0e
6 changed files with 209 additions and 0 deletions
67
Demos/AnimationDemo.cs
Normal file
67
Demos/AnimationDemo.cs
Normal file
|
@ -0,0 +1,67 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using MLEM.Animations;
|
||||
using MLEM.Startup;
|
||||
using MLEM.Textures;
|
||||
|
||||
namespace Demos {
|
||||
public class AnimationDemo : MlemGame {
|
||||
|
||||
private SpriteAnimationGroup group;
|
||||
private int facing;
|
||||
|
||||
protected override void LoadContent() {
|
||||
base.LoadContent();
|
||||
|
||||
var tex = LoadContent<Texture2D>("Textures/Anim");
|
||||
|
||||
// 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));
|
||||
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));
|
||||
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));
|
||||
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));
|
||||
|
||||
// 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
|
||||
// using a group isn't necessary, but highly recommended for things like character animations as it makes
|
||||
// it very easy to have different animations play at different times
|
||||
this.group = new SpriteAnimationGroup();
|
||||
// for example, the down animation should only play when we're facing down (0 in this case)
|
||||
this.group.Add(downAnim, () => this.facing == 0);
|
||||
this.group.Add(upAnim, () => this.facing == 1);
|
||||
this.group.Add(leftAnim, () => this.facing == 2);
|
||||
this.group.Add(rightAnim, () => this.facing == 3);
|
||||
}
|
||||
|
||||
protected override void Update(GameTime gameTime) {
|
||||
base.Update(gameTime);
|
||||
|
||||
if (this.InputHandler.IsKeyDown(Keys.Down))
|
||||
this.facing = 0;
|
||||
else if (this.InputHandler.IsKeyDown(Keys.Up))
|
||||
this.facing = 1;
|
||||
else if (this.InputHandler.IsKeyDown(Keys.Left))
|
||||
this.facing = 2;
|
||||
else if (this.InputHandler.IsKeyDown(Keys.Right))
|
||||
this.facing = 3;
|
||||
|
||||
// update the animation group
|
||||
// if not using a group, just update the animation itself here
|
||||
this.group.Update(gameTime);
|
||||
}
|
||||
|
||||
protected override void Draw(GameTime gameTime) {
|
||||
this.GraphicsDevice.Clear(Color.Black);
|
||||
|
||||
this.SpriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.PointClamp, transformMatrix: Matrix.CreateScale(10));
|
||||
// draw the group's current region
|
||||
// if not using a group, just update the animation's CurrentRegion here
|
||||
this.SpriteBatch.Draw(this.group.CurrentRegion, new Vector2(10, 10), Color.White);
|
||||
this.SpriteBatch.End();
|
||||
|
||||
base.Draw(gameTime);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -20,6 +20,18 @@
|
|||
/processorParam:TextureFormat=Compressed
|
||||
/build:Fonts/TestFont.spritefont
|
||||
|
||||
#begin Textures/Anim.png
|
||||
/importer:TextureImporter
|
||||
/processor:TextureProcessor
|
||||
/processorParam:ColorKeyColor=255,0,255,255
|
||||
/processorParam:ColorKeyEnabled=True
|
||||
/processorParam:GenerateMipmaps=False
|
||||
/processorParam:PremultiplyAlpha=True
|
||||
/processorParam:ResizeToPowerOfTwo=False
|
||||
/processorParam:MakeSquare=False
|
||||
/processorParam:TextureFormat=Color
|
||||
/build:Textures/Anim.png
|
||||
|
||||
#begin Textures/AutoTiling.png
|
||||
/importer:TextureImporter
|
||||
/processor:TextureProcessor
|
||||
|
|
BIN
Demos/Content/Textures/Anim.png
Normal file
BIN
Demos/Content/Textures/Anim.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 894 B |
|
@ -11,6 +11,7 @@ namespace Demos {
|
|||
static Program() {
|
||||
Demos.Add("Ui", () => new UiDemo());
|
||||
Demos.Add("AutoTiling", () => new AutoTilingDemo());
|
||||
Demos.Add("Animation", () => new AnimationDemo());
|
||||
}
|
||||
|
||||
public static void Main(string[] args) {
|
||||
|
|
82
MLEM/Animations/SpriteAnimation.cs
Normal file
82
MLEM/Animations/SpriteAnimation.cs
Normal file
|
@ -0,0 +1,82 @@
|
|||
using System;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using MLEM.Textures;
|
||||
|
||||
namespace MLEM.Animations {
|
||||
public class SpriteAnimation {
|
||||
|
||||
private AnimationFrame[] frames;
|
||||
public AnimationFrame this[int index] => this.frames[index];
|
||||
public AnimationFrame CurrentFrame {
|
||||
get {
|
||||
var accum = 0D;
|
||||
foreach (var frame in this.frames) {
|
||||
accum += frame.Seconds;
|
||||
if (accum >= this.TimeIntoAnimation)
|
||||
return frame;
|
||||
}
|
||||
// we might have overshot the end time by a little bit, so just return the last frame
|
||||
return this.frames[this.frames.Length - 1];
|
||||
}
|
||||
}
|
||||
public TextureRegion CurrentRegion => this.CurrentFrame.Region;
|
||||
public readonly double TotalTime;
|
||||
public double TimeIntoAnimation { get; private set; }
|
||||
public bool IsFinished { get; private set; }
|
||||
|
||||
public bool IsLooping = true;
|
||||
public Completed OnCompleted;
|
||||
public bool IsPaused;
|
||||
|
||||
public SpriteAnimation(params AnimationFrame[] frames) {
|
||||
this.frames = frames;
|
||||
foreach (var frame in frames)
|
||||
this.TotalTime += frame.Seconds;
|
||||
}
|
||||
|
||||
public SpriteAnimation(float timePerFrame, params TextureRegion[] regions)
|
||||
: this(Array.ConvertAll(regions, region => new AnimationFrame(region, timePerFrame))) {
|
||||
}
|
||||
|
||||
public SpriteAnimation(float timePerFrame, Texture2D texture, params Rectangle[] regions)
|
||||
: this(timePerFrame, Array.ConvertAll(regions, region => new TextureRegion(texture, region))) {
|
||||
}
|
||||
|
||||
public void Update(GameTime time) {
|
||||
if (this.IsFinished || this.IsPaused)
|
||||
return;
|
||||
|
||||
this.TimeIntoAnimation += time.ElapsedGameTime.TotalSeconds;
|
||||
if (this.TimeIntoAnimation >= this.TotalTime) {
|
||||
if (!this.IsLooping) {
|
||||
this.IsFinished = true;
|
||||
} else {
|
||||
this.Restart();
|
||||
}
|
||||
this.OnCompleted?.Invoke(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void Restart() {
|
||||
this.TimeIntoAnimation = 0;
|
||||
this.IsFinished = false;
|
||||
this.IsPaused = false;
|
||||
}
|
||||
|
||||
public delegate void Completed(SpriteAnimation animation);
|
||||
|
||||
}
|
||||
|
||||
public class AnimationFrame {
|
||||
|
||||
public readonly TextureRegion Region;
|
||||
public readonly float Seconds;
|
||||
|
||||
public AnimationFrame(TextureRegion region, float seconds) {
|
||||
this.Region = region;
|
||||
this.Seconds = seconds;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
47
MLEM/Animations/SpriteAnimationGroup.cs
Normal file
47
MLEM/Animations/SpriteAnimationGroup.cs
Normal file
|
@ -0,0 +1,47 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Xna.Framework;
|
||||
using MLEM.Textures;
|
||||
|
||||
namespace MLEM.Animations {
|
||||
public class SpriteAnimationGroup {
|
||||
|
||||
private readonly List<ConditionedAnimation> animations = new List<ConditionedAnimation>();
|
||||
private ConditionedAnimation currAnimation;
|
||||
public AnimationFrame CurrentFrame => this.currAnimation != null ? this.currAnimation.Animation.CurrentFrame : null;
|
||||
public TextureRegion CurrentRegion => this.currAnimation != null ? this.currAnimation.Animation.CurrentRegion : null;
|
||||
|
||||
public SpriteAnimationGroup Add(SpriteAnimation anim, Func<bool> condition) {
|
||||
this.animations.Add(new ConditionedAnimation(anim, condition));
|
||||
return this;
|
||||
}
|
||||
|
||||
public void Update(GameTime time) {
|
||||
if (this.currAnimation == null || !this.currAnimation.ShouldPlay()) {
|
||||
this.currAnimation = null;
|
||||
foreach (var anim in this.animations) {
|
||||
if (anim.ShouldPlay()) {
|
||||
this.currAnimation = anim;
|
||||
anim.Animation.Restart();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.currAnimation != null)
|
||||
this.currAnimation.Animation.Update(time);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal class ConditionedAnimation {
|
||||
|
||||
public readonly SpriteAnimation Animation;
|
||||
public readonly Func<bool> ShouldPlay;
|
||||
|
||||
public ConditionedAnimation(SpriteAnimation animation, Func<bool> shouldPlay) {
|
||||
this.Animation = animation;
|
||||
this.ShouldPlay = shouldPlay;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue