09 游戏画面管理与切换控制

摘要

以 XNA 为基础的游戏程序虽然可以很容易地显示图形和文字供用户检视,并附予各种特殊效果,丰富游戏的内容,以达到吸引游戏用户的最终目标。但是 XNA Framework 不像一般支持应用程序开发的 .NET Framework、.NET Compact Framework、或是 Silverlight Framework,对应用程序编程接口的开发提供完整的支持,XNA Framework 主要的支持在游戏功能的设计,在支持应用程序编程接口方面,例如窗口、对话框、菜单、工具栏、状态栏等和用户沟通的接口部分就需要多投入一点心力,才能建置具功能选单、场景切换、或是允许使用者设定游戏主角、游戏内容、和游戏难度的完整游戏。在这一篇文章中,我们将要介绍以 XNA 为基础的游戏程序的画面开关技巧,以及 XNA Framework 在与使用者沟通方面的支持。

游戏画面管理与开关

和一般的应用程序一样,以 XNA 为基础的游戏程序也需要功能选单供游戏用户选择喜好设定,包括游戏的背景图案、主角人物的图片、对战的对象、或是游戏的难度。每一种设定的设定画面都可能有更进一步的细部设定,造成游戏程序必须协助用户无障碍地在各种设定画面与游戏进行画面之间的切换,不会因为对游戏的使用者造成操作上的困扰。

游戏程序和一般的应用程序的定位不同,游戏程序通常不需要用户输入很多的数据,甚至允许用户不需要执行任何输入的动作就可以进入游戏程序设定的游戏场景,所以在支持画面设计与管理的功能方面较为薄弱,例如支持设计 Windows Phone 7 游戏程序开发的 XNA Framework 不像支持设计一般的 Windows Phone 7 应用程序的 Silverlight Framework 可以很容易地利用 XAML 文件与 PhoneApplicationPage 类别建立和供使用者操作的画面,和使用者进行沟通,或是读取用户设定或输入的数据,并利用 NavigationService 类别提供的 Navigate、GoForward、和 GoBack 等方法进行切换,开发以 XNA 为基础的游戏程序必须投入较多的心力在管理游戏程序的游戏画面、菜单画面、或是设定画面,以提供完整的游戏程序功能供用户使用。

认识 Game State Management 范例

