XNA游戏开发之2D游戏

简介:

摘要:以XNA为基础的游戏可以利用3D模型为游戏加入动画效果,也可以利用简单的程序技巧将2维图片显示成动画。虽然2维动画相对3维动画来说简单一些,但是制作出来的游戏其趣味性和挑战性也绝不逊色。今天我们就一块学习一下在使用XNA Framework开发2D游戏时的一些基础知识和注意事项。

主要内容:

1.2D游戏动画的基本原理

2.动画素材的准备

3.一个简单的2D动画

一、2D游戏动画的基本原理

在XNA中制作2D动画的过程很像翻卡通小人书,首先绘制好各种角色造型,然后以固定的时间间隔来显示不同的图片,当时间间隔小到一定程度时人眼就难以区分,从而形成一种动画效果。如果做过flash或者使用fireworks做过gif的朋友可能更容易理解,它就像flash中的逐帧动画一样,每帧显示一个图片,然后连起来就形成了动画效果。由于在XNA中有SpriteBatch可以绘制图片精灵,这样一来我们只需事先做好不同的角色造型的图片,每次在执行Update方法的时候改变绘制的精灵图片就可以制作出动画效果。

二、动画素材的准备

XNA开发2D动画的原理比较容易理解,我也就不过多的赘余了,现在我们就开始准备游戏素材。XNA的SpriteBatch的绘制方法有点类似于样式表CSS的background属性,可以通过设置参数来显示一个图片的其中一部分,这样一来我们为了方便管理游戏角色就只需要将同一角色的不同造型放到同一张图片中,每次更新时显示图片的不同部分就可以了。例如下面这幅图片就是如此:

精灵图片

在这幅图片中我们将22个不同造型的角色放到同一幅图片中,事先规划好每个小图片的大小,保证各个图片连接起来播放时能够形成一组连贯的动作。当然,为了让整个效果看起来更生动一些我们再来准备一张背景图片:

游戏背景

三、一个简单的2D动画

有了上面的游戏素材,我们就来简单模拟一下植物大战僵尸中的一个场景。在下面的Demo中表现了两种运动:其一就是我们要控制22个小图片之间的切换,以此产生角色行动的动画(在原地);其二就是控制图片切换的同时我们需要移动图片的位置从而形成角色在水平方向上行走动作。具体代码如下:

复制代码

  
  
1 using System;
2   using System.Collections.Generic;
3 using System.Linq;
4 using Microsoft.Xna.Framework;
5 using Microsoft.Xna.Framework.Audio;
6 using Microsoft.Xna.Framework.Content;
7 using Microsoft.Xna.Framework.GamerServices;
8 using Microsoft.Xna.Framework.Graphics;
9 using Microsoft.Xna.Framework.Input;
10 using Microsoft.Xna.Framework.Input.Touch;
11 using Microsoft.Xna.Framework.Media;
12 namespace _2DAnimation
13 {
14 public class MyGame : Microsoft.Xna.Framework.Game
15 {
16 GraphicsDeviceManager graphics;
17 SpriteBatch spriteBatch;
18 private Texture2D corpse; // 图片资源
19 private Point frameSize; // 每个小图片大小
20 private Point sheetSize; // 小图片个数
21 private Point currentFrame; // 当前小图片位置
22 private Vector2 postion; // 角色所在位置
23 private float speed; // 角色行走速度
24 private Texture2D background;
25 public MyGame()
26 {
27 graphics = new GraphicsDeviceManager( this );
28 Content.RootDirectory = " Content " ;
29 graphics.PreferredBackBufferWidth = 800 ; // 设置游戏视窗大小
30 graphics.PreferredBackBufferHeight = 480 ;
31 TargetElapsedTime = TimeSpan.FromTicks( 333333 * 2 );
32 }
33 protected override void Initialize()
34 {
35 frameSize = new Point( 100 , 125 );
36 sheetSize = new Point( 11 , 2 );
37 currentFrame = new Point( 0 , 0 );
38 postion = new Vector2(graphics.PreferredBackBufferWidth - 100 ,graphics.PreferredBackBufferHeight - 125 - 150 );
39 speed = 3 ;
40 base .Initialize();
41 }
42 protected override void LoadContent()
43 {
44 spriteBatch = new SpriteBatch(GraphicsDevice);
45 background = this .Content.Load < Texture2D > ( " background " ); // 加载游戏背景
46 corpse = this .Content.Load < Texture2D > ( " transparentCorpse " ); // 加载整张大图片(透明背景)
47 }
48 protected override void UnloadContent()
49 {
50 }
51 protected override void Update(GameTime gameTime)
52 {
53 if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
54 this .Exit();
55 ++ currentFrame.X;
56 if (currentFrame.X >= sheetSize.X)
57 {
58 currentFrame.X = 0 ;
59 ++ currentFrame.Y;
60 if (currentFrame.Y >= sheetSize.Y)
61 {
62 currentFrame.Y = 0 ;
63 }
64 }
65 postion.X -= speed;
66 if (postion.X < 20 )
67 {
68 this .Exit(); // 角色进入房屋后退出游戏
69 }
70 base .Update(gameTime);
71 }
72 protected override void Draw(GameTime gameTime)
73 {
74 GraphicsDevice.Clear(Color.CornflowerBlue);
75 spriteBatch.Begin(SpriteSortMode.BackToFront,BlendState.NonPremultiplied); // 所有的绘制工作均在sprite的begin和end中间进行
76 spriteBatch.Draw(
77 corpse, // 要绘制的精灵
78 postion, // 绘制的位置
79 new Rectangle(currentFrame.X * frameSize.X, currentFrame.Y * frameSize.Y, frameSize.X, frameSize.Y), // 绘制精灵的哪一部分
80 Color.White, // 颜色
81 0 , // 旋转角度
82 Vector2.Zero, // 旋转参考点
83 1 , // 缩放倍数
84 SpriteEffects.None, // 翻转
85 0 // 层深
86 );
87 spriteBatch.Draw(background, Vector2.Zero, Color.White);
88 spriteBatch.End();
89 base .Draw(gameTime);
90 }
91 }
92 }
复制代码

