分享我的XNA版超级玛丽(1)
在前文(圆我一个游戏梦,XNA版超级玛丽)中提到本人最近因学习WP开发时,因需要学习XNA,遂产生了尝试开发一个小时候玩过无数遍的游戏"超级玛丽"的想法.
这两天终于完成了游戏的雏形.从本文开始,我将一步步分享开发的历程.由于我没有系统的学习过游戏开发,所以文章中提到的内容也许并不是游戏开发正规的做法,但如果您从未接触过游戏开发,并对此感兴趣,我想我的文章还是能给你带来帮助的.
准备工作
在开始之前,你需要一些必备的开发工具:VS和XNA.以下是本文对应的开发环境
- VS2010
- Microsoft XNA Game Studio 4.0
VS相信大家都有,至于版本,以下是各个VS对应的XNA版本,如果你不是用的VS2010,那么你可以下载对应的XNA版本.
- XNA Game Studio 2.0(VS2005)
- XNA Game Studio 3.0(VS2008)
- XNA Game Studio 3.1(VS2008)
- XNA Game Studio 4.0(VS2010)
下载连接就不贴了,谷哥一下就出来了,我是安装WP7.1时顺带给我装上的.
Hello Mario
准备工作完成,可以正式开始我们的玛丽开发历程了.
打开VS,新建一个项目,选择C#-XNA Game Studio 中的Windows Game(4.0)模板,项目名称为SuperMario,如下图,点确定
这时VS会为我们生成一个名为SuperMario的解决方案,解决方案下面有两个项目,一个是名为SuperMario的主项目,另一个是名为SuperMarioContent的资源项目.SuperMarioContent项目是专门用来存放一些游戏资源的,比如图片,声音,地图什么的.解决方案如下图
打开Game1.cs,这是我们的主游戏文件,类似于新建一个Winform项目时默认创建的Form1.cs,同样,它的加载由Program.cs完成.
我们看到,它有5个重写的方法,前面三个我们看名字也能猜到大概它们的功能.后面两个才是我们关注的重点.这里我简单介绍下,我想大家肯定知道,电影是怎么形成的:一张张静止的图片不断的切换造成视觉上动画.那么游戏其实是一样的,区别就在电影是已经拍好的图片一张张切换,而游戏则是根据玩家的控制,画出相应的静止图片,然后不停的切换,形成动画,也就是说游戏比电影多了一个画的步骤,所以玩游戏比看电影对电脑的配置要求高,因为做的事多了.Game1.cs中的Draw方法就是负责画画的.而Update则是根据玩家的输入和时间的流动更新游戏中的元素.当游戏运行时,Update和Draw方法会不停的轮流运行,即时你没有为游戏添加任何功能.比如你现在按F5运行时,你看到的是一张静止的蓝色背景窗口,但实际上Update和Draw方法会每秒执行60次.
接下来让我们的玛丽出现在游戏画面中.在SuperMarioContent项目中添加一个文件夹,名称为Image,在该文件夹种"添加现有项",添加这张图片,这是mario的素材图片(有点小,大家凑和着用吧.实在找不到更好的了).在Game1.cs中输入如下代码
1 Texture2D _marioText; 2 protected override void LoadContent() 3 { 4 spriteBatch = new SpriteBatch(GraphicsDevice); 5 6 _marioText = this.Content.Load<Texture2D>(@"Image/mario"); 7 } 8 protected override void Draw(GameTime gameTime) 9 { 10 GraphicsDevice.Clear(Color.CornflowerBlue); 11 spriteBatch.Begin(); 12 spriteBatch.Draw(_marioText, new Vector2(100, 100), new Rectangle(0, 0, 16, 16), Color.White, 0, Vector2.Zero, 1.0f, SpriteEffects.None, 0); 13 spriteBatch.End(); 14 base.Draw(gameTime); 15 }
我们在LoadContent中载入了一张图片,然后在Draw方法中,绘制它,绘制的位置是坐标(x:100,y:100),XNA中默认的坐标原点是左上角.绘制时,并有没有绘制整个图片,而是一个小块,这个小块在图片中的位置是(x:0,y:0)长宽为16.按F5运行.Mario已经出现在游戏的画面中了...
跑吧 Mario
一动不动的Mario怎么去救公主呢,我们先来解决Mario跑步的问题.既然Mario能移动,说明他的位置是会变的,为它的位置申明一个变量,然后在Update方法中更新他的位置.代码现在如下
Texture2D _marioText; Vector2 _marioPosition = new Vector2(100, 100); protected override void Update(GameTime gameTime) { if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); _marioPosition.X++; base.Update(gameTime); } protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin(); spriteBatch.Draw(_marioText, _marioPosition, new Rectangle(0, 0, 16, 16), Color.White, 0, Vector2.Zero, 1.0f, SpriteEffects.None, 0); spriteBatch.End(); base.Draw(gameTime); }
按F5运行,怎么样,我们的Mario已经会"移动"了吧?不过现在的移动有点像鬼一样在飘,而且是自动的,不受我们的控制.我们先给他加上控制,一般游戏都是用"A" "D" 键来移动的,一个左移,一个右移.修改Update函数
1 protected override void Update(GameTime gameTime) 2 { 3 if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) 4 this.Exit(); 5 KeyboardState keyState = Keyboard.GetState(); 6 if (keyState.IsKeyDown(Keys.A)) 7 { 8 _marioPosition.X--; 9 } 10 if (keyState.IsKeyDown(Keys.D)) 11 { 12 _marioPosition.X++; 13 } 14 15 base.Update(gameTime); 16 }
代码很好理解,我就不解释了....现在按F5运行,Mario已经成为我们能控制的游戏角色了.但Mario还是像鬼一样在飘,是时候让它的脚动起来了。刚才提到过,所谓的动画,就是不断地切换静态的图片,为了让我们的Mario动起来,我们让Mairo在移动的时候不停的切换mario.png图片中的第二个和第三个小玛丽图片。这里我们给图片的所有小图片的位置编号,从0开始,那么跑步应该用1号和2号图片。先看代码
int _frmStartIndex=0; int _frmEndIndex = 0; int _frmIndex = 0;//当前画的图块的索引 int _frmChangeTime = 100;//多少毫秒换一次图片 int _frmCurrentTime = 0;//距离上次换图片过了多少毫秒 protected override void Update(GameTime gameTime) { if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); KeyboardState keyState = Keyboard.GetState(); if (keyState.IsKeyDown(Keys.A)) { _marioPosition.X--; _frmStartIndex = 1; _frmEndIndex = 2; } if (keyState.IsKeyDown(Keys.D)) { _marioPosition.X++; _frmStartIndex = 1; _frmEndIndex = 2; } if (keyState.GetPressedKeys().Count() == 0) { _frmStartIndex = 0; _frmEndIndex = 0; } _frmCurrentTime += gameTime.ElapsedGameTime.Milliseconds; if (_frmCurrentTime > _frmChangeTime) { _frmCurrentTime = 0; _frmIndex++; if (_frmIndex > _frmEndIndex) _frmIndex = _frmStartIndex; } base.Update(gameTime); } protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin(); spriteBatch.Draw(_marioText, _marioPosition, new Rectangle(_frmIndex * 16, 0, 16, 16), Color.White, 0, Vector2.Zero, 1.0f, SpriteEffects.None, 0); spriteBatch.End(); base.Draw(gameTime); }
请注意Draw函数的第二个参数有一些小的更改,在Update函数中,我们通过判断按键情况选择画图时应该选择的图片块的区域,Mario不动时图片块的索引范围是0-0,移动时是1-2,并且定义了一个切换图片的间隔时间变量_frmChangeTime,在Update函数中不停的累积,当超过100毫秒时,换下一张图片。如果没有这个间隔时间变量,那么每次Update执行都会换图片,那我们的Mario跑起来会疯了一样手舞足蹈。按F5运行,Mario移动时会动了吧,我想一定有人会说“为什么只有手会动,脚不动”,这纯粹是因为我找不到玛丽移动时应该用哪些图,不用怀疑现在的代码,如果你能找到正确的图片,就能让Mario正确的手脚并用跑起来。
处理加速
如果你玩过Mario这个游戏,你一定知道,Mario移动时是有个加速的过程的,而不是一按下跑步键就按固定的速度移动。其实这很容易解决,学过中学物理的我们都知道,加速移动嘛,不就是给个加速度然后运动的时候不停的增加速度。这里我们只要在游戏中通过物理知识模拟真实的运动情况就行了。看代码
float _runAcceleration=0.01F;//跑步加速度 float _runResistance = 0.005F;//... int MAXspeedR = 3;//右移最大速度 int MAXspeedL = -3;//左移最大速度 float _speed = 0;//当前速度 protected override void Update(GameTime gameTime) { if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); KeyboardState keyState = Keyboard.GetState(); int frmTime=gameTime.ElapsedGameTime.Milliseconds; if (keyState.IsKeyDown(Keys.A)) { _speed = _speed < MAXspeedL ? MAXspeedL : _speed - _runAcceleration * frmTime; } if (keyState.IsKeyDown(Keys.D)) { _speed = _speed > MAXspeedR ? MAXspeedR : _speed + _runAcceleration * frmTime; } if (keyState.GetPressedKeys().Count() == 0) { if (_speed > 0) { _speed -= _runResistance * frmTime; if (_speed < 0) _speed = 0; } if (_speed < 0) { _speed += _runResistance * frmTime; if (_speed >0) _speed = 0; } } if (_speed == 0) { _frmStartIndex = 0; _frmEndIndex = 0; } else { _frmStartIndex = 1; _frmEndIndex = 2; } this._marioPosition.X += _speed; _frmCurrentTime += frmTime; if (_frmCurrentTime > _frmChangeTime) { _frmCurrentTime = 0; _frmIndex++; if (_frmIndex > _frmEndIndex) _frmIndex = _frmStartIndex; } base.Update(gameTime); }
Update函数现在可以分为2部分,第一部分根据用户的键盘输入处理Mario速度,用时间乘以加速度得到速度,当用户不再按任何键时,处理减速。第二部分为根据Mario的速度来处理图片索引范围,现在当Mario的速度不为0时,显示跑步图片。这里this._marioPosition.X += _speed;何解呢?因为我们算出的速度是这一帧内的速度,可以理解为单位速度,距离等于速度乘以时间,时间为1,相当于距离等于速度。最后我们按F5运行,怎么样,此时的Mario已经有点感觉了吧。
目前Mario不管左移还是右移,身体都是朝右边的,往左移动时应该面朝左,这个不难处理,图片已经有了,有兴趣的可以自己试试。
结束
第一篇就先介绍到这里,我们的超级玛丽还远远没有完成,剩下的以后慢慢来。希望对大家有帮助。
下雪天的写个伯克不容易,给个好评阿,亲.....