XNA4.0 RPG游戏开发教程(五)
2016-03-08 19:00
246 查看
这个系列教程适合有一定C#和XNA4.0基础的朋友,如果没有学习过C#,那么《C#高级编程(第7版)》是一本不错的入门书籍,在http://pan.baidu.com/s/1sko1FnJ可以找到PDF版本,如果你从未接触过XNA4.0,那么《XNA4.0学习指南》是一本不错的入门书籍,在http://pan.baidu.com/s/1baJbWE可以找到PDF版本和随书源代码。
翻译国外的系列教程,一步步讲述如何用XNA4.0开发RPG游戏,是XNA4.0游戏开发为数不多的具有实战意义的教程。
原文地址:http://xnagpa.net/xna4rpg.php
作者非常耐心,每一步操作都讲的很详细,每一课都附有源代码。
我在翻译的过程中,根据作者的教程,又重新把每一课的源代码写一遍,目的是为了验证作者的源代码。
我重写的每一课源代码下载:http://pan.baidu.com/s/1c1tB2Sw
在这个系列教程的前几课,为了照顾初学者,我会加入操作截图,后续的课程我将假定你使用XNA4.0框架已经比较熟练了,所以不会再添加截图。
四、地砖引擎(二)
我正在写一些XNA4.0框架的教程,这些教程如果按照顺序阅读将会起到更好的效果。
这是这个系列教程(XNA4.0 RPG游戏开发)的第五部分,继续完成地砖引擎。目前为止地图已经被绘制,但是你的地图应该能够滚动,这样玩家能够在你的游戏世界移动并探索。实现地图滚动的好方法就是使用2D摄像机,摄像机展示玩家在游戏世界里可以看到的东西。右键点击“TileEngine”文件夹,选择“添加”——“新建项”——“类”,名字输入“Camera”。代码如下
在2个构造函数中,默认将speed设置为4(4像素每帧),zoom为1,即保持原始大小。
在Update方法中,检测玩家的键盘输入(四个方向键),并相应改变玩家在当前地图的位置(坐标)。
接下来我要添加一个表示玩家的类,这个类将负责更新和绘制玩家。右键点击“EyesOfTheDragon”项目,选择“添加”——“新建文件夹”,文件夹的名称为“Components”。右键点击“Components”文件夹,选择“添加”——“新建项”——“类”,名字输入“Player”。代码如下
在构造函数中,gameRef保存了传入的Game对象,并且用当前的屏幕区域初始化了camera对象。
在Update方法中,调用了camera的Update方法。
接下来添加一个“Player”对象到“GamePlayScreen”,首先引入Components的命名空间,然后在构造函数中初始化“Player”对象,代码如下
在来添加2个字段,表示地图的大小,将TileMap类的Field Region区和Property Region区的代码修改为如下
MathHelper.Clamp(value, min, max),value要限制的变量,min最小值,max最大值,如果value<min,返回min,如果value>max,返回max,如果min=<value<=max,返回value。
然后打开GamePlayScreen.cs,修改它的Draw方法为如下代码
public override void Draw(GameTime gameTime)
{
GameRef.SpriteBatch.Begin(
SpriteSortMode.Immediate,
BlendState.AlphaBlend,
SamplerState.PointClamp,
null,
null,
null,
Matrix.Identity);
map.Draw(GameRef.SpriteBatch, player.Camera);
base.Draw(gameTime);
GameRef.SpriteBatch.End();
}
这个时候我们运行游戏,用键盘的方向键可以滚动地图了,而且不会超过地图的边界。有一点你可能会注意到,对角线方向(比如同时按住下、右方向键)地图滚动速度要大于水平或垂直方向滚动速度,这可以用毕达哥拉斯定理解释,当同时按住下、右方向键,地图水平方向滚动了4像素/帧,垂直方向滚动了4像素/帧,设对角线方向滚动的距离为c,c*c=4*4+4*4,结果c=5.66,这个值是大于4像素/帧的。幸运的是,XNA提供了很好的解决这个问题的方法。
打开Camera.cs,修改Update方法为如下代码
public void Update(GameTime gameTime)
{
Vector2 motion = Vector2.Zero;
if (InputHandler.KeyDown(Keys.Left))
motion.X = -speed;
else if (InputHandler.KeyDown(Keys.Right))
motion.X = speed;
if (InputHandler.KeyDown(Keys.Up))
motion.Y = -speed;
else if (InputHandler.KeyDown(Keys.Down))
motion.Y = speed;
if (motion != Vector2.Zero)
motion.Normalize();
position += motion * speed;
LockCamera();
}
我们创建了一个Vector2对象motion,根据检查键盘输入来确定其X、Y方向的值,通过motion.Normalize()将其转换为一个仅表示方向的对象,motion * speed表示在指定方向滚动的距离。
接下来我要演示一个带有多图层的地图,打开TileMap.cs,在Method Region区添加一个AddLayer方法,通过这个方法向现有地图添加图层,代码如下
public void AddLayer(MapLayer layer)
{
if (layer.Width != mapWidth && layer.Height != mapHeight)
throw new Exception("Map layer size exception");
mapLayers.Add(layer);
}
打开GamePlayScreen.cs,修改LoadContent方法,创建一个图层,并添加到地图中,在tileset1.png中,有很多种地砖,目前我们只用到了第一种,我们现在要在新建的图层中随机位置添加80块地砖,每种地砖都是从地砖文件随机抽取,修改之后的LoadContent方法代码如下
protected override void LoadContent()
{
Texture2D tilesetTexture = Game.Content.Load<Texture2D>(@"Tilesets\tileset1");
tileset = new Tileset(tilesetTexture, 8, 8, 32, 32);
MapLayer layer = new MapLayer(40, 40);
for (int y = 0; y < layer.Height; y++)
{
for (int x = 0; x < layer.Width; x++)
{
Tile tile = new Tile(0, 0);
layer.SetTile(x, y, tile);
}
}
map = new TileMap(tileset, layer);
MapLayer splatter = new MapLayer(40, 40);
Random random = new Random();
for (int i = 0; i < 80; i++)
{
int x = random.Next(0, 40);
int y = random.Next(0, 40);
int index = random.Next(2, 14);
Tile tile = new Tile(index, 0);
splatter.SetTile(x, y, tile);
}
map.AddLayer(splatter);
base.LoadContent();
}
接下来我要演示在同一张地图中使用不同的地砖文件,我们已经有了一种地砖文件,这是森林风格的,我们还要一种城市风格的地砖文件,http://xnagpa.net/xna4/downloads/tilesets2.zip可以下载到。下载并解压,复制tileset2.png到EyesOfTheDragonContent项目的Tilesets文件夹,右键点击“Tilesets”文件夹,选择“添加”——“现有项”,将“tileset2.png”添加进来。
打开“GamePlayScreen.cs”,修改LoadContent方法,代码如下
protected override void LoadContent()
{
base.LoadContent();
Texture2D tilesetTexture = Game.Content.Load<Texture2D>(@"Tilesets\tileset1");
Tileset tileset1 = new Tileset(tilesetTexture, 8, 8, 32, 32);
tilesetTexture = Game.Content.Load<Texture2D>(@"Tilesets\tileset2");
Tileset tileset2 = new Tileset(tilesetTexture, 8, 8, 32, 32);
List<Tileset> tilesets = new List<Tileset>();
tilesets.Add(tileset1);
tilesets.Add(tileset2);
MapLayer layer = new MapLayer(40, 40);
for (int y = 0; y < layer.Height; y++)
{
for (int x = 0; x < layer.Width; x++)
{
Tile tile = new Tile(0, 0);
layer.SetTile(x, y, tile);
}
}
MapLayer splatter = new MapLayer(40, 40);
Random random = new Random();
for (int i = 0; i < 80; i++)
{
int x = random.Next(0, 40);
int y = random.Next(0, 40);
int index = random.Next(2, 14);
Tile tile = new Tile(index, 0);
splatter.SetTile(x, y, tile);
}
splatter.SetTile(1, 0, new Tile(0, 1));
splatter.SetTile(2, 0, new Tile(2, 1));
splatter.SetTile(3, 0, new Tile(0, 1));
List<MapLayer> mapLayers = new List<MapLayer>();
mapLayers.Add(layer);
mapLayers.Add(splatter);
map = new TileMap(tilesets, mapLayers);
}
还要修改GamePlayScreen的Draw方法,代码如下
public override void Draw(GameTime gameTime)
{
GameRef.SpriteBatch.Begin(
SpriteSortMode.Immediate,
BlendState.AlphaBlend,
SamplerState.PointClamp,
null,
null,
null,
Matrix.Identity);
map.Draw(GameRef.SpriteBatch, player.Camera); base.Draw(gameTime);
GameRef.SpriteBatch.End();
}
本课教程就到这里吧,我尽量让每课教程保持一个合理的长度,这样不会让你一下子面对太多内容。
祝你在游戏开发之旅好运。
Jamie McMahon
翻译:阿斌
翻译国外的系列教程,一步步讲述如何用XNA4.0开发RPG游戏,是XNA4.0游戏开发为数不多的具有实战意义的教程。
原文地址:http://xnagpa.net/xna4rpg.php
作者非常耐心,每一步操作都讲的很详细,每一课都附有源代码。
我在翻译的过程中,根据作者的教程,又重新把每一课的源代码写一遍,目的是为了验证作者的源代码。
我重写的每一课源代码下载:http://pan.baidu.com/s/1c1tB2Sw
在这个系列教程的前几课,为了照顾初学者,我会加入操作截图,后续的课程我将假定你使用XNA4.0框架已经比较熟练了,所以不会再添加截图。
四、地砖引擎(二)
我正在写一些XNA4.0框架的教程,这些教程如果按照顺序阅读将会起到更好的效果。
这是这个系列教程(XNA4.0 RPG游戏开发)的第五部分,继续完成地砖引擎。目前为止地图已经被绘制,但是你的地图应该能够滚动,这样玩家能够在你的游戏世界移动并探索。实现地图滚动的好方法就是使用2D摄像机,摄像机展示玩家在游戏世界里可以看到的东西。右键点击“TileEngine”文件夹,选择“添加”——“新建项”——“类”,名字输入“Camera”。代码如下
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; namespace XRpgLibrary.TileEngine { public class Camera { #region Field Region Vector2 position; float speed; float zoom; Rectangle viewportRectangle; #endregion #region Property Region public Vector2 Position { get { return position; } private set { position = value; } } public float Speed { get { return speed; } set { speed = (float)MathHelper.Clamp(speed, 1f, 16f); } } public float Zoom { get { return zoom; } } #endregion #region Constructor Region public Camera(Rectangle viewportRect) { speed = 4f; zoom = 1f; viewportRectangle = viewportRect; } public Camera(Rectangle viewportRect, Vector2 position) { speed = 4f; zoom = 1f; viewportRectangle = viewportRect; Position = position; } #endregion #region Method Region public void Update(GameTime gameTime) { if (InputHandler.KeyDown(Keys.Left)) position.X -= speed; else if (InputHandler.KeyDown(Keys.Right)) position.X += speed; if (InputHandler.KeyDown(Keys.Up)) position.Y -= speed; else if (InputHandler.KeyDown(Keys.Down)) position.Y += speed; } #endregion } }这个类有4个字段,“position”,玩家在当前地图的位置(坐标);”speed“,玩家的移动速度;”zoom“,放大倍数;“viewportRectangle”,当前地图中玩家的可见区域。
在2个构造函数中,默认将speed设置为4(4像素每帧),zoom为1,即保持原始大小。
在Update方法中,检测玩家的键盘输入(四个方向键),并相应改变玩家在当前地图的位置(坐标)。
接下来我要添加一个表示玩家的类,这个类将负责更新和绘制玩家。右键点击“EyesOfTheDragon”项目,选择“添加”——“新建文件夹”,文件夹的名称为“Components”。右键点击“Components”文件夹,选择“添加”——“新建项”——“类”,名字输入“Player”。代码如下
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using XRpgLibrary; using XRpgLibrary.TileEngine; namespace EyesOfTheDragon.Components { public class Player { #region Field Region Camera camera; Game1 gameRef; #endregion #region Property Region public Camera Camera { get { return camera; } set { camera = value; } } #endregion #region Constructor Region public Player(Game game) { gameRef = (Game1)game; camera = new Camera(gameRef.ScreenRectangle); } #endregion #region Method Region public void Update(GameTime gameTime) { camera.Update(gameTime); } public void Draw(GameTime gameTime, SpriteBatch spriteBatch) { } #endregion } }这个类在后续的课程中将继续扩展,这个类有2个字段,camera是与Player关联的Camera对象。
在构造函数中,gameRef保存了传入的Game对象,并且用当前的屏幕区域初始化了camera对象。
在Update方法中,调用了camera的Update方法。
接下来添加一个“Player”对象到“GamePlayScreen”,首先引入Components的命名空间,然后在构造函数中初始化“Player”对象,代码如下
using EyesOfTheDragon.Components; #region Field Region Engine engine = new Engine(32, 32); Tileset tileset; TileMap map; Player player; #endregion #region Constructor Region public GamePlayScreen(Game game, GameStateManager manager) : base(game, manager) { player = new Player(game); } #endregion然后在Update方法中调用player的Update方法,修改Update方法的代码为如下
public override void Update(GameTime gameTime) { player.Update(gameTime); base.Update(gameTime); }接下来还要修改一下“TileMap”类的代码,修改之后的完整代码如下所示
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; namespace XRpgLibrary.TileEngine { public class TileMap { #region Field Region List<Tileset> tilesets; List<MapLayer> mapLayers; #endregion #region Property Region #endregion #region Constructor Region public TileMap(List<Tileset> tilesets, List<MapLayer> layers) { this.tilesets = tilesets; this.mapLayers = layers; } public TileMap(Tileset tileset, MapLayer layer) { tilesets = new List<Tileset>(); tilesets.Add(tileset); mapLayers = new List<MapLayer>(); mapLayers.Add(layer); } #endregion #region Method Region public void Draw(SpriteBatch spriteBatch) { Rectangle destination = new Rectangle(0, 0, Engine.TileWidth, Engine.TileHeight); Tile tile; foreach (MapLayer layer in mapLayers) { for (int y = 0; y < layer.Height; y++) { destination.Y = y * Engine.TileHeight; for (int x = 0; x < layer.Width; x++) { tile = layer.GetTile(x, y); destination.X = x * Engine.TileWidth; spriteBatch.Draw( tilesets[tile.Tileset].Texture, destination, tilesets[tile.Tileset].SourceRectangles[tile.TileIndex], Color.White); } } } } #endregion } }我们要在TileMap类中使用camera对象,最好的方法就是将camera对象作为参数传递到Draw方法,我们将使用camera对象来控制地砖将要被绘制到哪里(因为地图是随着玩家的移动滚动的),修改Draw方法为如下代码
public void Draw(SpriteBatch spriteBatch, Camera camera) { Rectangle destination = new Rectangle(0, 0, Engine.TileWidth, Engine.TileHeight); Tile tile; foreach (MapLayer layer in mapLayers) { for (int y = 0; y < layer.Height; y++) { destination.Y = y * Engine.TileHeight - (int)camera.Position.Y; for (int x = 0; x < layer.Width; x++) { tile = layer.GetTile(x, y); if (tile.TileIndex == -1 || tile.Tileset == -1) continue; destination.X = x * Engine.TileWidth - (int)camera.Position.X; spriteBatch.Draw( tilesets[tile.Tileset].Texture, destination, tilesets[tile.Tileset].SourceRectangles[tile.TileIndex], Color.White); } } } }
在来添加2个字段,表示地图的大小,将TileMap类的Field Region区和Property Region区的代码修改为如下
#region Field Region List<Tileset> tilesets; List<MapLayer> mapLayers; static int mapWidth; static int mapHeight; #endregion #region Property Region public static int WidthInPixels { get { return mapWidth * Engine.TileWidth; } } public static int HeightInPixels { get { return mapHeight * Engine.TileHeight; } } #endregion然后在构造函数中初始化他们,修改构造函数为如下
#region Constructor Region public TileMap(List<Tileset> tilesets, List<MapLayer> layers) { this.tilesets = tilesets; this.mapLayers = layers; mapWidth = mapLayers[0].Width; mapHeight = mapLayers[0].Height; for (int i = 1; i < layers.Count; i++) { if (mapWidth != mapLayers[i].Width || mapHeight != mapLayers[i].Height) throw new Exception("Map layer size exception"); } } public TileMap(Tileset tileset, MapLayer layer) { tilesets = new List<Tileset>(); tilesets.Add(tileset); mapLayers = new List<MapLayer>(); mapLayers.Add(layer); mapWidth = mapLayers[0].Width; mapHeight = mapLayers[0].Height; } #endregion当玩家在地图中移动时,我们不希望摄像头超出地图边界,所以要添加一个锁定摄像头的方法。打开Camera.cs,添加一个LockCamera方法,并且在Update方法中调用LockCamera方法锁定摄像头,修改Camera类的Method Region区,代码如下
#region Method Region public void Update(GameTime gameTime) { if (InputHandler.KeyDown(Keys.Left)) position.X -= speed; else if (InputHandler.KeyDown(Keys.Right)) position.X += speed; if (InputHandler.KeyDown(Keys.Up)) position.Y -= speed; else if (InputHandler.KeyDown(Keys.Down)) position.Y += speed; LockCamera(); } private void LockCamera() { position.X = MathHelper.Clamp(position.X, 0, TileMap.WidthInPixels - viewportRectangle.Width); position.Y = MathHelper.Clamp(position.Y, 0, TileMap.HeightInPixels - viewportRectangle.Height); } #endregion在LockCamera方法中,通过MathHelper.Clamp方法来限制position的值。
MathHelper.Clamp(value, min, max),value要限制的变量,min最小值,max最大值,如果value<min,返回min,如果value>max,返回max,如果min=<value<=max,返回value。
然后打开GamePlayScreen.cs,修改它的Draw方法为如下代码
public override void Draw(GameTime gameTime)
{
GameRef.SpriteBatch.Begin(
SpriteSortMode.Immediate,
BlendState.AlphaBlend,
SamplerState.PointClamp,
null,
null,
null,
Matrix.Identity);
map.Draw(GameRef.SpriteBatch, player.Camera);
base.Draw(gameTime);
GameRef.SpriteBatch.End();
}
这个时候我们运行游戏,用键盘的方向键可以滚动地图了,而且不会超过地图的边界。有一点你可能会注意到,对角线方向(比如同时按住下、右方向键)地图滚动速度要大于水平或垂直方向滚动速度,这可以用毕达哥拉斯定理解释,当同时按住下、右方向键,地图水平方向滚动了4像素/帧,垂直方向滚动了4像素/帧,设对角线方向滚动的距离为c,c*c=4*4+4*4,结果c=5.66,这个值是大于4像素/帧的。幸运的是,XNA提供了很好的解决这个问题的方法。
打开Camera.cs,修改Update方法为如下代码
public void Update(GameTime gameTime)
{
Vector2 motion = Vector2.Zero;
if (InputHandler.KeyDown(Keys.Left))
motion.X = -speed;
else if (InputHandler.KeyDown(Keys.Right))
motion.X = speed;
if (InputHandler.KeyDown(Keys.Up))
motion.Y = -speed;
else if (InputHandler.KeyDown(Keys.Down))
motion.Y = speed;
if (motion != Vector2.Zero)
motion.Normalize();
position += motion * speed;
LockCamera();
}
我们创建了一个Vector2对象motion,根据检查键盘输入来确定其X、Y方向的值,通过motion.Normalize()将其转换为一个仅表示方向的对象,motion * speed表示在指定方向滚动的距离。
接下来我要演示一个带有多图层的地图,打开TileMap.cs,在Method Region区添加一个AddLayer方法,通过这个方法向现有地图添加图层,代码如下
public void AddLayer(MapLayer layer)
{
if (layer.Width != mapWidth && layer.Height != mapHeight)
throw new Exception("Map layer size exception");
mapLayers.Add(layer);
}
打开GamePlayScreen.cs,修改LoadContent方法,创建一个图层,并添加到地图中,在tileset1.png中,有很多种地砖,目前我们只用到了第一种,我们现在要在新建的图层中随机位置添加80块地砖,每种地砖都是从地砖文件随机抽取,修改之后的LoadContent方法代码如下
protected override void LoadContent()
{
Texture2D tilesetTexture = Game.Content.Load<Texture2D>(@"Tilesets\tileset1");
tileset = new Tileset(tilesetTexture, 8, 8, 32, 32);
MapLayer layer = new MapLayer(40, 40);
for (int y = 0; y < layer.Height; y++)
{
for (int x = 0; x < layer.Width; x++)
{
Tile tile = new Tile(0, 0);
layer.SetTile(x, y, tile);
}
}
map = new TileMap(tileset, layer);
MapLayer splatter = new MapLayer(40, 40);
Random random = new Random();
for (int i = 0; i < 80; i++)
{
int x = random.Next(0, 40);
int y = random.Next(0, 40);
int index = random.Next(2, 14);
Tile tile = new Tile(index, 0);
splatter.SetTile(x, y, tile);
}
map.AddLayer(splatter);
base.LoadContent();
}
接下来我要演示在同一张地图中使用不同的地砖文件,我们已经有了一种地砖文件,这是森林风格的,我们还要一种城市风格的地砖文件,http://xnagpa.net/xna4/downloads/tilesets2.zip可以下载到。下载并解压,复制tileset2.png到EyesOfTheDragonContent项目的Tilesets文件夹,右键点击“Tilesets”文件夹,选择“添加”——“现有项”,将“tileset2.png”添加进来。
打开“GamePlayScreen.cs”,修改LoadContent方法,代码如下
protected override void LoadContent()
{
base.LoadContent();
Texture2D tilesetTexture = Game.Content.Load<Texture2D>(@"Tilesets\tileset1");
Tileset tileset1 = new Tileset(tilesetTexture, 8, 8, 32, 32);
tilesetTexture = Game.Content.Load<Texture2D>(@"Tilesets\tileset2");
Tileset tileset2 = new Tileset(tilesetTexture, 8, 8, 32, 32);
List<Tileset> tilesets = new List<Tileset>();
tilesets.Add(tileset1);
tilesets.Add(tileset2);
MapLayer layer = new MapLayer(40, 40);
for (int y = 0; y < layer.Height; y++)
{
for (int x = 0; x < layer.Width; x++)
{
Tile tile = new Tile(0, 0);
layer.SetTile(x, y, tile);
}
}
MapLayer splatter = new MapLayer(40, 40);
Random random = new Random();
for (int i = 0; i < 80; i++)
{
int x = random.Next(0, 40);
int y = random.Next(0, 40);
int index = random.Next(2, 14);
Tile tile = new Tile(index, 0);
splatter.SetTile(x, y, tile);
}
splatter.SetTile(1, 0, new Tile(0, 1));
splatter.SetTile(2, 0, new Tile(2, 1));
splatter.SetTile(3, 0, new Tile(0, 1));
List<MapLayer> mapLayers = new List<MapLayer>();
mapLayers.Add(layer);
mapLayers.Add(splatter);
map = new TileMap(tilesets, mapLayers);
}
还要修改GamePlayScreen的Draw方法,代码如下
public override void Draw(GameTime gameTime)
{
GameRef.SpriteBatch.Begin(
SpriteSortMode.Immediate,
BlendState.AlphaBlend,
SamplerState.PointClamp,
null,
null,
null,
Matrix.Identity);
map.Draw(GameRef.SpriteBatch, player.Camera); base.Draw(gameTime);
GameRef.SpriteBatch.End();
}
本课教程就到这里吧,我尽量让每课教程保持一个合理的长度,这样不会让你一下子面对太多内容。
祝你在游戏开发之旅好运。
Jamie McMahon
翻译:阿斌
相关文章推荐
- XNA学习笔记1
- XNA学习笔记3 鼠标响应
- ContentPipeline
- 显示文字与输入
- 物體在二維空間中的移動
- 了解 XNA 的遊戲架構。
- 遊戲畫面管理與切換控制
- 圖形特效與文字顯示
- 2 維動畫與碰撞偵測
- 進階音效控制與管理
- XNA 互動式遊戲設計
- XNA Framework 常用的類別
- VS 2012、VS 2013安装XNA扩展
- XNA4.0 RPG游戏开发教程(一)
- XNA4.0 RPG游戏开发教程(二)
- XNA4.0 RPG游戏开发教程(三)
- XNA4.0 RPG游戏开发教程(四)
- 浅谈AVG游戏中的脚本
- Xna3.1中的2D绘图与AlphaBlend(编辑中)
- XNA4.0学习笔记1:XNA解析及精灵动画