您的位置:首页 > 其它

XNA4.0 RPG游戏开发教程(六)

2016-03-10 10:43 281 查看
这个系列教程适合有一定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游戏开发)的第六部分,在这一课我将添加一个新的screen来创建一个角色。首先我要添加一个新的控件,一个左右选择器,当选中这个控件,并按下左、右方向键的时候会在一个字符串集合中循环。右键点击“Controls”文件夹,选择“添加”——“新建项”——“类”,名字输入“LeftRightSelector”。代码如下

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 LeftRightSelector : Control
{
#region Event Region
public event EventHandler SelectionChanged;
#endregion
#region Field Region
List<string> items = new List<string>();
Texture2D leftTexture;
Texture2D rightTexture;
Texture2D stopTexture;
Color selectedColor = Color.Red;
int maxItemWidth;
int selectedItem;
#endregion
#region Property Region
public Color SelectedColor
{
get { return selectedColor; }
set { selectedColor = value; }
}
public int SelectedIndex
{
get { return selectedItem; }
set { selectedItem = (int)MathHelper.Clamp(value, 0f, items.Count); }
}
public string SelectedItem
{
get { return Items[selectedItem]; }
}
public List<string> Items
{
get { return items; }
}
#endregion
#region Constructor Region
public LeftRightSelector(Texture2D leftArrow, Texture2D rightArrow, Texture2D stop)
{
leftTexture = leftArrow;
rightTexture = rightArrow;
stopTexture = stop;
TabStop = true;
Color = Color.White;
}
#endregion
#region Method Region
public void SetItems(string[] items, int maxWidth)
{
this.items.Clear();
foreach (string s in items)
this.items.Add(s);
maxItemWidth = maxWidth;
}
protected void OnSelectionChanged()
{
if (SelectionChanged != null)
{
SelectionChanged(this, null);
}
}
#endregion
#region Abstract Method Region
public override void Update(GameTime gameTime)
{
}
public override void Draw(SpriteBatch spriteBatch)
{
Vector2 drawTo = position;
if (selectedItem != 0)
spriteBatch.Draw(leftTexture, drawTo, Color.White);
else
spriteBatch.Draw(stopTexture, drawTo, Color.White);
drawTo.X += leftTexture.Width + 5f;
float itemWidth = spriteFont.MeasureString(items[selectedItem]).X;
float offset = (maxItemWidth - itemWidth) / 2;
drawTo.X += offset;
if (hasFocus)
spriteBatch.DrawString(spriteFont, items[selectedItem], drawTo, selectedColor);
else
spriteBatch.DrawString(spriteFont, items[selectedItem], drawTo, Color);
drawTo.X += -1 * offset + maxItemWidth + 5f;
if (selectedItem != items.Count - 1)
spriteBatch.Draw(rightTexture, drawTo, Color.White);
else
spriteBatch.Draw(stopTexture, drawTo, Color.White);
}
public override void HandleInput(PlayerIndex playerIndex)
{
if (items.Count == 0)
return;
if (InputHandler.ButtonReleased(Buttons.LeftThumbstickLeft, playerIndex) ||
InputHandler.ButtonReleased(Buttons.DPadLeft, playerIndex) ||
InputHandler.KeyReleased(Keys.Left))
{
selectedItem--;
if (selectedItem < 0)
selectedItem = 0;
OnSelectionChanged();
}
if (InputHandler.ButtonReleased(Buttons.LeftThumbstickRight, playerIndex) ||
InputHandler.ButtonReleased(Buttons.DPadRight, playerIndex) ||
InputHandler.KeyReleased(Keys.Right))
{
selectedItem++;
if (selectedItem >= items.Count)
selectedItem = items.Count - 1;
OnSelectionChanged();
}
}
#endregion
}
}
这个类有一个SelectionChanged事件,当选择发生变化时将会触发这个事件。

items字段表示可选项的列表,有3个Texture2D对象,分别表示左箭头、右箭头、结束符(向左或向右翻到达尽头),再次感谢Tuckbone为我制作这些图片,selectedColor表示选中项的颜色,maxItemWidth表示所有选项的最大宽度,selectedIndex表示当前选中项在选择器的序号。

SetItems方法将用一个新的选项集合重置当前控件的选项集合,OnSelectionChanged是事件处理函数。

Draw方法绘制控件,控件的左边,如果选中项的序号为0(向左翻到了尽头),则显示结束符,否则显示左箭头;控件的中间,如果当前控件被选中,则按指定的颜色绘制当前选中项文字,否则按默认颜色绘制当前选中项文字;控件的右边,如果当前选中项的序号为总数-1(向右翻到了尽头),则显示结束符,否则显示右箭头。

