我们有一个大的思路,那就是现在有一个Game1类,它是启动类,并且,它的Update和Draw函数被每帧每帧地调用。
我们可能有很多角色或者是其他的游戏元素,他们实现了一个接口,这个接口中有Update和Draw的定义,然后Game1的Update和Draw调用它们。
这样就是简单的XNA架构。
所以我们新建一个接口,叫“IRole”,定义了方法Update和Draw,它的代码大概是:
interface IRole { void Update(GameTime gameTime); void Draw(GameTime gameTime); }
所以我们新建一个角色类,我起名叫“SmartRole”,做法是添加一个类,实现了IRole接口,到“Smartoys”项目中,它的代码大概是:
class SmartRole:IRole { public void Update(GameTime gameTime) { } public void Draw(GameTime gameTime) { } }
这是我们的第一个角色。到这里顺便说下gameTime,这个参数可以得到一些游戏运行时间的东西,比如每帧多少微秒。等到后边我在说游戏状态改变的时候,就会看到了。
这时我们可以在Game1中定义一个IRole iRole = new SmartRole(),并且在Update和Draw中调用这个iRole的Update和Draw。但是屏幕并不会改变,这是因为我们还没有添加图片呢(废话)。
对于图片,我们看看解决方案中的SmartoysContent项目,在其中新建一个名为“Images”的文件夹,里边右键新建现有项,把自己的图片打开并保存在这里,就算添加进来了。如图所示:
这里,图片的格式,建议大家都使用png格式存储,因为jpg和gif保存图片都会有损(自己试试就知道,图片会出花点的),而bmp格式不支持透明色,唯独png格式又没损失,又支持透明色,用于游戏图片非常方便。
一个角色往往有很多张图片,分别是这个角色的不同动作状态所对应的图片,一般来说这些都要放在一张png图片中,排好横竖,就像我下面的这张图片:
(图片来自于FC游戏《洛克人》美特鲁截图,制作人为卡普空公司)
两行三列,共有4个状态图片和1个角色子弹图片。
在代码中,定义如下字段(就是Java的属性,你懂的):
private Texture2D smartRolePicture; private Point currentFrame = new Point(0, 0); //当前用图片是第0行0列的图片 private Point sheetSize = new Point(2, 3); //两行三列 private Point frameSize = new Point(40, 40); //每张图片的大小是40*40
在构造器里,添加如下代码加载png图片:
smartRolePicture = Content.Load<Texture2D>(@"images\美特鲁");
这里注意不写png扩展名。
这时该在Draw里写代码了,我们发现缺少一些东西。给Draw方法重构增加参数SpriteBatch spriteBatch,这个东西是用于绘制的东西,必须要添加进来。
这时候在Draw方法里使用这句就可以了:
spriteBatch.Draw(smartRolePicture, new Vector2(X, Y), new Rectangle(currentFrame.X * frameSize.X, currentFrame.Y * frameSize.Y, frameSize.X, frameSize.Y), Color.White, 0, Vector2.Zero, 1f, SpriteEffects.None, 0);
smartRolePicture说明了要显示哪个Texture2D。X和Y是这个角色的属性,分别对应x和y字段,表示角色在坐标系中的位置,需要自己定义,定义好后,可以先设置为。new Rectangle指明了显示整张png中的哪个图片。Color.White表示不染色,这个可以自己修改看看效果。0表示旋转角度是0,先不改。Vector2.Zero表示显示图片的起始位置,具体我没用过,自己看吧。1f表示1倍大小显示角色图片。SpriteEffects可以玩翻转。最后一个0表示层深,也就是角色在整个游戏程序中的图片是第几层,可以用也可以不用。
大家看到这里肯定会想,参数也太多了吧,的确,这个方法还有很多参数少的重载方法,用用就知道了。
这时,还需要把Game1的Draw修改成类似如下代码:
Matrix scaleMatrix = Matrix.CreateScale(stretchX, stretchY, 0f); //stretchX和stretchY是我自己定义的float型变量,可以随意改变游戏画面大小 //0f我没用过 spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, null, null, null, scaleMatrix); //这里边有很多参数,我都没怎么了解,有兴趣的读者可以自己尝试,不过最后边的那个scaleMatrix是我自己定义的,因为我希望修改它的stretchX和stretchY就可以随意改变游戏画面大小 iRole.Draw(gameTime, spriteBatch); //调用iRole的Draw spriteBatch.End(); base.Draw(gameTime);
注意调用角色的Draw要卸载spriteBatch的Begin和End之间。
这时有的读者可能发现,我为什么要在这里设置一个scaleMatrix而不是在角色的spriteBatch.Draw的参数里修改缩放倍数,这是因为两者的效果不一样。前者只是最普通的缩放,会出现马赛克,而后者会使用一些缩放算法减少马赛克。在我的游戏中,前者是我的选择。
这时候运行调试,游戏程序窗口就会出现一个图片,而且是png图片的一部分。