德阳市建设厅官方网站,网站建设厘金手指排名十九,html模板之家免费下载,成功案例网站建设第六章#xff1a;动画类以及动画精灵
好久不见家人们好久没更新MonoGame系列了#xff0c;不是主包弃坑了#xff0c;主要是主包最近忙着搞项目学科一找暑假工打#xff0c;这不一闲下来就立刻马不停蹄的来给大家更新了#xff0c;今天的教程代码部分比较多接下来我们正式…第六章动画类以及动画精灵
好久不见家人们好久没更新MonoGame系列了不是主包弃坑了主要是主包最近忙着搞项目学科一找暑假工打这不一闲下来就立刻马不停蹄的来给大家更新了今天的教程代码部分比较多接下来我们正式开始动画类
我们知道现在许多像素独立游戏都是使用帧动画的方式来处理以及修改动画当然了也不乏有使用骨骼动画来实现的独立游戏但我们这个教程使用的是帧动画来实现一个最简单的动画在学习Animation类之前我们得先学习一下什么是帧动画在1907年逐帧动画由一位无名的技师发明一开始作为一种实验性视频在早期的影视作品中大显风头。 起初这个技术并不被世人了解后来法国艾米尔科尔发现了这个独特的技术并制作了很多优秀的早期逐帧动画代表作如逐帧定格木偶剧《小浮士德 Les Allumettes》 (1908)。 “生命之轮”Zoerope1867年作为玩具出现在美国转动圆盘透过缝隙就能看到运动形象。这个就是帧动画的前身那么我们该如何实现这个类容呢。
第一步创建文件并定义
我们书接上回上次我们创建了TextureSprite等等的类那么这次我们同样在Graphics文件夹下创建文件 Animation.cs
接着写入下面代码
using System;
using System.Collections.Generic;namespace SlimeGame.Graphics;public class Animation
{/// summary/// 帧序列存储所有帧图片/// /summary /// value/valuepublic ListTextureRegion Frames { get; set; }/// summary/// 帧间隔存储每帧的时间间隔/// /summary /// value/valuepublic TimeSpan Delay { get; set; }/// summary/// 无参构造/// /summarypublic Animation(){Frames new ListTextureRegion();Delay TimeSpan.FromMilliseconds(100);}/// summary/// 有参构造/// /summarypublic Animation(ListTextureRegion frames, TimeSpan delay){Frames frames;Delay delay;}
}第二步修改TextureAtlas.cs使其适配Animation组件
我们回到Atlas文件的设置我们需要修改非常多的内容接下来我们一起来修改
我们在代码中增加一个字典用来存储所有有的动画
private Dictionarystring, Animation Animations;我们修改定义文件在定义中添加以下代码为动画字典申请空间
/// summary
/// 无参构造
/// /summary
public TextureAtlas()
{Regions new Dictionarystring, TextureRegion();Animations new Dictionarystring, Animation();
}/// summary
/// 有参构造
/// /summary
public TextureAtlas(Texture2D texture)
{TotalTexture texture;Regions new Dictionarystring, TextureRegion();Animations new Dictionarystring, Animation();
}再然后就是我们最熟悉的增删查该环节了/// summary/// 在字典中增加动画/// /summary/// param nameanimationName动画对应名称/键/param/// param nameanimation动画本体/parampublic void AddAnimation(string animationName, Animation animation){Animations.Add(animationName, animation);}/// summary/// 得到当前动画/// /summary/// param nameanimationName动画名称/param/// returns动画本体/returnspublic Animation GetAnimation(string animationName){return Animations[animationName];}/// summary/// 从字典中移除动画/// /summary/// param nameanimationName动画名称/键/param/// returns是否移除/returnspublic bool RemoveAnimation(string animationName){return Animations.Remove(animationName);}// 清空字典public void AnimationsClear(){Animations.Clear();}最后一步修改文件加载方式
还记得我们上次使用XML文件加载的那个内容吗这次我们一次性搞定可能包括以后这部分模板部分的代码我们都不会再次修改了我们一起加油哦/// summary/// 从文件中加载纹理/// /summary/// param namecontent文件资源管理/param/// param namefileName文件名称/param/// returns/returnspublic static TextureAtlas FromFile(ContentManager content, string fileName){TextureAtlas atlas new TextureAtlas();// 合并文件名成完整项目路径string filePath Path.Combine(content.RootDirectory, fileName);//文件流式存储using (Stream stream TitleContainer.OpenStream(filePath)){// Xml读取器的获得using (XmlReader reader XmlReader.Create(stream)){// 读XMl的文件内容XDocument doc XDocument.Load(reader);XElement root doc.Root;// Texture 该元素包含要加载的 Texture2D 的内容路径.// 因此我们将检索该值然后使用内容管理器加载纹理.string texturePath root.Element(Texture).Value;atlas.TotalTexture content.LoadTexture2D(texturePath);// Regions 该元素包含单独的Region元素每个元素描述// 图集中的其他纹理区域. //// 例子:// Regions// Region namespriteOne x0 y0 width32 height32 /// Region namespriteTwo x32 y0 width32 height32 /// /Regions//// 因此我们检索所有Region元素然后遍历每个元素从中生成一个新的 TextureRegion 实例并将其添加到此图集.var regions root.Element(Regions)?.Elements(Region);if (regions ! null){foreach (var region in regions){string name region.Attribute(name)?.Value;int x int.Parse(region.Attribute(x)?.Value ?? 0);int y int.Parse(region.Attribute(y)?.Value ?? 0);int width int.Parse(region.Attribute(width)?.Value ?? 0);int height int.Parse(region.Attribute(height)?.Value ?? 0);if (!string.IsNullOrEmpty(name)){atlas.AddRegion(name, x, y, width, height);}}}// Animations 该元素包含单独的Animation元素每个元素描述// 在图集中的不同动画//// Example:// Animations// Animation nameanimation delay100// Frame regionspriteOne /// Frame regionspriteTwo /// /Animation// /Animations//// 因此我们检索所有Animation元素然后遍历每个元素// 并从中生成新的 Animation 实例并将其添加到此图集.var animationElements root.Element(Animations).Elements(Animation);if (animationElements ! null){foreach (var animationElement in animationElements){string name animationElement.Attribute(name)?.Value;float delayInMilliseconds float.Parse(animationElement.Attribute(delay)?.Value ?? 0);TimeSpan delay TimeSpan.FromMilliseconds(delayInMilliseconds);ListTextureRegion frames new ListTextureRegion();var frameElements animationElement.Elements(Frame);if (frameElements ! null){foreach (var frameElement in frameElements){string regionName frameElement.Attribute(region).Value;TextureRegion region atlas.GetRegion(regionName);frames.Add(region);}}Animation animation new Animation(frames, delay);atlas.AddAnimation(name, animation);}}return atlas;}}}至此我们Atlas的修改到此结束第三步创建AnimationSprite.cs
这个类是什么呢这个就是用来在场景中渲染出这个动画的类效果也就是每帧他会渲染出不同的Sprite而上面哪个Ainmation只起到存储的作用Ok我们直接开始
using System;
using Microsoft.Xna.Framework;namespace SlimeGame.Graphics;public class AnimatedSprite : Sprite
{/// summary/// 当前帧下标/// /summaryprivate int CurrentFrame;/// summary/// 时间间隔/// /summary private TimeSpan Elapsed;/// summary/// 所用动画/// /summaryprivate Animation animation;public Animation Animation{get animation;set{animation value;Region animation.Frames[0];}}/// summary/// 无参构造/// /summarypublic AnimatedSprite() { }/// summary/// 有参构造/// /summary/// param nameanimation动画/param public AnimatedSprite(Animation animation){Animation animation;}/// summary/// 循环播放当前动画组件/// /summary/// param namegameTime/param public void Update(GameTime gameTime){Elapsed gameTime.ElapsedGameTime;if (Elapsed animation.Delay){Elapsed - animation.Delay;CurrentFrame;if (CurrentFrame animation.Frames.Count){CurrentFrame 0;}Region animation.Frames[CurrentFrame];}}
}
然后我们再次返回Atlas在最后完成这个操作public AnimatedSprite CreateAnimatedSprite(string animationName){Animation animation GetAnimation(animationName);return new AnimatedSprite(animation);}那么接写下来我们所要做的工作就全部完成了那么我们接下来给出我们本章所有修改的代码
Animation.cs
using System;
using System.Collections.Generic;namespace SlimeGame.Graphics;public class Animation
{/// summary/// 帧序列存储所有帧图片/// /summary /// value/valuepublic ListTextureRegion Frames { get; set; }/// summary/// 帧间隔存储每帧的时间间隔/// /summary /// value/valuepublic TimeSpan Delay { get; set; }/// summary/// 无参构造/// /summarypublic Animation(){Frames new ListTextureRegion();Delay TimeSpan.FromMilliseconds(100);}/// summary/// 有参构造/// /summarypublic Animation(ListTextureRegion frames, TimeSpan delay){Frames frames;Delay delay;}
}
TextureAtlas.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;namespace SlimeGame.Graphics;/// summary
/// 图集类存储纹理集和
/// /summary
public class TextureAtlas
{/// summary/// 存储每个纹理的字典/// /summaryprivate Dictionarystring, TextureRegion Regions;/// summary/// 存储每个动画的字典/// /summaryprivate Dictionarystring, Animation Animations;/// summary/// 所需总体的纹理图片/// /summarypublic Texture2D TotalTexture { get; set; }/// summary/// 无参构造/// /summarypublic TextureAtlas(){Regions new Dictionarystring, TextureRegion();Animations new Dictionarystring, Animation();}/// summary/// 有参构造/// /summary/// param nametexture所需总体纹理/parampublic TextureAtlas(Texture2D texture){TotalTexture texture;Regions new Dictionarystring, TextureRegion();Animations new Dictionarystring, Animation();}/// summary/// 在图集里增加纹理/// /summary/// param namename纹理对应名称/键/param/// param namex纹理切割X坐标/param/// param namey纹理切割Y坐标/param/// param namewidth纹理切割宽度/param/// param nameheight纹理切割高度/parampublic void AddRegion(string name, int x, int y, int width, int height){TextureRegion region new TextureRegion(TotalTexture, x, y, width, height);Regions.Add(name, region);}/// summary/// 在字典中增加动画/// /summary/// param nameanimationName动画对应名称/键/param/// param nameanimation动画本体/parampublic void AddAnimation(string animationName, Animation animation){Animations.Add(animationName, animation);}/// summary/// 从字典中查询纹理/// /summary/// param namename对应字典名字/键/param/// returns纹理/returnspublic TextureRegion GetRegion(string name){return Regions[name];}/// summary/// 得到当前动画/// /summary/// param nameanimationName动画名称/param/// returns动画本体/returnspublic Animation GetAnimation(string animationName){return Animations[animationName];}/// summary/// 从字典中移除纹理/// /summary/// param namename对应字典名字/键/param/// returns是否删除/returnspublic bool RemoveRegion(string name){return Regions.Remove(name);}/// summary/// 从字典中移除动画/// /summary/// param nameanimationName动画名称/键/param/// returns是否移除/returnspublic bool RemoveAnimation(string animationName){return Animations.Remove(animationName);}/// summary/// 清空此字典/// /summarypublic void RegionsClear(){Regions.Clear();}public void AnimationsClear(){Animations.Clear();}/// summary/// 从文件中加载纹理/// /summary/// param namecontent文件资源管理/param/// param namefileName文件名称/param/// returns/returnspublic static TextureAtlas FromFile(ContentManager content, string fileName){TextureAtlas atlas new TextureAtlas();// 合并文件名成完整项目路径string filePath Path.Combine(content.RootDirectory, fileName);//文件流式存储using (Stream stream TitleContainer.OpenStream(filePath)){// Xml读取器的获得using (XmlReader reader XmlReader.Create(stream)){// 读XMl的文件内容XDocument doc XDocument.Load(reader);XElement root doc.Root;// Texture 该元素包含要加载的 Texture2D 的内容路径.// 因此我们将检索该值然后使用内容管理器加载纹理.string texturePath root.Element(Texture).Value;atlas.TotalTexture content.LoadTexture2D(texturePath);// Regions 该元素包含单独的Region元素每个元素描述// 图集中的其他纹理区域. //// 例子:// Regions// Region namespriteOne x0 y0 width32 height32 /// Region namespriteTwo x32 y0 width32 height32 /// /Regions//// 因此我们检索所有Region元素然后遍历每个元素从中生成一个新的 TextureRegion 实例并将其添加到此图集.var regions root.Element(Regions)?.Elements(Region);if (regions ! null){foreach (var region in regions){string name region.Attribute(name)?.Value;int x int.Parse(region.Attribute(x)?.Value ?? 0);int y int.Parse(region.Attribute(y)?.Value ?? 0);int width int.Parse(region.Attribute(width)?.Value ?? 0);int height int.Parse(region.Attribute(height)?.Value ?? 0);if (!string.IsNullOrEmpty(name)){atlas.AddRegion(name, x, y, width, height);}}}// Animations 该元素包含单独的Animation元素每个元素描述// 在图集中的不同动画//// Example:// Animations// Animation nameanimation delay100// Frame regionspriteOne /// Frame regionspriteTwo /// /Animation// /Animations//// 因此我们检索所有Animation元素然后遍历每个元素// 并从中生成新的 Animation 实例并将其添加到此图集.var animationElements root.Element(Animations).Elements(Animation);if (animationElements ! null){foreach (var animationElement in animationElements){string name animationElement.Attribute(name)?.Value;float delayInMilliseconds float.Parse(animationElement.Attribute(delay)?.Value ?? 0);TimeSpan delay TimeSpan.FromMilliseconds(delayInMilliseconds);ListTextureRegion frames new ListTextureRegion();var frameElements animationElement.Elements(Frame);if (frameElements ! null){foreach (var frameElement in frameElements){string regionName frameElement.Attribute(region).Value;TextureRegion region atlas.GetRegion(regionName);frames.Add(region);}}Animation animation new Animation(frames, delay);atlas.AddAnimation(name, animation);}}return atlas;}}}public Sprite CreatSprite(string regionName){TextureRegion region GetRegion(regionName);return new Sprite(region);}public AnimatedSprite CreateAnimatedSprite(string animationName){Animation animation GetAnimation(animationName);return new AnimatedSprite(animation);}
}
AnimationSprite.cs
using System;
using Microsoft.Xna.Framework;namespace SlimeGame.Graphics;public class AnimatedSprite : Sprite
{/// summary/// 当前帧下标/// /summaryprivate int CurrentFrame;/// summary/// 时间间隔/// /summary private TimeSpan Elapsed;/// summary/// 所用动画/// /summaryprivate Animation animation;public Animation Animation{get animation;set{animation value;Region animation.Frames[0];}}/// summary/// 无参构造/// /summarypublic AnimatedSprite() { }/// summary/// 有参构造/// /summary/// param nameanimation动画/param public AnimatedSprite(Animation animation){Animation animation;}/// summary/// 循环播放当前动画组件/// /summary/// param namegameTime/param public void Update(GameTime gameTime){Elapsed gameTime.ElapsedGameTime;if (Elapsed animation.Delay){Elapsed - animation.Delay;CurrentFrame;if (CurrentFrame animation.Frames.Count){CurrentFrame 0;}Region animation.Frames[CurrentFrame];}}
}
第四步使用动画组件
上面就是我们本次教程修改的全部代码了那么接下来我们来介绍如何使用这个组件
修改·XML
?xml version1.0 encodingutf-8?
TextureAtlasTextureimages/atlas/TextureRegionsRegion nameslime-1 x340 y0 width20 height20 /Region nameslime-2 x340 y20 width20 height20 /Region namebat-1 x340 y40 width20 height20 /Region namebat-2 x340 y60 width20 height20 /Region namebat-3 x360 y0 width20 height20 /Region nameunfocused-button x259 y80 width65 height14 /Region namefocused-button-1 x259 y94 width65 height14 /Region namefocused-button-2 x259 y109 width65 height14 /Region namepanel-background x324 y97 width15 height15 /Region nameslider-off-background x341 y96 width11 height10 /Region nameslider-middle-background x345 y81 width3 height3 /Region nameslider-max-background x354 y96 width11 height10 //RegionsAnimationsAnimation nameslime-animation delay200Frame regionslime-1 /Frame regionslime-2 //AnimationAnimation namebat-animation delay200Frame regionbat-1 /Frame regionbat-2 /Frame regionbat-1 /Frame regionbat-3 //AnimationAnimation namefocused-button-animation delay300Frame regionfocused-button-1 /Frame regionfocused-button-2 //Animation/Animations
/TextureAtlas
加下来将GameMain函数修改至如下所示
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using SlimeGame.Graphics;
using SlimeGameLibrary;namespace SlimeGame;public class GameMain : Core
{private AnimatedSprite _slime;private AnimatedSprite _bat;public GameMain() : base(SlimeGame, 1280, 720, false){}protected override void Initialize(){// TODO: 增加你的初始化逻辑base.Initialize();}protected override void LoadContent(){TextureAtlas atlas TextureAtlas.FromFile(Content, configs/atlas_slice.xml);_slime atlas.CreateAnimatedSprite(slime-animation);_slime.Scale new Vector2(4.0f, 4.0f);_bat atlas.CreateAnimatedSprite(bat-animation);_bat.Scale new Vector2(4.0f, 4.0f);}protected override void Update(GameTime gameTime){if (GamePad.GetState(PlayerIndex.One).Buttons.Back ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))Exit(); // 退出游戏按下Esc键或是手柄上的一个啥键// TODO: 在此处增加你的游戏主循环逻辑_slime.Update(gameTime);_bat.Update(gameTime);base.Update(gameTime);}protected override void Draw(GameTime gameTime){GraphicsDevice.Clear(Color.CornflowerBlue);SpriteBatch.Begin(samplerState: SamplerState.PointClamp);_slime.Draw(SpriteBatch, Vector2.One);_bat.Draw(SpriteBatch, new Vector2(_slime.Width 10, 0));SpriteBatch.End();base.Draw(gameTime);}
}老方法运行这个代码我们看看效果结语
最近不是打算弃坑的只是我最近忙东西忘记更新再加上没过几天都要学车了我最近也是着急忙慌的看科一当然了我这里有一个新项目给大家学习参考也是我缺席着十几天来的成果
https://gitee.com/qiu-tutu/eclipse-game
https://gitee.com/qiu-tutu/eclipse
这两个是我最近今天开发的项目
线上多人射击游戏可创建或者加入房间每个房间最多两人由于素材不完整角色动画步完全我们接下来得不断完善整体游戏逻辑当然是完全免费开源的由于项目工程文件太大了大家可以看第二个仓库的内容里面有所有的完整代码。但是如果想要开发的话还是得自己动手学我是用的服务器是Photon服务器当然我会专门写一篇来处理这些内容地。
接下来是照例地几个问题
什么是Animation
为什么要创建AnimationSprite
创建好后地Animation我们该如何使用