游戏设计入门——游戏程序框架设计

游戏开发这个世界太广阔了,这篇文章中,我只在程序实现的抽象逻辑上,开一个口子进行一些肤浅的阐述。编程

当我去设计一个游戏,一个玩法,包含规则,游戏对象等等一系列的游戏系统,用纸能够写下来,用嘴能够说出来,可是当我想要用程序去实现这一堆东西的时候,就有些无从下手。多线程

好比咱们你们都会下五子棋,它有一个明确的规则“一人一字交替放置棋子,率先5颗连成一线获胜”,在现实世界中,咱们不用考虑五子棋的硬件配置,拿一张白纸,画上横纵格子,两人分别执笔就能够完成一场五子棋的游戏,或者是使用正规的五子棋盘和棋子。不管用什么玩,要实现“玩”是很简单的。框架

可是在作一个五子棋视频游戏的时候,那就须要把“棋子”“棋盘”这些东西用软件去实现,异步

进一步,做为抽象概念的“游戏规则”“胜负判断”也须要软件去实现,这就须要更多的“用计算机思惟去思考”。编程语言

因而我花了一些时间,凭借有限的本科计算机基础以及一些自我东拼西凑的自学,总结了一下游戏框架的一个通用设计方案。函数

一.随便开个头工具

首先阐述一下大的抽象概念,这里也不用被“抽象”二字吓到了,什么是抽象,就是概括总结出来的结论之类的东西,就像把自行车,飞机,汽车都抽象为“交通工具”同样,这里概括总结一下这些玩意的共性,因而“交通工具”这一个抽象概念就诞生了。oop

视频游戏程序框架,我认为她(she)就是一个循环(Loop)过程性,“开始游戏——杀敌/解密/闯关/…——游戏胜利/游戏失败——开始游戏”,对吧,关键字,循环(Loop)的,过程的。性能

进一步对此概念进行细化,衍生出GameState(游戏状态)和GameController(游戏/规则控制器),至于为何会有这两个概念?我是参考了UE4提供的GameState类和GameMode类,同时也参考了前辈们用Flash写的游戏逻辑,至此我总结为GS和GC两大块,至于更高级的学术阐述,受限于我学识水平目前还作不到。优化

 二.GameState

GameState就是对游戏状态的描述,最基本的两个,GamePlay(开始游戏)GameOver(游戏结束),这里GameOver不能理解成玩家平时看见的GameOver,玩家平时看见的GameOver大多表示游戏失败,而在这里,这个概念只是表示游戏结束,由于不管你游戏胜利仍是游戏失败,游戏都结束了(GameOver)。

在此之上,能够进行扩展,例如如今游戏都会有主菜单,也有暂停,或者有多人模式,游戏设置等等,因而咱们能够在GameState中添加MainMenu,GamePause,MultiPlay,GameOption等等。

使用GameState进行游戏状态的管理有什么用?最重要的就是给你一个清晰的编程实现游戏的思路,或者说给你一个入手点,至于方便管理游戏进程,方便后续游戏程序功能性扩展,下降游戏程序各系统耦合性等等,实在太多了。

至于GameState如何使用?这东西就是用来切换的,做为标识游戏目前状态的一个Flag。

以前在阅读《游戏人工智能编程案例精粹》这本书中,其中详解了FSM(有限状态机)在游戏AI的应用和扩展,以此联想,对于GameState的处理使用FSM岂不是再合适不过了。《lua游戏开发实践指南》中提到“对于Singleton,不管什么状况下,只要它们提供方便就使用它们”,虽然这句话说的太满,不太符合中国人的思惟,也不符合辩证法(笑),但也某种程度上代表Singleton的实用性和普遍性。因此更进一步,使用Singleton(单例模式)的FSM处理GameState,以我来看是极好的。

固然,以上是抽象概念的阐述,最终用到游戏程序设计上,还得按照一些编程语言的语法和特性来实现,这里,我也给出了一份Unity的C#的原型代码,能够看成伪代码吧。

Unity的C#的原型代码: 

publicclassS_GameState : MonoBehaviour {

   publicenumGameState

   {

       GamePlay,

       GamePause,

       GameOver,

       GameReady,

       GameInit

   }

   publicstaticS_GameState Instance;

   privateGameState m_GameState;

   void Awake()

   {

       Instance = this;

   }

   publicGameState GetGameState()

   {

       returnm_GameState;

   }

   publicvoid ToGamePlay()

   {

       m_GameState = GameState.GamePlay;

   }

   publicvoid ToGamePause()

   {

       m_GameState = GameState.GamePause;

   }

   publicvoid ToGameOver()

   {

       m_GameState = GameState.GameOver;

   }

   publicvoid ToGameInit()

   {

       m_GameState = GameState.GameInit;

   }

}

