XNA之RPG游戏开发教程之三
本节在上一节基础上继续完善该游戏引擎,主要完成以下任务:
(1)完善StartMenuScreen,同时添加一个GamePlayScreen页面
(2)创建一个新的控件,picture box
(3)为ControlManager类添加新的事件处理
首先是给ControlManager类添加新的事件处理,FocusChanged事件;因为要通过LinkLabel实现页面间跳转,控件的聚焦变化后触发该事件,ControlManager类代码修改如下:
#region Event Region public event EventHandler FocusChanged;//聚焦更改事件 #endregion 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) {
//代码增添部分,当LinkLabel控件聚焦发生改变,触发事件 if (FocusChanged != null) FocusChanged(this[selectedControl], null); 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) { if (FocusChanged != null) FocusChanged(this[selectedControl], null); break; } } while (currentControl != selectedControl); this[selectedControl].HasFocus = true; }
添加一个新的游戏页面GamePlayScreen,代码跟上一节的StartMenuScreen的代码相似,只是对BaseGameState的简单继承
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 GamePlayScreen : BaseGameState { #region Field Region #endregion #region Property Region #endregion #region Constructor Region public GamePlayScreen(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) { base.Draw(gameTime); } #endregion #region Abstract Method Region #endregion } }
将该页面添加到Game1.cs中
public GamePlayScreen GamePlayScreen;//定义一个类级变量 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);//在类中添加对象 stateManager.ChangeState(TitleScreen); }
第二件事就是创建一个新的控件:picture box,跟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 PictureBox : Control { #region Field Region Texture2D image;//控件中加载的图片 Rectangle sourceRect;//图片的长度矩形 Rectangle destRect;//图片在窗体上呈现的矩形 #endregion #region Property Region public Texture2D Image { get { return image; } set { image = value; } } public Rectangle SourceRectangle { get { return sourceRect; } set { sourceRect = value; } } public Rectangle DestinationRectangle { get { return destRect; } set { destRect = value; } } #endregion #region Constructors构造函数的重载 public PictureBox(Texture2D image, Rectangle destination) { Image = image; DestinationRectangle = destination; SourceRectangle = new Rectangle(0, 0, image.Width, image.Height);//原图片大小 Color = Color.White; } public PictureBox(Texture2D image, Rectangle destination, Rectangle source) { Image = image; DestinationRectangle = destination; SourceRectangle = source; Color = Color.White; } #endregion #region Abstract Method Region//来自于继承类的方法重载 public override void Update(GameTime gameTime) { } public override void Draw(SpriteBatch spriteBatch) { spriteBatch.Draw(image, destRect, sourceRect, Color); } public override void HandleInput(PlayerIndex playerIndex) { } #endregion #region Picture Box Methods//为新的图片框设定位置 public void SetPosition(Vector2 newPosition) { destRect = new Rectangle( (int)newPosition.X, (int)newPosition.Y, sourceRect.Width, sourceRect.Height); } #endregion } }
PictureBox控件需要加载图片,在EyesOfTheDragonContent目录下添加一个新的文件夹GUI,将leftarrowUp.png,rightarrowUp.png,StopBar.png三幅图片加入以便用于图片控件的调用
接下来就是最后一个任务,将PictureBox控件添加到StartMenuGreen.cs中来完善该页面,具体代码如下
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 Microsoft.Xna.Framework.Content; using XRpgLibrary; using XRpgLibrary.Controls; namespace EyesOfTheDragon.GameScreens { public class StartMenuScreen : BaseGameState { #region Field region PictureBox backgroundImage;//页面中的背景图片 PictureBox arrowImage;//页面中的箭头图标 LinkLabel startGame;//三个选项,开始游戏,登陆游戏,结束游戏 LinkLabel loadGame; LinkLabel exitGame; float maxItemWidth = 0f;//用来控制箭头图标显示位置 #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();//要先调用基类的登陆函数,这样就实例化了ControlManager对象 ContentManager Content = Game.Content; //
backgroundImage = new PictureBox( Content.Load<Texture2D>(@"Backgrounds\titlescreen"), GameRef.ScreenRectangle);//实例化背景图片框并加入到控件管理对象中 ControlManager.Add(backgroundImage); Texture2D arrowTexture = Content.Load<Texture2D>(@"GUI\leftarrowUp"); arrowImage = new PictureBox( arrowTexture, new Rectangle( 0, 0, arrowTexture.Width, arrowTexture.Height)); ControlManager.Add(arrowImage);//实例化箭头图片框并加入到控件管理对象中 startGame = new LinkLabel(); startGame.Text = "The story begins"; startGame.Size = startGame.SpriteFont.MeasureString(startGame.Text); startGame.Selected +=new EventHandler(menuItem_Selected); ControlManager.Add(startGame); loadGame = new LinkLabel(); loadGame.Text = "The story continues"; loadGame.Size = loadGame.SpriteFont.MeasureString(loadGame.Text); loadGame.Selected += menuItem_Selected; ControlManager.Add(loadGame); exitGame = new LinkLabel(); exitGame.Text = "The story ends"; exitGame.Size = exitGame.SpriteFont.MeasureString(exitGame.Text); exitGame.Selected += menuItem_Selected; ControlManager.Add(exitGame);//在控件管理类中添加三个选择按键 ControlManager.NextControl(); ControlManager.FocusChanged += new EventHandler(ControlManager_FocusChanged);//订阅焦点改变事件 Vector2 position = new Vector2(350, 500);//定义选择按键的起始位置
//遍历控件管理类中的所有控件 foreach (Control c in ControlManager) { if (c is LinkLabel) {
//如果是LinkLabel控件,就在起始位置上向下排列放置 if (c.Size.X > maxItemWidth) maxItemWidth = c.Size.X; c.Position = position; position.Y += c.Size.Y + 5f; } } ControlManager_FocusChanged(startGame, null);//触发事件,起始状态为箭头出现在startGame按键旁 } void ControlManager_FocusChanged(object sender, EventArgs e)//聚焦改变事件,为箭头标记重绘显示位置 { Control control = sender as Control; Vector2 position = new Vector2(control.Position.X + maxItemWidth + 10f, control.Position.Y); arrowImage.SetPosition(position); } private void menuItem_Selected(object sender, EventArgs e) {
//按键选中事件触发,如果选中startGame或者loadGame按键,跳转到GamePlayScreen页面 if (sender == startGame) { StateManager.PushState(GameRef.GamePlayScreen); } if (sender == loadGame) { StateManager.PushState(GameRef.GamePlayScreen); }
//如果选中的是exitGame按键,跳出游戏 if (sender == exitGame) { GameRef.Exit(); } } public override void Update(GameTime gameTime) { ControlManager.Update(gameTime, playerIndexInControl); base.Update(gameTime); } public override void Draw(GameTime gameTime) { GameRef.SpriteBatch.Begin(); base.Draw(gameTime); ControlManager.Draw(GameRef.SpriteBatch); GameRef.SpriteBatch.End(); } #endregion #region Game State Method Region #endregion } }
OK,今天任务结束