代码总体来说还是比较简单,主要通过在Update方法中动态修改currentFrame来形成图片切换,当然之所以这样是因为Draw方法的第三个参数,通过它我们才能做到一张图片的局部显示(具体来说就是在Rectangle中指定corpse精灵的起始坐标和要显示的图片宽度和高度)。图片的水平移动主要通过在Update中动态修改position变量的值,当然这里需要注意图片超出游戏视窗的情况。下面是运行效果:

截图效果:

游戏截图效果

动画效果:

游戏动画效果

值得一提的是,我们这里牵扯到了图片显示的层深问题,如果注意看代码的朋友会发现我们并没有首先绘制游戏背景,而是先绘制了游戏角色(当然我是为了说明层深问题而故意这么做的)。默认情况下载XNA会按照程序调用顺序绘制精灵,这样我们就看不到角色了,因为它被背景图片遮住了。如果说遇到了这种情况(事实上游戏开发中经常遇到)我们就需要设置图片的层深,也就是我们上面代码中Draw方法的最后一个参数。它是float类型,其取值范围是0-1。具体0是代表最先绘制还是最后绘制则完全取决于SpriteBatch的Begin方法中的第一个参数,这个参数是SpriteSortMode,他是一个枚举类型,有五种模式:

取值

描述

Deferred

这是默认模式,此模式下只有在SpriteBatch调用End方法时才会被绘制,如果绘制多个精灵则按照调用次序依次进行。

Texture

同Deferred类似,在绘制之前会按照纹理排序,对于相同深度而不互相重叠的情况下效果较好。

BackToFront

在End方法执行后绘制精灵,绘制精灵的顺序按照层深度由前往后排序(先绘制层深值较小的)。

FrontToBack

在End方法执行后绘制精灵,绘制精灵的顺序按照层深度由后往前排序(先绘制层深值较大的)。

Immediate

调用Begin方法后就会立即绘制精灵(这也是五种模式中唯一在End方法之前就进行绘制的),同一时间只有一个SpriteBatch被使用。

另一点需要注意的是,我们的角色是透明的,在XNA Game开发中如果想要让图片透明有两种方式:第一就是图片本省就是透明,此时当然需要选用能够存储图像alpha的图片格式来保存图片(例如png格式可以将图像的alpha存储到图片信息中,我们上的例子中就是这么做的。事实上GIF也可以,但是在XNA中默认不支持GIF);第二种方式就是将图片需要显示成透明的部分设置为洋红色(RGB:255,0,255),这样XNA会自动将洋红色部分渲染成透明。

OK,最后附上代码下载:

Download

目录
相关文章
|
人工智能 安全 Unix
游戏编程之九 设计工具之游戏引擎
游戏编程之九 设计工具之游戏引擎
88 0
|
6月前
|
Linux iOS开发 MacOS
游戏开发丨基于PyGlet的简易版Minecraft我的世界游戏
游戏开发丨基于PyGlet的简易版Minecraft我的世界游戏
153 2
|
5月前
Libgdx游戏开发(7)——开始游戏界面实现
使用上的注意事项 1. 切换到一个新的Screen的时候,如果之前的Screen不再使用,需要手动调用Screen.dispose方法,进行资源的释放 2. 给Game对象设置Screen的时候,设置的新的那个Screen会调用onShow()方法,而之前的Screen会调用onHide()方法 3. 如果有需要的话,一般在onShow()方法,给当前Screen设置一个输入监听器 优化尝试 - 全局game对象
54 0
游戏开发零基础入门教程(10):游戏积木之碰撞
顾名思义就是两个物体碰到一起。联系到我们的现实世界,你随手将一个东西扔出去,这个东西最终掉落在地上,就可以说这个东西与地面发生了碰撞。在游戏开发中,我们关注的“碰撞”重点在于发生的那一刻:是谁碰到了谁,碰撞的一方或者被撞的一方又该做出怎样的反应。
77 0
游戏开发零基础入门教程(10):游戏积木之碰撞
【游戏开发】游戏概念设计
游戏一直是人们追逐的梦想之一。如今,游戏一步一步地从以前的简单娱乐工具发展为现代娱乐、竞技甚至在某些方面能够模拟现实生活的现代工具。随着技术的不断进步,游戏的品质和数量也在不断提高。
|
开发工具
游戏开发零基础入门教程系列:人人都能做游戏
你正在阅读的是我原创的游戏开发零基础入门教程系列,面向的是没人任何游戏开发和编程经验,想要学习自己做游戏的普通人。这个系列教程已经帮助了很多人做出了自己人生的第一个游戏,希望它也能帮助到你。
412 0
|
开发者 Python
小游戏开发_完成游戏|学习笔记
快速学习 小游戏开发_完成游戏
150 0
|
图形学
Unity3D游戏引擎为何能让游戏发烧友如此痴狂
前景好——高薪行业里的天生贵族学习Unity3d很多人都是冲着游戏开发工程师的目标而来。目前游戏逐渐占领大众娱乐市场,整个行业结构正在发生翻天覆地的变化。游戏产业作为一个新兴产业,从初期形成到现如今的快速发展并迅速走向成熟时期,游戏行业已经成为文化娱乐产业、网络经济的重要组成部分,成为所有行业中发展前景最好的朝阳产业。
1244 0

热门文章

最新文章