补记:

至于FSM和Singleton,请教谷歌老师是一个很好方法,不过,这里我稍微阐述一些FSM的应用,FSM早些年用于游戏AI的构建,毕竟游戏AI不一样于科研领域的AI,游戏AI不是为了让玩家没法打败而设立的,基本上游戏AI就是一套规律的集合,好比《黑暗之魂3》的第一个BOSS——古达,其中一个规律就是半血以后会变身,变身时候有动画,不会攻击,玩家能够很安逸的砍空一条体力,而后全身而退,这个规律,打几百遍古达都不会变。

回到原来话题,FSM普遍应用于游戏AI的地位如今基本被行为树取代了,而后FSM如今就专职作起了角色动画的管理,好比第三人称玩家角色的各类动画切换,UE4和Unity都使用FSM进行动画状态切换的管理。

 三.GameController

说完了GameState,就该说一下GameController了

GameController就是用来管理游戏规则的了,好比开始游戏了,要生成玩家角色,生成敌人,生成地图等等;玩家按了ESC,要暂停游戏了;玩家通关了,妙极,GameOver;

因此GameController比起GameState要更加具体,基本上GameController就是要处理GameState切换以后一系列工做,依旧是五子棋,好比GameState从MainMenu切换到了GamePlay,那么GameController就要加载一个载入画面,载入结束后,消掉载入画面,同时显示一个棋盘等待。固然,OnLoading也能够做为一个GameState,至于要不要这个OnLoading的GameState,就归到弹性选项里面好了(笑)。

这里就须要一个游戏状态的检测,若是游戏某一时刻切换了状态,那么做为GameController就得作点事情了,因此要快!准!狠!

因而在一个独立线程里面整个一while(true)来不断循环判断是否游戏状态进行了切换

固然GameController也可使用一个Singleton来实现,我认为是不错的,不只能够异步执行,并且很快,充分知足快准狠的须要,并且分离了游戏的渲染线程和逻辑线程,并行优化/劣化好像很不错(笑)——对于通常的小型游戏,多线程可能会杀鸡用牛刀,反而劣化的游戏性能。

不过如今游戏引擎都体统了一个每帧调用的函数,因此将游戏状态检测放在里面也是很好的,如下,提供一个Unity的C#代码,以供参考。

Unity的C#的原型代码:

void Awake()

   {

       Instance = this;

   }

   void Start()

   {

       m_StartWait = newWaitForSeconds(m_StartDelay);

       m_EndWait = newWaitForSeconds(m_EndDelay);

       StartCoroutine(GameStateOperator());

   }

   IEnumeratorGameStateOperator()

   {

       while(true)

       {

            switch(S_GameState.Instance.GetGameState())

            {

                caseS_GameState.GameState.GameInit:

                    GameInit();

                    break;

                caseS_GameState.GameState.GameReady:

                    GameReady();

                    break;

                caseS_GameState.GameState.GamePlay:

                    GamePlay();

                    break;

                caseS_GameState.GameState.GamePause:

                    GamePause();

                    break;

                caseS_GameState.GameState.GameOver:

                    GameOver();

                    break;

            }

            yieldreturnnull;

       }

   }

补记:

这里使用了Unity的伪线程——协程,方便使用多线程进行参考,同时也为了让代码结构清晰一些。

 四.状态切换

GameState提供了游戏状态来切换,GameController提供了状态切换后的工做处理,那么问题来了,什么玩意儿来切换GameState呢?

天然是游戏对象了,GameObejct,玩家角色,Npc,某个子弹,某些触发器,键盘操做等等。回到上面看看GameState的切换函数使用了public,也是这个缘由,反正都是static了,稍微裸一点,我以为颇为不错(笑)。

回到原来话题,好比玩家角色也许有一个HP的属性,当HP==0时,GameOver,调用一下GameState的状态切换函数,将状态切换称GameOver,这时,GameController检测到了GameState切换了,开始作出响应,很完美。

固然GameController也能够用一用状态切换,好比一些相似关卡倒计时计算须要写在GameController里面,当倒计时为0是,游戏结束,这时候就须要GameController调用切换函数了。一样的,对于玩家角色的HP检测放到GameController里面也何尝不可,不过这显然不符合OOP的设计原则,这么明显的增长耦合性,软件工程老师要气死。可是我就是要气死他(笑)。

补记:

对于游戏对象的分析和设计,我以为须要综合OOP思想和设计原则,虽然设计主流游戏类型,大多有原型了,好比UE4就很人性化,提供了各类类型游戏原型,这里UML之类工具使用起来也是极好的。固然不能忘了UI的设计,UI是要契合游戏程序的,有效利用GameState是很好的入口点。下一篇我应该会说说UI设计的东西。