已经找到更好的方法来处理动画,这篇文章只是闭门造车的负面例子🐱🏍
大致步骤
动画播放的本质就是多张图片间的快速切换。每张图片都有单独的持续时间,即可根据播放进度选择一张图片显示出来。如果播放进度大于1(播放时间超过所有帧加起来的总时间)则从头来过。
1、创建 AnimationFrame
首先创建 AnimationFrame.cs 文件
一个 AnimationFrame 就是动画中的其中一帧。这一帧可以是一整张包含所有帧的图片中的某个位置(Rectangle),也可以是单独的一张贴图(Texture2D),此处我选择后者(因为素材绘画的原因)。
using Microsoft.Xna.Framework.Graphics; using System; namespace CatFishing_Windows.Models { class AnimationFrame { //帧贴图 public Texture2D FrameTexture { get; set; } //帧持续时间 public TimeSpan Duration { get; set; } } }
2、创建 Animation
创建 Animation.cs 文件, Animation 中主要应该包含一下几项:
1、包含该动画所有帧的 List<Animation>
public List<AnimationFrame> Frames = new List<AnimationFrame>();
2、记录该动画从播放到现在的时间 TimeIntoAnimation
TimeSpan TimeIntoAnimation;
3、枚举每一帧的持续时间,累加获得动画持续的总时间 Duration
TimeSpan Duration { get { double totalSeconds = 0; foreach (var frame in Frames) { totalSeconds += frame.Duration.TotalSeconds; } return TimeSpan.FromSeconds(totalSeconds); } }
4、向 Animation() 添加帧的方法
public void AddFrame(Texture2D frame, double duration) { AnimationFrame animationFrame = new AnimationFrame() { FrameTexture = frame, Duration = TimeSpan.FromSeconds(duration) }; Frames.Add(animationFrame); }
其中, frame 为添加帧的贴图, duration 为该帧的预计持续时间。 duration 之所以为 double 是为了让 .Add() 在调用时看起来没有那么冗长,将 TimeSpan.FromSeconds() 在传入 .Add() 后进行。
5、计算 TimeIntoAnimation 的方法 Update() 。这个方法在game.cs内的 update() 处调用,每次 update() 时将 gameTime.ElapsedGameTime.TotalSeconds 累加进 TimeIntoAnimation 。
gameTime.ElapsedGameTime 代表这次 Update() 距离上次 Update() 所耗的时间。
public void Update(GameTime gameTime) { double secondsIntoAnimation = TimeIntoAnimation.TotalSeconds + gameTime.ElapsedGameTime.TotalSeconds; //用已播放的时间%动画总时间 //若 已播放时间大于总时间 则余数是多出来的秒数,记录余数进入下一次循环 //若 已播放时间小于总时间 则余数为 已播放时间 double remainder = secondsIntoAnimation % Duration.TotalSeconds; TimeIntoAnimation = TimeSpan.FromSeconds(remainder); }
6、获取当前时间的对应帧。逐帧累加时间,即可获知当前 TimeIntoAnimation 应该对应的帧。
public Texture2D CurrentTexture { get { AnimationFrame currentFrame = null; // 逐帧查找对应的帧 TimeSpan accumulatedTime = new TimeSpan(); foreach (var frame in Frames) { if (accumulatedTime + frame.Duration >= TimeIntoAnimation) { currentFrame = frame; break; } else accumulatedTime += frame.Duration; } //如果无法找到帧 则返回最后一帧 if (currentFrame == null) currentFrame = Frames.LastOrDefault(); return currentFrame.FrameTexture; } }
3、简单使用
1、创建新的 Animation ,并添加帧。
Animation a1 = new Animation(); a1.AddFrame(Content.Load<Texture2D>("png0"), 0.5); a1.AddFrame(Content.Load<Texture2D>("png1"), 0.5); a1.AddFrame(Content.Load<Texture2D>("png2"), 0.5);
2、在 game.cs 中的 Update() 调用 Animation 的 Update() 事件
a1.Update(gameTime);
3、在 game.cs 中的 Draw() 绘制 Animation 的当前帧
spriteBatch.Draw(a1.CurrentTexture, new Vector2(0,0), Color.White);