2024年3月10日发(作者:)

利用有限状态栅重构XNA游对 

广g,i1大学华软软件学院刘生建袁冠远 

[摘要]在wind0ws系统上开发游戏一般要求开发者不仅要掌握c++语言、Windows SDK,还要了解DirectX、人工智能技术等,这 

往往造成较高的游戏开发门槛。随着微软xNA框架的推出,越来越多的开发者可以快速推出自己的游戏作品,但是正因为这个框 

架很容易上手,也导致了很多游戏初学者虽然实现了游戏的功能,但是代码的组织较为混乱。本文从实际的教学经验中总结了如何 

利用有限状态机原理重构XNA游戏的一些思路。 

[关键词]游戏XNA重构 有限状态机(FSM) 

1.传统的游戏编程思想 

c}}做传统的桌面商业应用程序一般采用事件驱动的方法,代码比 

较清晰。而做过游戏编程的人都知道,在游戏编程中因为效率原因一 

般不直接采用事件驱动的开发方法,而采用循环查询为主的处理方法, 

现状态的处理和迁移。 

3.简单的XNA状态机实现 

借助c#强大的语言表达能力,我们可以轻松的实现游戏或者精灵 

的状态控制。为了今后更好的复用该设计模式,我们可利用c#的泛型 

程序主体伪代码如下: 

while(没有主动退出&&没有失败)f 

Update(time);//更新系统状态 

Draw(time);//根据状态刷新屏幕 

) 

初学者的Update代码往往包含了游戏的所有逻辑处理,我们简化 

示意如下: 

void update(DateTime delta)( 

输人检查; //根据玩家操作改变角色的位置等 

人T智能处理;//根据时间改变怪物精灵的位置、速度、魔法值、 

能量值等 

switch(游戏状态)f 

case选关: 

If(确认)state=运行; 

break; 

ease运行: 

If(按下暂停键)state=暂停; 

Iff超时)stare=失败: 

break; 

case暂停: 

If(按下恢复键)state=运行; 

break; 

case失败: 

If(继续)state=选关; 

else退 : 

break; 

】 

) 

Draw方法与Update比较对应,本例子中也是根据状态画出不同的 

屏幕,比如选关状态画 游戏的可选关卡及操作方法提示,而运行中状 

态则画出游戏背景及宝藏、游戏中玩家控制的角色精灵(here)及若干非 

玩家控制的怪物精灵(NPCs),这个例子中未展开输入检查及人工智能 

处理的代码,可以预见也是很多个判断分支组成的代码。随着游戏逻 

辑的不断增加,这样的代码就会迅速变得十分臃肿,难以阅读维护。 

2.利用有限状态机的思想来改进代码 

在日常生活中有很多事物都只有有限的几种状态,比如家里的电 

灯,大楼里的电梯等,电灯有一个开关按钮可以改变其状态,电灯的状 

态可以通过图1的示意图来直观展示。同样在游戏中,也可以使用类 

似的状态迁移图来表示游戏的状态变化及玩家角色的状态变化,再根 

据状态图完成相应的编码。 

图l电灯的状态迁移图 

种最简单的有限状态机包含FSM类来代表有限状态机、FSMState 

代表状态类,开发者可以继承出各种具体状态类,在状态类中实现数据 

封装及相应的条件跳转来切换到新的状态 。运行时先创建一个FSM 

实例并设置它的 前状态为初始状态,之后就在游戏循环中不断调用 

FSM的update方法,而该方法最终调用当前状态的Update方法,从而实 

————

286--—— 

表示,首先设计一个所有的状态类State 