HandleInput方法处理键盘和游戏手柄输入,当玩家按下左方向键,当前选中项序号-1,判断向左翻动是否到了尽头,然后触发OnSelectionChanged事件,当玩家按下右方向键则相反。

现在我们来添加一个新的screen,右键点击“GameScreens”文件夹,选择“添加”——“新建项”——“类”,名字输入“CharacterGeneratorScreen”。代码如下

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.Controls;

namespace EyesOfTheDragon.GameScreens
{
public class CharacterGeneratorScreen : BaseGameState
{
#region Field Region
LeftRightSelector genderSelector;
LeftRightSelector classSelector;
PictureBox backgroundImage;
string[] genderItems = { "Male", "Female" };
string[] classItems = { "Fighter", "Wizard", "Rogue", "Priest" };
#endregion
#region Property Region
#endregion
#region Constructor Region
public CharacterGeneratorScreen(Game game, GameStateManager stateManager)
: base(game, stateManager)
{
}
#endregion
#region XNA Method Region
public override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
base.LoadContent();
CreateControls();
}
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);
ControlManager.Draw(GameRef.SpriteBatch);
GameRef.SpriteBatch.End();
}
#endregion
#region Method Region
private void CreateControls()
{
Texture2D leftTexture = Game.Content.Load<Texture2D>(@"GUI\leftarrowUp");
Texture2D rightTexture = Game.Content.Load<Texture2D>(@"GUI\rightarrowUp");
Texture2D stopTexture = Game.Content.Load<Texture2D>(@"GUI\StopBar");
backgroundImage = new PictureBox(
Game.Content.Load<Texture2D>(@"Backgrounds\titlescreen"),
GameRef.ScreenRectangle);
ControlManager.Add(backgroundImage);
Label label1 = new Label();
label1.Text = "Who will search for the Eyes of the Dragon?";
label1.Size = label1.SpriteFont.MeasureString(label1.Text);
label1.Position = new Vector2((GameRef.Window.ClientBounds.Width - label1.Size.X) /
2, 150);
ControlManager.Add(label1);
genderSelector = new LeftRightSelector(leftTexture, rightTexture, stopTexture);
genderSelector.SetItems(genderItems, 125);
genderSelector.Position = new Vector2(label1.Position.X, 200);
ControlManager.Add(genderSelector);
classSelector = new LeftRightSelector(leftTexture, rightTexture, stopTexture);
classSelector.SetItems(classItems, 125);
classSelector.Position = new Vector2(label1.Position.X, 250);
ControlManager.Add(classSelector);
LinkLabel linkLabel1 = new LinkLabel();
linkLabel1.Text = "Accept this character.";
linkLabel1.Position = new Vector2(label1.Position.X, 300);
linkLabel1.Selected += new EventHandler(linkLabel1_Selected);
ControlManager.Add(linkLabel1);
ControlManager.NextControl();
}
void linkLabel1_Selected(object sender, EventArgs e)
{
InputHandler.Flush();
StateManager.PopState();
StateManager.PushState(GameRef.GamePlayScreen);
}
#endregion
}
}
接下来把这个screen添加到游戏中,打开Game1.cs,在Game State Region区添加一个CharacterGeneratorScreen对象,并且在构造函数中初始化它,代码如下

public CharacterGeneratorScreen CharacterGeneratorScreen;

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 StartMenuScreen(this, stateManager);
GamePlayScreen = new GamePlayScreen(this, stateManager);
CharacterGeneratorScreen = new CharacterGeneratorScreen(this, stateManager);
stateManager.ChangeState(TitleScreen);
}
打开StartMenuScreen.cs,修改它的menuItem_Selected事件处理函数,在选择开始游戏之后,应该是进入CharacterGeneratorScreen,而不是GamePlayScreen。代码如下

private void menuItem_Selected(object sender, EventArgs e)
{
if (sender == startGame)
{
StateManager.PushState(GameRef.CharacterGeneratorScreen);
}
if (sender == loadGame)
{
StateManager.PushState(GameRef.GamePlayScreen);
}
if (sender == exitGame)
{
GameRef.Exit();
}
}


本课教程就到这里吧,我尽量让每课教程保持一个合理的长度,这样不会让你一下子面对太多内容。

祝你在游戏开发之旅好运。

Jamie McMahon

翻译:阿斌
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  XNA