- 注册时间
- 2005-7-1
- 最后登录
- 2018-4-24
版主
自定义头衔
- 积分
- 402
|
为状态写代码
(前言:不是什么新东西,不过我自己还没有听到过类似的概念,所以就自己先来个写写)
游戏好比一个具有状态的机器(不要理解为状态机,那是复杂的数据结构的陷阱),我们在决定了草案(请参考第一部分关于设计的一丁点内容)以后往往不知道怎么搭起框架,本部分希望能够在AC开发的设计理念基础上为大家准备好一个通用的框架,而基础的核心,就是为状态写代码
通常游戏的循环部分(我省略了加载和卸载部分内容)可以更细地划分为如下一些部分:(以AC为例,如果
不知道AC这个是什么,可以到我自己的GOOGLEPAGE上先看看)
游戏被划分为很多步骤(STEP): [s:8] - enum STEP {
- STEP_STARTANIM,
- STEP_CREATE,
- STEP_DELAY,
- STEP_MOVEDOWN,
- STEP_AUTODOWN,
- STEP_CHECK,
- STEP_CHECKEFFECT,
- STEP_ATTACK,
- STEP_ATTACKEFFECT,
- STEP_DEFENCE,
- STEP_ENDANIM,
- STEP_EXIT,
- STEP_COUNT,
- } ;
复制代码 我很乐意给每个步骤加上注释,但是“代码与注释脱离”告诉我们应该避免让具名的标签加上注释
(AVC很喜欢不写注释,但是他的变量你很少看到X1 Y3这类的名字),每个单位表示一个具体的流程(就是状态名),最后COUNT表示总计个数,然后你:- typedef void (Player::*Flow)( void ) ;
- Flow flowfunction[STEP_COUNT] ;
复制代码 现在所有的步骤就是索引了(这里有一个小小问题,STEP和INDEX可能不兼容,为了方便你就STATIC_CAST好了,嗯……不知道什么是STATIC_CAST的人……你干脆想个别的办法,代替STEP名称巴……)当你创建每个步骤的时候,你所做的事情就是在 进行状态分离 (当然你根据你自己划分,尽可能细,简单的划分就是你游戏的处理环节,你这样想,游戏会不断重复这个步骤,是不是每次重复的内容都类似?举个例子:AC的小球下落被进行状态分离,首先小球会被创建i.e.CREATE,然后小球会先在高处停留一会,就是DELAY,接着开始下落MOVE,就这样分成了三步,然后你想想每次会执行一个微小的步骤,唉你学过高等数学的微积分多好,DELTA X dx对,你会很高兴发现你原来已经知道了游戏是怎么运作了,你的思路会从整体中被分离开,每次一个dx^^)
一大堆,实际就是一个enum和一个function然后怎么运作这个函数的呢? [s:8] - flowfunction[STEP_STARTANIM] = &Player::startAnim;
- flowfunction[STEP_CREATE] = &Player::createBall;
- flowfunction[STEP_DELAY] = &Player::delay;
- flowfunction[STEP_MOVEDOWN] = &Player::moveDown;
- flowfunction[STEP_AUTODOWN] = &Player::autoDown;
- flowfunction[STEP_CHECK] = &Player::check;
- flowfunction[STEP_CHECKEFFECT] = &Player::checkeffect;
- flowfunction[STEP_ATTACK] = &Player::attack;
- flowfunction[STEP_ATTACKEFFECT] = &Player::attackeffect;
- flowfunction[STEP_DEFENCE] = &Player::defence;
- flowfunction[STEP_ENDANIM] = &Player::endAnim;
- flowfunction[STEP_EXIT] = &Player::exitGame;
复制代码 这么多!oh no!就一句话罢了……让你的每个player的函数注册到你步骤中去……看到了吗?为了方便,所有的函数就是对应步骤的名称的去STEP+小写罢了,那么这些事情是什么时候做得?
Player:layer(),构造函数……不懂的话……那你就放在init过程里面好了
嗯,现在是回顾一下的时候了,你在Manager部分(参考第一部分)创建了Player,Player构造的时候呢,注册了步骤对应的函数,然后你就不用关心流程怎么做了,你记住,现在你的函数的调用被简化到了你的一个标记上UINT_PTR是什么,你大叫……嗯,让我解释不如让你自己换一个好了unsigned int,嗯,你点头,我可以用int吗(你说:我比较懒- -)完全可以^^,不过不要有负数^^
第一个部分中,我写了我是用一个MOVE一个RENDER实现的代码(没说清,就是Player::Move(), Player::Render() ),所以这里我们看看MOVE实作手法:- void Player::move( void )
- {
- (this->*flowfunction[attack_flag])() ;
- }
复制代码 哦……就一句话,看不懂吗- - [s:4] ,反正就是这样调用注册版函数……
偓哦!原来你要这么做:
Manager:oop --> 其中调用每个一个Player对象的 Player::Move() -->
后者调用flowfunction,根据当前的attackflag调用现在的函数,这叫一帧Frame,然后你那个函数作了什么(那我不知道了,反正你游戏作啥?偶很乐意知道哦^^),然后每次重复,所以要LOOP!
一个要求,flowfunction需要知道什么时候,怎么样改变状态?那是,比如AC中时间一到,下落,letschange state!就这样,真的,我觉得编写的生活突然美好了很多,不需要再去调用具体的函数,反正下一次就是另外的状态了……(就是DELAY状态对应的函数被调用了)
C语言代码写作的人很喜欢用小函数,我从她们那里偷了这个思路^^,暂时就写这么点,希望大家能够从这么点东西中受到启发,而且我很乐意和大家讨论,中间也有很多不足,很希望高手指点,谢谢!
参考书籍:《WINDOWS游戏编程大师技巧》
[s:1] |
|