XNA4.0 RPG游戏开发教程(二)
2016-03-02 17:48
447 查看
这个系列教程适合有一定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游戏开发)的第二部分,在这一课我将添加更多的游戏组件,打开我们上一课未完成的解决方案。
首先我们要更新InputHandler.cs,添加对游戏手柄的支持。完整的代码如下
接下来我要添加一些GUI控件,以及一个管理这些控件的类。游戏开发与winform开发有很大的不同,winform开发有很多现成的控件使用,而游戏开发没有任何现成的控件,所有的控件都要自己编写。用一个类来管理每一个游戏状态里所有的控件是很有必要的,首先创建一个所有控件的基类,在“解决方案资源管理器”中右键点击“XRpgLibrary”项目,选择“添加”——“新建文件夹”,给这个文件夹命名为“Controls”,右键点击这个文件夹,选择“添加”——“新建项”——“类”,名字输入“Control”。这个类的代码如下
需要提到的是,在XNA游戏框架内,用SpriteFont来表示游戏内显示文字内容的字体,Color表示文字内容的颜色。关于SpriteFont的详细解释请参考《XNA4.0学习指南》。
ControlManager是接下来我们要添加的类,右键点击“Controls”文件夹,选择“添加”——“新建项”——“类”,名字输入“ControlManager”。这个类的代码如下
List<T>类具有3个构造函数,所以在这个类里我也写了3个具有类似参数的构造函数,selectedIndex字段保存当前选中的控件的序号。
Update方法用来更新控件和处理输入,Draw方法用来绘制控件,NextControl和PreviousControl方法用来在控件之间移动。
NextControl和PreviousControl方法目前还存在一些问题可能导致异常,后续我将更新他们。
译者注:break用于跳出当前循环。
接下来我们要添加具体的控件了,首先添加一个Label控件,用于在游戏里显示文字,右键点击“Controls”文件夹,选择“添加”——“新建项”——“类”,名字输入“Label”,代码如下
接下来再添加一个LinkLabel控件,这个控件与Label很相似,但是它可以被选中。选择“添加”——“新建项”——“类”,名字输入“LinkLabel”,代码如下
在构造函数里,TabStop属性被默认设置为true,这样LinkLabel控件默认可以被选中;HasFocus属性默认为false,即未选中状态。在Draw方法里,如果未选中按通常颜色绘制,如果被选中则按指定的selectedColor颜色绘制。HandleInput方法里,如果未被选中,立即返回,不执行任何操作。如果被选择并且按下键盘Enter键或者游戏手柄A键,则触发OnSelected事件。
在后续的课程中我还会添加其他控件,但是对于本课程来说,这2个控件已经足够我们实现在游戏状态之间切换。接下来我们要做的是添加游戏状态(GameState),一个游戏开始时显示的菜单,这个菜单有不同的选项,玩家可以选择以何种方式开始游戏。
要使用ControlManager,需要一个SpriteFont,右键点击“EyesOfTheDragonContent”项目,选择“添加”——“新建文件夹”,给这个文件夹命名为“Fonts”,右键点击“Fonts”文件夹,选择“添加”——“新建项”——“Sprite Font”,名字输入“ControlFont“,然后将Size修改为20。
我还要小小的修改一下BaseGameState类,修改之后的代码如下
在示范ControlManager的用法之前,我要添加一个screen。右键点击GameScreens文件夹,选择“添加”——“新建项”——“类”,名字输入“StartMenuScreen”,这个类的代码如下
在构造函数的末尾,通过调用stateManager的ChangeState方法直接切换到TitleScreen,成为游戏启动后的第一个显示。
然后打开TitleScreen.cs,由于改动有点多,我直接把代码贴出来
在Update方法中,调用了ControlManager的Update方法,在Draw方法中也调用了ControlManager的Draw方法。
在事件处理函数startLabel_Selected内,调用了StateManager的PushState方法,这样当我们按下ENTER键或者手柄A键的时候,StartMenuScreen就会被压入StateManager的栈中,成为最顶端而显示在游戏中。
本课教程就到这里吧,我尽量让每课教程保持一个合理的长度,这样不会让你一下子面对太多内容。
祝你在游戏开发之旅好运。
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游戏开发)的第二部分,在这一课我将添加更多的游戏组件,打开我们上一课未完成的解决方案。
首先我们要更新InputHandler.cs,添加对游戏手柄的支持。完整的代码如下
using System; using System.Collections.Generic; using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Media; namespace XRpgLibrary { public class InputHandler : Microsoft.Xna.Framework.GameComponent { #region Keyboard Field Region static KeyboardState keyboardState; static KeyboardState lastKeyboardState; #endregion #region Game Pad Field Region static GamePadState[] gamePadStates; static GamePadState[] lastGamePadStates; #endregion #region Keyboard Property Region public static KeyboardState KeyboardState { get { return keyboardState; } } public static KeyboardState LastKeyboardState { get { return lastKeyboardState; } } #endregion #region Game Pad Property Region public static GamePadState[] GamePadStates { get { return gamePadStates; } } public static GamePadState[] LastGamePadStates { get { return lastGamePadStates; } } #endregion #region Constructor Region public InputHandler(Game game) : base(game) { keyboardState = Keyboard.GetState(); gamePadStates = new GamePadState[Enum.GetValues(typeof(PlayerIndex)).Length]; foreach (PlayerIndex index in Enum.GetValues(typeof(PlayerIndex))) gamePadStates[(int)index] = GamePad.GetState(index); } #endregion #region XNA methods public override void Initialize() { base.Initialize(); } public override void Update(GameTime gameTime) { lastKeyboardState = keyboardState; keyboardState = Keyboard.GetState(); lastGamePadStates = (GamePadState[])gamePadStates.Clone(); foreach (PlayerIndex index in Enum.GetValues(typeof(PlayerIndex))) gamePadStates[(int)index] = GamePad.GetState(index); base.Update(gameTime); } #endregion #region General Method Region public static void Flush() { lastKeyboardState = keyboardState; } #endregion #region Keyboard Region public static bool KeyReleased(Keys key) { return keyboardState.IsKeyUp(key) && lastKeyboardState.IsKeyDown(key); } public static bool KeyPressed(Keys key) { return keyboardState.IsKeyDown(key) && lastKeyboardState.IsKeyUp(key); } public static bool KeyDown(Keys key) { return keyboardState.IsKeyDown(key); } #endregion #region Game Pad Region public static bool ButtonReleased(Buttons button, PlayerIndex index) { return gamePadStates[(int)index].IsButtonUp(button) && lastGamePadStates[(int)index].IsButtonDown(button); } public static bool ButtonPressed(Buttons button, PlayerIndex index) { return gamePadStates[(int)index].IsButtonDown(button) && lastGamePadStates[(int)index].IsButtonUp(button); } public static bool ButtonDown(Buttons button, PlayerIndex index) { return gamePadStates[(int)index].IsButtonDown(button); } #endregion } }对于XBOX360来说,可能有4个游戏手柄,所以我使用数组来保存每个手柄的输入,gamePadStates当前帧手柄的输入,lastGamePadStates上一帧手柄的输入,这是与键盘最大的区别,因为键盘通常只有一个,其他的代码都与键盘输入处理类似,他们也都是静态字段、属性、方法。
接下来我要添加一些GUI控件,以及一个管理这些控件的类。游戏开发与winform开发有很大的不同,winform开发有很多现成的控件使用,而游戏开发没有任何现成的控件,所有的控件都要自己编写。用一个类来管理每一个游戏状态里所有的控件是很有必要的,首先创建一个所有控件的基类,在“解决方案资源管理器”中右键点击“XRpgLibrary”项目,选择“添加”——“新建文件夹”,给这个文件夹命名为“Controls”,右键点击这个文件夹,选择“添加”——“新建项”——“类”,名字输入“Control”。这个类的代码如下
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.Controls { public abstract class Control { #region Field Region protected string name; protected string text; protected Vector2 size; protected Vector2 position; protected object value; protected bool hasFocus; protected bool enabled; protected bool visible; protected bool tabStop; protected SpriteFont spriteFont; protected Color color; protected string type; #endregion #region Event Region public event EventHandler Selected; #endregion #region Property Region public string Name { get { return name; } set { name = value; } } public string Text { get { return text; } set { text = value; } } public Vector2 Size { get { return size; } set { size = value; } } public Vector2 Position { get { return position; } set { position = value; position.Y = (int)position.Y; } } public object Value { get { return value; } set { this.value = value; } } public bool HasFocus { get { return hasFocus; } set { hasFocus = value; } } public bool Enabled { get { return enabled; } set { enabled = value; } } public bool Visible { get { return visible; } set { visible = value; } } public bool TabStop { get { return tabStop; } set { tabStop = value; } } public SpriteFont SpriteFont { get { return spriteFont; } set { spriteFont = value; } } public Color Color { get { return color; } set { color = value; } } public string Type { get { return type; } set { type = value; } } #endregion #region Constructor Region public Control() { Color = Color.White; Enabled = true; Visible = true;
SpriteFont = ControlManager.SpriteFont; } #endregion #region Abstract Methods public abstract void Update(GameTime gameTime); public abstract void Draw(SpriteBatch spriteBatch); public abstract void HandleInput(PlayerIndex playerIndex); #endregion #region Virtual Methods protected virtual void OnSelected(EventArgs e) { if (Selected != null) { Selected(this, e); } } #endregion } }这个类有很多保护字段,他们对所有的控件是通用的,通过对应的属性将这些字段公开,所以他们在继承类里可以被重写。OnSelected方法用来触发Selected事件。有3个虚方法在继承类里必须要实现:Update,更新控件;Draw,绘图;HandleInput,处理控件的输入。我们定义的这个控件与winform编程常用的控件有很多相似的字段、属性,比如Name、Text、Value、HasFocus、Enabled、Visible、TabStop等,他们的作用也类似。
需要提到的是,在XNA游戏框架内,用SpriteFont来表示游戏内显示文字内容的字体,Color表示文字内容的颜色。关于SpriteFont的详细解释请参考《XNA4.0学习指南》。
ControlManager是接下来我们要添加的类,右键点击“Controls”文件夹,选择“添加”——“新建项”——“类”,名字输入“ControlManager”。这个类的代码如下
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.Controls { public class ControlManager : List<Control> { #region Fields and Properties int selectedControl = 0; static SpriteFont spriteFont; public static SpriteFont SpriteFont { get { return spriteFont; } } #endregion #region Constructors public ControlManager(SpriteFont spriteFont) : base() { ControlManager.spriteFont = spriteFont; } public ControlManager(SpriteFont spriteFont, int capacity) : base(capacity) { ControlManager.spriteFont = spriteFont; } public ControlManager(SpriteFont spriteFont, IEnumerable<Control> collection) : base(collection) { ControlManager.spriteFont = spriteFont; } #endregion #region Methods public void Update(GameTime gameTime, PlayerIndex playerIndex) { if (Count == 0) return; foreach (Control c in this) { if (c.Enabled) c.Update(gameTime); if (c.HasFocus) c.HandleInput(playerIndex); } if (InputHandler.ButtonPressed(Buttons.LeftThumbstickUp, playerIndex) || InputHandler.ButtonPressed(Buttons.DPadUp, playerIndex) || InputHandler.KeyPressed(Keys.Up)) PreviousControl(); if (InputHandler.ButtonPressed(Buttons.LeftThumbstickDown, playerIndex) || InputHandler.ButtonPressed(Buttons.DPadDown, playerIndex) || InputHandler.KeyPressed(Keys.Down)) NextControl(); } public void Draw(SpriteBatch spriteBatch) { foreach (Control c in this) { if (c.Visible) c.Draw(spriteBatch); } } public void NextControl() { if (Count == 0) return; int currentControl = selectedControl; this[selectedControl].HasFocus = false; do { selectedControl++; if (selectedControl == Count) selectedControl = 0; if (this[selectedControl].TabStop && this[selectedControl].Enabled) break; } while (currentControl != selectedControl); this[selectedControl].HasFocus = true; } public void PreviousControl() { if (Count == 0) return; int currentControl = selectedControl; this[selectedControl].HasFocus = false; do { selectedControl--; if (selectedControl < 0) selectedControl = Count - 1; if (this[selectedControl].TabStop && this[selectedControl].Enabled) break; } while (currentControl != selectedControl); this[selectedControl].HasFocus = true; } #endregion } }这个类是继承于List<T>,它将具有List<T>所有的字段、属性、方法,这样在添加、删除控件的时候使用List<T>自带的方法即可。
List<T>类具有3个构造函数,所以在这个类里我也写了3个具有类似参数的构造函数,selectedIndex字段保存当前选中的控件的序号。
Update方法用来更新控件和处理输入,Draw方法用来绘制控件,NextControl和PreviousControl方法用来在控件之间移动。
NextControl和PreviousControl方法目前还存在一些问题可能导致异常,后续我将更新他们。
译者注:break用于跳出当前循环。
接下来我们要添加具体的控件了,首先添加一个Label控件,用于在游戏里显示文字,右键点击“Controls”文件夹,选择“添加”——“新建项”——“类”,名字输入“Label”,代码如下
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; namespace XRpgLibrary.Controls { public class Label : Control { #region Constructor Region public Label() { tabStop = false; } #endregion #region Abstract Methods public override void Update(GameTime gameTime) { } public override void Draw(SpriteBatch spriteBatch) { spriteBatch.DrawString(SpriteFont, Text, Position, Color); } public override void HandleInput(PlayerIndex playerIndex) { } #endregion } }这个类比较简单,在构造函数里,将tabStop字段默认设置为false,这样Label控件默认无法被选中。在Draw方法中调用spriteBatch.DrawString方法绘制文字。
接下来再添加一个LinkLabel控件,这个控件与Label很相似,但是它可以被选中。选择“添加”——“新建项”——“类”,名字输入“LinkLabel”,代码如下
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.Controls { public class LinkLabel : Control { #region Fields and Properties Color selectedColor = Color.Red; public Color SelectedColor { get { return selectedColor; } set { selectedColor = value; } } #endregion #region Constructor Region public LinkLabel() { TabStop = true; HasFocus = false; Position = Vector2.Zero; } #endregion #region Abstract Methods public override void Update(GameTime gameTime) { } public override void Draw(SpriteBatch spriteBatch) { if (hasFocus) spriteBatch.DrawString(SpriteFont, Text, Position, selectedColor); else spriteBatch.DrawString(SpriteFont, Text, Position, Color); } public override void HandleInput(PlayerIndex playerIndex) { if (!HasFocus) return; if (InputHandler.KeyReleased(Keys.Enter) || InputHandler.ButtonReleased(Buttons.A, playerIndex)) base.OnSelected(null); } #endregion } }这个类也不算太复杂,增加了一个字段selectedColor,表示LinkLabel被选中时的文字颜色。
在构造函数里,TabStop属性被默认设置为true,这样LinkLabel控件默认可以被选中;HasFocus属性默认为false,即未选中状态。在Draw方法里,如果未选中按通常颜色绘制,如果被选中则按指定的selectedColor颜色绘制。HandleInput方法里,如果未被选中,立即返回,不执行任何操作。如果被选择并且按下键盘Enter键或者游戏手柄A键,则触发OnSelected事件。
在后续的课程中我还会添加其他控件,但是对于本课程来说,这2个控件已经足够我们实现在游戏状态之间切换。接下来我们要做的是添加游戏状态(GameState),一个游戏开始时显示的菜单,这个菜单有不同的选项,玩家可以选择以何种方式开始游戏。
要使用ControlManager,需要一个SpriteFont,右键点击“EyesOfTheDragonContent”项目,选择“添加”——“新建文件夹”,给这个文件夹命名为“Fonts”,右键点击“Fonts”文件夹,选择“添加”——“新建项”——“Sprite Font”,名字输入“ControlFont“,然后将Size修改为20。
我还要小小的修改一下BaseGameState类,修改之后的代码如下
using System; using System.Collections.Generic; using System.Linq; using System.Text; using XRpgLibrary; using XRpgLibrary.Controls; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; namespace EyesOfTheDragon.GameScreens { public abstract partial class BaseGameState : GameState { #region Fields region protected Game1 GameRef; protected ControlManager ControlManager; protected PlayerIndex playerIndexInControl; #endregion #region Properties region #endregion #region Constructor Region public BaseGameState(Game game, GameStateManager manager) : base(game, manager) { GameRef = (Game1)game; playerIndexInControl = PlayerIndex.One; } #endregion #region XNA Method Region protected override void LoadContent() { ContentManager Content = Game.Content; SpriteFont menuFont = Content.Load<SpriteFont>(@"Fonts\ControlFont"); ControlManager = new ControlManager(menuFont); base.LoadContent(); } public override void Update(GameTime gameTime) { base.Update(gameTime); } public override void Draw(GameTime gameTime) { base.Draw(gameTime); } #endregion } }添加了ControlManager、playerIndexInControl字段,在LoadContent方法中,加载了SpriteFont,并用这种字体实例化了ControlManager对象。
在示范ControlManager的用法之前,我要添加一个screen。右键点击GameScreens文件夹,选择“添加”——“新建项”——“类”,名字输入“StartMenuScreen”,这个类的代码如下
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; namespace EyesOfTheDragon.GameScreens { public class StartMenuScreen : BaseGameState { #region Field region #endregion #region Property Region #endregion #region Constructor Region public StartMenuScreen(Game game, GameStateManager manager) : base(game, manager) { } #endregion #region XNA Method Region public override void Initialize() { base.Initialize(); } protected override void LoadContent() { base.LoadContent(); } public override void Update(GameTime gameTime) { base.Update(gameTime); } public override void Draw(GameTime gameTime) { if (InputHandler.KeyReleased(Keys.Escape)) { Game.Exit(); } base.Draw(gameTime); } #endregion #region Game State Method Region #endregion } }目前这个类只是一个游戏状态的框架,在下一课我将添加更多内容。我现在只是用它来展示如何在游戏状态之间切换。在Draw方法内,加入了键盘输入检查,如果按下ESC键,则退出游戏。这只是为了展示键盘输入的处理,并不是一个合理的游戏逻辑,在下一课我将更新它。打开Game1.cs,在TitleScreen字段下添加这个screen
public StartMenuScreen StartMenuScreen;在Game1的构造函数里初始化它,Game1的构造函数应该是这样的
public Game1() { graphics = new GraphicsDeviceManager(this); graphics.PreferredBackBufferWidth = screenWidth; graphics.PreferredBackBufferHeight = screenHeight; ScreenRectangle = new Rectangle( 0, 0, screenWidth, screenHeight); Content.RootDirectory = "Content"; Components.Add(new InputHandler(this)); stateManager = new GameStateManager(this); Components.Add(stateManager); TitleScreen = new TitleScreen(this, stateManager); StartMenuScreen = new GameScreens.StartMenuScreen(this, stateManager); stateManager.ChangeState(TitleScreen); }
在构造函数的末尾,通过调用stateManager的ChangeState方法直接切换到TitleScreen,成为游戏启动后的第一个显示。
然后打开TitleScreen.cs,由于改动有点多,我直接把代码贴出来
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using XRpgLibrary; using XRpgLibrary.Controls; namespace EyesOfTheDragon.GameScreens { public class TitleScreen : BaseGameState { #region Field region Texture2D backgroundImage; LinkLabel startLabel; #endregion #region Constructor region public TitleScreen(Game game, GameStateManager manager) : base(game, manager) { } #endregion #region XNA Method region protected override void LoadContent() { ContentManager Content = GameRef.Content; backgroundImage = Content.Load<Texture2D>(@"Backgrounds\titlescreen"); base.LoadContent(); startLabel = new LinkLabel(); startLabel.Position = new Vector2(350, 600); startLabel.Text = "Press ENTER to begin"; startLabel.Color = Color.White; startLabel.TabStop = true; startLabel.HasFocus = true; startLabel.Selected += new EventHandler(startLabel_Selected); ControlManager.Add(startLabel); } public override void Update(GameTime gameTime) { ControlManager.Update(gameTime, PlayerIndex.One); base.Update(gameTime); } public override void Draw(GameTime gameTime) { GameRef.SpriteBatch.Begin(); base.Draw(gameTime); GameRef.SpriteBatch.Draw( backgroundImage, GameRef.ScreenRectangle, Color.White); ControlManager.Draw(GameRef.SpriteBatch); GameRef.SpriteBatch.End(); } #endregion #region Title Screen Methods private void startLabel_Selected(object sender, EventArgs e) { StateManager.PushState(GameRef.StartMenuScreen); } #endregion } }第一个改动是添加了一个LinkLabel控件,在LoadContent方法内,初始化这个控件,例如位置、文字内容、文字颜色等,在这个screen中,startLabel的HasFocus属性为true,所以它是默认选中状态,并且将它的Selected事件绑定到对应的事件处理函数startLabel_Selected,然后把它添加到ControlManager。对于游戏screen来说,在调用base.LoadContent之后初始化控件很重要,这是因为ControlManager在base.LoadContent之后才存在。
在Update方法中,调用了ControlManager的Update方法,在Draw方法中也调用了ControlManager的Draw方法。
在事件处理函数startLabel_Selected内,调用了StateManager的PushState方法,这样当我们按下ENTER键或者手柄A键的时候,StartMenuScreen就会被压入StateManager的栈中,成为最顶端而显示在游戏中。
本课教程就到这里吧,我尽量让每课教程保持一个合理的长度,这样不会让你一下子面对太多内容。
祝你在游戏开发之旅好运。
Jamie McMahon
翻译:阿斌
相关文章推荐
- XNA学习笔记1
- XNA学习笔记3 鼠标响应
- ContentPipeline
- 显示文字与输入
- 物體在二維空間中的移動
- 了解 XNA 的遊戲架構。
- 遊戲畫面管理與切換控制
- 圖形特效與文字顯示
- 2 維動畫與碰撞偵測
- 進階音效控制與管理
- XNA 互動式遊戲設計
- XNA Framework 常用的類別
- VS 2012、VS 2013安装XNA扩展
- XNA4.0 RPG游戏开发教程(一)
- 浅谈AVG游戏中的脚本
- Xna3.1中的2D绘图与AlphaBlend(编辑中)
- XNA4.0学习笔记1:XNA解析及精灵动画
- XNA4.0学习笔记2:控制精灵和碰撞检测
- XNA学习笔记3:创建自定义精灵类
- 00 认识 XNA Game Studio 4.0