经过上面几节的学习,慢慢的掌握了精灵的一些基本常识,可是咱们知道游戏中游戏精灵都是富于表现能力的,而且经过不一样的动做或者动画去构造一个游戏。ide
这篇文章将学习如何使用系列图为游戏精灵添加动画效果,如下面这一系列图为例,将其分割显示:学习

--这个图片是偷 深蓝 的动画
这是一张png图片,咱们仍是须要把它加载到纹理图形中,能够考虑如何在精灵位图上轮流得到独立的精灵帧。如下编写这个精灵帧所要先获得的信息:this
- 精灵位图中每一个单独图像(帧)的宽和高
- 精灵位图的行与列的总数
- 指示接下来精灵位图中将要绘制精灵帧在精灵位图中所处的行与列的位置索引
上面的那张精灵位图中,每一个单独精灵帧的宽和高都是150像素,有10行1列。因此咱们要绘制它显示在窗口上,就得从第一个精灵帧开始绘制。而这时候咱们就要编写下面的三行代码用来控制精灵帧的切换:spa
Point frameSize
=
new
Point(
150
,
150
);
//
每帧的长与高
Point currentFrame
=
new
Point(
0
,
0
);
//
初始化第一帧
Point sheetSize
=
new
Point(
10
,
1
);
//
定义一个10 列1行的point ,本图片一共有一列10个小人
//
若是有多列则相应改动后面的1
上篇文章咱们有使用SpriteBatch.Draw 的重载方法,其中参数三是一个Rectangle 对象,上篇咱们不设置矩形范围,因此给定一个NULL。而本便咱们须要使用一个 Rectangle 对象来算出该位置的源矩形。添加下面的代码:code
spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend);
spriteBatch.Draw(enemy,
//
纹理图像
new
Vector2((graphics.GraphicsDevice.Viewport.Width
/
2
)
-
(frameSize.X
/
2
),
(graphics.GraphicsDevice.Viewport.Height
/
2
)
-
(frameSize.Y
/
2
)),
//
将系列图放在屏幕中间播放
new
Rectangle(
currentFrame.X
*
frameSize.X,
//
当前的帧点的x 轴乘以每行移动的宽度获得该矩形从屏幕哪一个坐标画
currentFrame.Y
*
frameSize.Y,
//
当前的帧点的Y 轴乘以每行移动的高度获得该矩形从屏幕哪一个坐标画
frameSize.X,
//
须要画该矩形块的宽度为系列图每格小人物的宽度
frameSize.Y),
//
须要画该矩形块的高度为系列图每格小人物的高度
Color.White,
0
,
//
旋转图像,按角度旋转图像,0为不旋转,依次相似一、二、三、四、5等
Vector2.Zero,
//
指定旋转的参照点
1
,
//
缩放比例,这里是按默认比例绽开
SpriteEffects.None,
//
不翻转图像
0
//
纹理层深度
);
spriteBatch.End();
若是按照上面的代码写在Draw 里面的话,仍是没有动画效果的,由于咱们一直重复的上面这张精灵位图的第一帧,为了产生动画,还必须在Update 里面完成状态的更新:对象
++
currentFrame.X;
//
将下标要画的X坐标剃增,即改变该列的位置向下个位置转移
if
(currentFrame.X
>=
sheetSize.X)
//
若是下标大于或者等于系列图的当前列的数量
{
currentFrame.X
=
0
;
//
从新将下标初始化为0
++
currentFrame.Y;
//
将将下标要画的Y坐标剃增,即改变该列的位置向下个位置转移
if
(currentFrame.Y
>=
sheetSize.Y)
//
若是当前的要跳的行大于或等于该系列图的总行数
{
currentFrame.Y
=
0
;
//
从新将其初始化为0
}
}
这个时候,能够ctrl+F5 运行游戏,看看效果。blog
尽管游戏看起来动画效果不错。但有没有发现这个动画的轮换速度也太快了,由于游戏每秒更新30次状态这个己经是很快的速度了。为了使其可以按照咱们要求的速度进行精灵位图切换,咱们能够在Update 的时候作下小手脚,使其动画速度为可控状态,看代码:索引
int
timeSinceLastFrame
=
0
;
//
用来追踪上一帧以后通过多少时间
int
millsecondPreFrame
=
100
;
//
用来指定在移动当前的帧索引以前想要等待的时间隔
修改后的Update 方法,应该是这样子的:游戏
protected
override
void
Update(GameTime gameTime)
{
//
Allows the game to exit
if
(GamePad.GetState(PlayerIndex.One).Buttons.Back
==
ButtonState.Pressed)
this
.Exit();
timeSinceLastFrame
+=
gameTime.ElapsedGameTime.Milliseconds;
//
每次累加游戏的时间
if
(timeSinceLastFrame
>
millsecondPreFrame)
//
若是大于须要等待的时间
{
timeSinceLastFrame
-=
millsecondPreFrame;
//
从新加累加的时间初始化
++
currentFrame.X;
//
将下标要画的X坐标剃增,即改变该列的位置向下个位置转移
if
(currentFrame.X
>=
sheetSize.X)
//
若是下标大于或者等于系列图的当前列的数量
{
currentFrame.X
=
0
;
//
从新将下标初始化为0
++
currentFrame.Y;
//
将将下标要画的Y坐标剃增,即改变该列的位置向下个位置转移
if
(currentFrame.Y
>=
sheetSize.Y)
//
若是当前的要跳的行大于或等于该系列图的总行数
{
currentFrame.Y
=
0
;
//
从新将其初始化为0
}
}
}
//
TODO: Add your update logic here
base
.Update(gameTime);
}
这时,咱们再来看看这个效果:
下一篇将会学习到关于用户输入和碰撞检测方面的知识。