public class State<T>{//T类型的状态 

protected SpriteFont m font;,/用该字体往屏幕上绘制英文文字 

protected KeyboardState m

_

keyboardState;//用该状态查询玩家 

的按键 

public virtual Void Enter(T owner){//进入此状态时被调用 

) 

,/帧处理函数,owner代表状态的主体 

public vitrual void Execute(T owner,GameTime gameTime)( 

j 

//帧绘制函数,owner代表状态的主体 

public virtual void Draw(T owner,GameTime gameTime){ 

) 

public virtual void Exit(T owner){//离开此状态时被调用 

1 

} 

以上的状态祖先类十分简单,实际使用时要创建相应的派生状态 

类才可使用。通常游戏本身是有状态的,大部分精灵也是有状态的。 

尤其是人丁智能控制的NPC,利用状态来控制会让代码变得比较清 

晰。下面就以游戏的状态来实例,本例子中我们设定一个状态是选荚, 

另一个状态是运行游戏,相应的状态类如下所示: 

public class Menu:sta <MyGame>{//选关的状态 

public override void Enter(MyGame owner)( 

if(m_font==nul1)//此处加载字体只是在屏幕上绘制调试信 

息 

nl

font=owner.Con[ent.Load<Spritef’0nt>f@”fonts\score”1; 

Console.WriteLine(”Enter Menu”); 

} 

public override void Exit(MyGame owner) { 

Console.WriteLine(”Exit Menu”); 

) 

public override void Execute(MyGame owner,Game 1’hne game- 

Time)( 

keyboardState=Keyboard.GetState0;//获取键盘状态 

汀(m—keyboardState.IsKeyDown(Keys.Up)){// ̄v E箭头 

owner.Level=owner.Level一1;,/关卡减1 

) 

if(m—keyboardState.IsK yD0wn(K ys.Down))( 

owner.1 evel=owner.Level+1 ill关卡增1 

} 

if(m_keyboardState.IsKeyD0wn(Keys.Enter))( 

owner.GameState:new PIay0;,,按下回车进入运行状态 

) 

public override void Draw(MyGame owner,GameTime game Fime) 

{ 

string msg String.Format(”Current Level:{O}”,owner.Leve1); 

owner.SpriteBatch.DrawString(m font,msg,new Vector2(10, 

101 co1or.Gnldenrod);//绘制当前关卡信息 

,/绘制操作提示 

owner.SpriteBatch.DrawString(m font,”change level(UplDown) 

new Vector2(10,lOO),Color.Azure); 

owner.SpriteBateh.DrawStirng(m_font ”OK(Emer)”,new Vec- 

tor2(10,1 40),Color.BlueViolet); 

1 (下转第288页) 

议 

2.2 2安全认证服务器 

安全认证服务器运行在网络环境下,集中控制所有用户对网络的 

访问,同时提供认证、授权和审计服务。 

使用者在进行身份认证时,仅需要输入用户名和由电子令牌产生 

的“动态口令”。通过安全认证代理强制执行安全口令策略机制,将认 

汪信息送安全认证服务器端调用同步信任认证算法模块对“动态口令” 

进行认证,保证认证过程的完成。 

2.23安全认证代理 

◆采用双因素(静态口令及动态口令双因素)身份认证技术和一次 

性认证原则,保证一次一密。 

◆可支持TACACS和RADIUS远程拨号访问认证协议,允许用户进 

行远程拨号访问。 

◆用户的重要信息(如口令)均以变换形式在存储设备中存储或存 

信道中传输。 

◆客户端提供认证API开发接口,包括C、VC、VB、F(.xP“,、POW— 

ERBUILDER等各种软件开发接口。可以非常方便地嵌入原应 系统, 

无需添加额外的访问设备。 

安全认证代理是安全认证服务器的客户端,是企业网络中任何需 

要受保护的认证资源。安全认证代理在系统中就像一个“安全哨兵”。 

更特别的是:对Web来说,一个安全认证代理是用来保护Web服务器的 

安全软件,并且被TCP/IP网络连接到运行着的安全认证服务器上,这就 

为Web服务器提供了身份认证服务。T安全认证代理是动态口令Web 

的职能关键之处,因为安全认证代理直接被安装在Web Server层上,并 

且强制执行安全策略。 

当用户试图进入被安全认证代理保护的资源时,用户马上被要求 

输入其有效的身份证明,即PIN码和从动态口令卡中产生的动态口 

令。这些数据通过SSL传送到安全认证服务器上,在那里验证输入的 

PIN和动态口令是否有效。被授权的林果动态口令用户很容易就可进 

入,而未被授权的人则被拒绝进入受保护的Web服务器。 

安全认汪代理保护Web Server所选定的页面和目录。在Web 

Server的目录和文件启动代理软件后,所有试图访问这 被保护的Web 

页而的用户,需f}{示动态口令令牌码。只有这些Server数据库巾注册 

了的用户才能访问受林果动态口令保护的页面. 冈此,既可以把网站 

作为公 资源提供给所有用户,也可以把它作为高机密网站来给可信 

任刖户发送保密信息。 

安伞认证代婵对如下Web平台提供林果动态l_=I令保护: 

一安全认证代理for Windows N F/2000 

保护llS虚拟服务器、路径和文件;Outlook Web Access;Mieroso|} 

Silt Server和S Server Commeree Edition;Microsoft Proxy Selwerl l

■安全认证代理[or Lotus Dota1.1() 

},I I,oIllS数据库(地址簿、LI历、邮件等)、I RL路径和安装存 

Wind+,w—NT 台上的Domino Web服务器 的文件 

■安伞认证代婵fbr Netseape/iPlanet Well Servers 

俅护Well服务器根目录或在Windows NT或UNIX半 (Solaris、 

HP一1 JX和AIX)l 的登录认证。 

安全认证代理町快捷简便地布置安全服务,而不需要 用户的桌 

嘶交 。存用户获准访问机密Web资源之前,必须确定用户的身份,强 

制实施他们制定的安全策略,既可以把网站作为公共资源提供给所有 

用户,也可以把它作为高机密网站来给可信任用户发送保密信息。 

23动态口令双因素安全认证系统的特点 

◆开放式体系,系统支持WINDOWS NT、NETWARE、UNIX、LINUX 

等网络系统平台。 

◆用户数据和动态密码种子受加密保护。 

(上接第286页) 1 

相信读者不难仿照上面写出自己的运行状态的示意代码了,关键 

是在帧处理函数和帧绘制函数应实现游戏本身的需求。下面我们看看 

游戏类主要的代码: 

public class MyGame:Microsoft.Xna.Framework.Game{ 

State<MyGame>m

◆支持IIS和APACHE等www服务器,可控制网页的特殊访问。 

◆提供ASP调用接口,可轻易实现与WEB服务器的无缝集成。 

◆由于令牌是脱机使用的,客户端的应用环境并不局限于计算机 

系统,对电话委托系统,甚至是ATM、POS等都可以使用令牌。 

◆单向、简捷的认证过程,能够有效防止非授权用户的访问 

◆集中式的网络认证和管理,完整的日志功能,便于审汁追踪。 

◆抗反向工程,自我保护。 

◆可选的热备份认证服务器,确保系统可靠性。 

2.4应用程序接口 

提供多种应用系统开发接口: 

◆C接口、VB接口、FoxPro接口、DELPHI接口、PB接口 

◆CGI接口 

 ̄ASP接口 

 ̄JAVA接口 

2.5令牌物理特性 

◆Tl桴塑料外壳 

◆电子令牌小巧便捷,使用方便 

◆加强型电子令牌有按键选择,可提供PIN码输入 

◆不使用时自动进入省电状态(指卜式令忡) 

◆超低功耗,节能环侏 

2.6动态口令舣冈素安令认证系统的发装 

动态口令双因素安伞认证系统安装时除r添加必嘤的设 ( 奠 

伞认证服务器、安仝认证代理、令牌等,安全认旺服务 要十立人客 

原仃的网络内,安令认证代卵足需要侏护的网络资源是系统一{1已经 

存的应 )外,只需对原应用系统的I 1々认汪部分稍作改动,就能 

动态口令系统的无缝嵌入,I,GE_r DYNAPASS/SERVER提供多种认证接 

口,包括C、VC、VB、FOXPRO、POWERBUII 13ER等,以适应不同刖, 的 

需要。对于互联网的应用,LGE rDYNAPASS/SERVER提供ASP渊用拔 

口、摔件模块,实现与现有WEB服务器的无缝集成。 

参考文献 

[1]高林计算机网络技术人民邮电出版社 

[2]徐俊明组合网络理论科学出版社 

[3]段水福.无线局域网(WLAN)设计与实现.浙江大学出版社 

创建初始状态: 

protected override void LoadContent(){ 

spriteBatch=new SpriteBatch(GraphicsDevice) 

this.GameState=new Menu0; 

} 

在帧处理函数中调用游戏状态类的相应函数: 

state;//状态 

int m

level;//关卡 

if(m—sta/e!=nul1)m—state.Execute(this,gameTime); 

在帧绘制函数中也相应调用游戏状态类的相应函数: 

protected override void Draw(GameTim gameTime){ 

spriteBatch.Begin0; 

GraphicsDevice.Clear(Color.CornflowerBlue); 

level=l; 

if(Ill—state!=nul1)nl—state.Draw(this,gameTime); 

} 

public State<MyGame>GameStme{ 

get{return m—state;} 

set( 

if(m—state!=nul1)m_state.Exit(this); 

base.Draw(gameTime); 

spriteBatch.Endf1: 

) 

4.小结 

state value; 

if(m_state!=nul1)m_state.Enter(this); 

} 

) 

通过有限状态机我们可以实现游戏处理逻辑的模块化处理,提高 

了灵活性与扩展性,增加了代码的可维护性,本文通过简单的例子示范 

了如何利用有限状态机来重构现有的XNA游戏代码,希望对游戏开发 

初学者起到抛砖引玉的作用。 

参考文献 

通过GameState属性的设置,我们实现了旧状态的离开与新状态的 

进入处理,增加了程序的灵活性,比如写日志或者发出提示音等。也免 

去了传统的状态机类使用。为了使状态类能正常工作,我们需要首先 

--——

[1](美)Mat Buckland著.<(Programming Game AI by Exa1nple} 

Wordware Publishing,Inc,2005:43—77 

288--——