要为以 XNA 为基础的游戏程序加上菜单选单,设定画面,或是场景切换功能,除了自行开发以外,也可以利用发表于 APP HUB 网站的 Game State Management 范例程序 (网址:http://create.msdn.com/en-US/education/catalog/sample/game_state_management),此范例程序提供三种游戏平台的范例,分别是 Windows Phone 7 平台的范例:GSMSample_4_0_PHONE.zip;Windows 平台和 XBOX 游戏机平台的范例:GSMSample_4_0_WIN_XBOX.zip,有兴趣的读者可以自行下载 Game State Management 范例程序提供的原始码,为上述三种平台的游戏程序加入游戏画面管理与切换的功能。如果读者有需要开发网络游戏程序,可以参考发表于 APP HUB 网站的 Network Game State Management 范例程序(网址:http://create.msdn.com/en-US/education/catalog/sample/network_game_state_management)。

[注意]

使用 Game State Management 范例程序提供的原始码必须遵守 Microsoft Permissive License 授权规范,详细的授权规定请参考 Microsoft Permissive License (Ms-PL) 文件的说明。

欲使用 Game State Management 范例程序提供的原始码,请先下载正确的范例版本,解压缩之后使用 Visual Studio 2010 Express 开启扩展名为 .sln 的方案档,您将可以在 [Solution Explorer] 窗口中看到名称为 GameStateManagementSample (Phone) 的游戏程序项目,以及名称为 Content 的 Content Pipeline 项目。

名称为 GameStateManagementSample (Phone) 的游戏程序项目中名称为 ScreenManager 的文件夹中有三个重要的原始程序档案,分别是负责管理游戏画面的 ScreenManager.cs,可以协助处理使用者输入的 InputState.cs,以及做为游戏程序画面基类的 GameScreen.cs。ScreenManager 文件夹底下的原始程序档案的用途可以参考表1的说明:

表1:ScreenManager 文件夹底下的原始程序档案的用途
原始程序文件名 定义的类别名称 用途
ScreenManager.cs ScreenManager 提供管理多个 GameScreen 类别的对象的功能,负责呼叫 GameScreen 类别的对象的 Update 方法更新画面的状态,呼叫 GameScreen 类别的对象的 Draw 方法更新画面显示的内容,以及将使用者的输入的动作转交给目前显示的 GameScreen 类别的对象。
InputState.cs InputState 负责处理用户透过键盘、游戏控制器、和触控面板的输入操作。
GameScreen.cs GameScreen 代表一个游戏画面,包括游戏的主菜单、设定菜单、和游戏的主画面,都是一个 GameScreen 类别的对象。

[说明]

ScreenManager 类别继承自 XNA Framework 内建的 DrawableGameComponent 类别。XNA Framework 内建的 DrawableGameComponent 类别和 GameComponent 类别都是支持模块化游戏设计的基类,两者皆支持 Update 方法,以执行更新游戏状态的动作,DrawableGameComponent 另外支持 LoadContent、UnloadContent、以及 Draw 方法,做为加载游戏资源、释放资源、以及绘制游戏内容之用。以 XNA 为基础的游戏程序可以将游戏的人物和模块制作成继承自 DrawableGameComponent 类别或 GameComponent 类别的衍生类别,将更新游戏状态、加载/释放资源、与绘制游戏内容的工作封装在类别中,使游戏程序具备更优良的结构。

[提示]

每一个继承自 GameScreen 类别的衍生类别可以经由覆写 (override) LoadContent 方法加载画面需要用到的资源,覆写 UnloadContent 方法执行释放资源的动作,覆写 Update 方法以执行更新画面状态的动作,覆写 HandleInput 方法以处理使用者的输入操作,覆写 Draw 方法以显示画面的内容。除此之外,GameScreen 类别另外提供允许衍生类别覆写的 Serialize 方法和 Deserialize 方法,执行储存画面状态,或是读回之前储存的画面状态的动作。如果有需要控制画面转场的效果,可以设定 GameScreen 类别的 TransitionOnTime 属性和 TransitionOffTime 属性,将 TransitionOnTime 属性和 TransitionOffTime 属性设定成 0 代表画面切换不需要转场效果。如果画面要以突现的方式盖在目前的画面之上,可以将 GameScreen 类别的 IsPopup 属性设定成 true。

除了名称为 ScreenManager 的文件夹以外,名称为 GameStateManagementSample (Phone) 的游戏程序项目中还有一个名称为 Screens 的文件夹,位于此文件夹底下的是 Game State Management 范例程序提供的现成游戏程序画面,您可以直接使用 GameStateManagementSample (Phone) 的游戏程序项目提供的游戏画面,或是自行开发继承自 GameScreen.cs 定义的 GameScreen 类别的衍生类别,定义所开发的游戏程序需要的画面。

Screens 文件夹底下的原始程序档案的用途可以参考表2 的说明:

表2:Screens 文件夹底下的原始程序档案的用途
原始程序文件名 定义的类别名称 用途
BackgroundScreen.cs BackgroundScreen 做为游戏背景的画面。
GameplayScreen.cs GameplayScreen 游戏的执行画面。
LoadingScreen.cs LoadingScreen 显示加载中,请用户稍候的讯息的画面。
MainMenuScreen.cs MainMenuScreen 主菜单选单画面。
MenuEntry.cs MenuEntry 代表菜单中的功能选项的类别。
MenuScreen.cs MenuScreen 所有的菜单画面的基类。
MessageBoxScreen.cs MessageBoxScreen 显示讯息供用户检视的画面。
OptionsMenuScreen.cs OptionsMenuScreen 提供设定画面供使用者进行喜好设定的画面。
PlayerIndexEventArgs.cs PlayerIndexEventArgs 菜单被用户选中时引发的Selected事件伴随的事件参数。

[提示]

请注意 ScreenManager 文件夹和 Screens 文件夹中的某些类别需要使用到 Content Pipeline 项目中的游戏资源,也就是您必须在 Content Pipeline 项目中准备好必要的游戏资源,否则光有类别的原始码还是无法制作出游戏程序需要使用的游戏画面。

需要使用到资源的源代码档案包括负责管理游戏画面的 ScreenManager.c 会用到 Content Pipeline 项目中名称为 blank 的图片和 menufont 字型定义文件;负责显示讯息窗口和用户沟通的 MessageBoxScreen.cs 会用到 Content Pipeline 专案中名称为 gradient 的图片;负责扮演游戏主窗口的 GameplayScreen.cs 会用到 Content Pipeline 项目中名称为 gamefont 字型定义文件,而当做背景窗口的 BackgroundScreen.cs 则需要用到 Content Pipeline 项目中名称为 background 的图片。请注意如果游戏程序需要改变上述置于 Content Pipeline 项目的游戏资源的名称,必须一并修改使用到这些资源的源代码,否则所开发的游戏程序将无法执行。

使用 Game State Management 范例提供的原始码管理游戏程序的画面

了解 Game State Management 范例提供的原始程序档案的功能和用途之后,我们就可以利用范例制作好的类别来开发具备菜单与画面切换功能的游戏程序了。

首先请启动 Visual Studio 2010 Express for Windows Phone,建立一个 [Windows Phone Game(4.0)] 型态的项目,然后将 Game State Management 范例的游戏程序项目中的 ScreenManager 文件夹和 Screens 文件夹中的所有档案加入到所建立的游戏程序项目中,将 Game State Management 范例的 Content Pipeline 项目中的 background.png、blank.png、gradient.png、gamefont.spritefont、和menufont.spritefont 加入到所建立的游戏程序项目附属的 Content Pipeline 项目中。

做好之后请编辑 Game1 类别,于原始程序档案的最前面引入以下的名称空间:

using GameStateManagement;
然后于 Game1 类别中宣告以下的变量,负责管理游戏程序需要使用的所有画面:
ScreenManager screenManager;				//管理遊戲畫面的 ScreenManager 類別的物件
再把 Game1 类别的建构函式编辑成以下的样子,负责设定游戏窗口的宽度和高度,建立负责管理游戏画面的 ScreenManager 类别的对象:

public Game1()
{
graphics = new GraphicsDeviceManager(this);
    Content.RootDirectory = "Content";
graphics.PreferredBackBufferWidth = 480;				//設定遊戲視窗的寬度為 480
    graphics.PreferredBackBufferHeight = 800;				//設定遊戲視窗的高度為 800
    screenManager = new ScreenManager(this);			  //建立 ScreenManager 類別的物件
Components.Add(screenManager);		//將 ScreenManager 類別的物件加入到 Components 集合
if (!screenManager.DeserializeState())	       //如果沒有前一次執行儲存的畫面狀態
    {
        screenManager.AddScreen(new BackgroundScreen(), 
null);				//建立遊戲背景畫面,並交給 ScreenManager 管理
        screenManager.AddScreen(new MainMenuScreen(), 
null);				//建立主功能表畫面,並交給 ScreenManager 管理
    }
    TargetElapsedTime = TimeSpan.FromTicks(333333);
}

请注意,游戏程序执行时需要用到的所有画面都必须交给 ScreenManager 管理。

[提示]

因为 ScreenManager 类别继承自 DrawableGameComponent 类别,当 DrawableGameComponent 类别的衍生类别的对象加入到 Game1 类别的 Components 集合之后,每次 Game1 类别的 LoadContent 方法、Update 方法、和 Draw 方法被呼叫的时候,DrawableGameComponent 类别的衍生类别的对象的 LoadContent 方法、Update 方法、和 Draw 方法也会被呼叫,让 DrawableGameComponent 类别的衍生类别的对象能够加载游戏资源,更新状态,并绘制对象的内容。

编辑妥 Game1 类别的建构函式之后,请覆写 OnExiting 方法,在游戏程序结束执行时将画面的状态储存下来,以便下一次执行游戏程序的时候还原到上一次结束执行时的画面。请为 Game1 类别加入以下的 OnExiting 方法:

protected override void OnExiting(object sender, EventArgs args)
{
    screenManager.SerializeState();	//呼叫 screenManager 的 SerializeState 方法儲存遊戲畫面
    base.OnExiting(sender, args);
}
最后我们必须编辑 Game1 类别的 Update 方法中,将判断使用者是否按下 Windows Phone 7 智能型手机左下方的 Back 硬件按键的程序代码批注掉,因为加入画面控制功能的游戏程序在用户按下智能型手机左下方的 Back 硬件按键时,如果有上一个游戏画面,则必须回到上一个游戏画面,而不是结束游戏程序的执行,编辑妥的 Update 方法如下:

protected override void Update(GameTime gameTime)
{
    //if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
    //    this.Exit();
    base.Update(gameTime);
}

做好之后请执行游戏程序项目,您将会看到游戏程序提供的主菜单,如图1 所示:

图1:游戏程序提供的主菜单

按下画面中的 [Options] 功能,您就会看到游戏程序的设定画面,点选设定画面中的菜单,可以看到仿真设定值改变的效果,如图2 所示:

图2:游戏程序的设定画面

按下 Windows Phone 7 智能型手机左下方的 Back 硬件按键回到图1的画面,再点选 [Play Game] 功能,您就会看到一个简单的游戏执行的情形,如图3 所示:

图3:简单的游戏执行的情形

按下 Windows Phone 7 智能型手机左下方的 Back 硬件按键可以回到主菜单,再按一次可以结束游戏程序的执行。

[Game State Management 范例使用要诀]

因为 Game State Management 范例提供的原始程序档案中,当做所有游戏画面基类的 GameScreen 类别内容储存/读回游戏画面状态的功能,所以在游戏画面管理和切换的功能尚未制作完善之前,先将制作好的游戏程序部署至 Windows Phone 7 Emulator (仿真器) 执行,如果功能不正确,则将仿真器关闭,丢弃储存的游戏画面状态,待程序修改妥后,再将修改后的程序重新部署到仿真器执行。

您可以视需要修改 MainMenuScreen.cs 的程序代码,提供不同的菜单供用户操作,不要忘了请一并编辑 Content Pipeline 项目中的 menufont.spritefont 字型定义文件,定义菜单需要显示的文字。如果需要为所开发的游戏程序提供中文菜单,请参考 [图形特效与文字显示] 一文的说明,于 Content Pipeline 项目中的 menufont.spritefont 字型定义文件定义好欲显示的中文字和字型规格。

欲修改游戏程序的主菜单,请编辑 MainMenuScreen.cs 源文件的 MainMenuScreen 类别的建构函式中建立 MenuEntry 类别的对象的语法,如下:

public MainMenuScreen() : base("Main Menu")
{
    MenuEntry playGameMenuEntry = new MenuEntry("Play Game");
    MenuEntry optionsMenuEntry = new MenuEntry("Options");
    playGameMenuEntry.Selected += PlayGameMenuEntrySelected;
    optionsMenuEntry.Selected += OptionsMenuEntrySelected;
    MenuEntries.Add(playGameMenuEntry);
    MenuEntries.Add(optionsMenuEntry);
}
当然,修改建立 MenuEntry 类别的对象的语法必须一并修改 MenuEntry 类别的 Selected 事件的事件处理程序,如下:
void PlayGameMenuEntrySelected(object sender, PlayerIndexEventArgs e)
{
     LoadingScreen.Load(ScreenManager, true, e.PlayerIndex, new GameplayScreen());
}
void OptionsMenuEntrySelected(object sender, PlayerIndexEventArgs e)
{
    ScreenManager.AddScreen(new OptionsMenuScreen(), e.PlayerIndex);
}
请注意 [Options] 菜单的 Selected 事件的事件处理程序会直接显示 OptionsMenuScreen 类别定义的内容,而 [Play Game] 菜单的 Selected 事件的事件处理程序则会先显示 LoadingScreen 类别定义的内容,让使用者先看到 [Loading…] 的文字,然后才看到 GameplayScreen 类别定义的内容。

以 GameplayScreen 类别为例,其建构函式就有设定 TransitionOnTime 属性和 TransitionOffTime 属性,表示切换到 GameplayScreen 画面和切换离开 GameplayScreen 画面都要显示转场效果。GameplayScreen 类别的建构函式如下:

public GameplayScreen()
{
    TransitionOnTime = TimeSpan.FromSeconds(1.5);
    TransitionOffTime = TimeSpan.FromSeconds(0.5);
}

最后我们只要将游戏的功能制作在扮演游戏主画面的 GameplayScreen.cs 档案中,或置换掉 GameplayScreen.cs 档案的内容,就可以完成提供主菜单和游戏设定画面的游戏程序了。

利用 Guide 类别与游戏使用者沟通

以 XNA 为基础的游戏程序除了可以利用主菜单和设定画面与用户沟通之外,也可以利用 Guide 类别提供的功能和用户沟通,包括显示讯息画面供用户检视和显示输入画面协助用户输入资料等常用的用户接口。

欲利用 Guide 类别提供协助用户输入数据的操作画面并显示讯息画面,请先于原始程序档案的最前面引入以下的名称空间:

using Microsoft.Xna.Framework.GamerServices;
using System;
using System.Collections.Generic;
然后于类别中宣告以下的变量
string typedText;								//存放使用者輸入的資料的變數

需要显示协助用户输入数据的操作画面的时候,只要透过下列的程序代码,就可以利用 Guide 类别的 BeginShowKeyboardInput 方法显示供用户输入数据的画面:

Guide.BeginShowKeyboardInput(PlayerIndex.One,
                        "Here's your Keyboard", "Type something...",
                        ((typedText == null) ? "" : typedText),
                        GetTypedChars, null);			//顯示供使用者輸入資料的畫面
当使用者完成输入并按下输入画面中的 [OK] 键时,就会执行到名称为 GetTypedChars 的方法,由 GetTypedChars 方法呼叫 Guide 类别的 EndShowKeyboardInput 方法取得使用者输入的内容,做法如下:
protected void GetTypedChars(IAsyncResult r)
{
    typedText = Guide.EndShowKeyboardInput(r);			//取得使用者輸入的內容
}

做好之后请执行游戏程序,执行显示协助用户输入数据的功能,您就会看到如图4 所示的画面:

图4:协助用户输入数据的画面

如果游戏程序需要显示讯息和用户沟通,要求使用者做决策,就可以利用 Guide 类别的 BeginShowMessageBox 方法显示讯息画面供用户做决策。例如以下就是 Guide 类别的 BeginShowMessageBox 方法的使用技巧:

string msg = "Quit Game?";            					//準備供使用者檢視的訊息
List<string> MBButtons = new List<string>();			//準備供使用者選擇的按鍵的集合
MBButtons.Add("Yes");								//加入 Yes 鍵到MBButtons集合
MBButtons.Add("No");									//加入 No 鍵到MBButtons集合
Guide.BeginShowMessageBox("Game Over", msg, MBButtons, 0,
                    MessageBoxIcon.Alert, GetMBResult, null);//顯示訊息畫面和使用者溝通
当用户按下讯息画面中的按键时会呼叫到名称为 GetMBResult 的方法,由 GetMBResult 方法判断用户的按键选择。以下的 GetMBResult 方法会呼叫 Guide 类别的 EndShowMessageBox 方法取得用户的按键状态:
protected void GetMBResult(IAsyncResult r)
{
    int? b = Guide.EndShowMessageBox(r);					//取得使用者的按鍵狀態
    if (b == 0)										//使用者按下第一個按鍵
    {
        //user click Yes
    }
    else											//使用者按下第二個按鍵
    {
        //user click No
    }
}

请注意呼叫 Guide 类别的 EndShowMessageBox 方法取得的结果是一个整数,其内容值为 0 代表用户按下第一个按键,其内容值为 1 代表用户按下第二个按键,其内容值为 2 代表用户按下第三个按键,以此类推。

做好之后请启动游戏程序,执行显示讯息和用户沟通的功能,您就会看到图5 的画面:

图5:利用 Guide 类别显示讯息和用户沟通的画面

[范例下载]

XNAGameWithMenu.zip







  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值