cocos2d-x 游戏开发之有限状态机(FSM) (四)
cocos2d-x 游戏开发之有限状态机(FSM) (四)
虽然我们了解了FSM,并且可以写自己的FSM,但是有更好的工具帮我们完成这个繁琐的工作。SMC(http://smc.sourceforge.net/)就是这样的工具。下载地址:
http://sourceforge.net/projects/smc/files/latest/download
在bin下面的Smc.jar是用于生成状态类的命令行工具。使用如下命令:
$ java -jar Smc.jar Monkey.sm
1 真实世界的FSM
首先定义一个状态机纯文本文件:Monkey.sm,内容如下:
// cheungmine
// 2015-01-22
// entity class
%class Monkey
// entity class header
%header Monkey.h
// inital state
%start MonkeyMap::STOP
// entity state map
%map MonkeyMap
%%
STOP
Entry {
stop();
}
Exit {
exit();
}
{
walk WALK {}
}
WALK
Entry {
walk();
}
Exit {
exit();
}
{
stop STOP {}
turn TURN {}
}
TURN
Entry {
turn();
}
Exit {
exit();
}
{
walk WALK {}
}
%%
其中%class Monkey 说明实体类的名字:Monkey (Monkey.h和Monkey.cpp)
%header 指定头文件:Monkey.h
%map 指明状态图类,这个类包含全部状态。这里是:MonkeyMap
%start 指明其实的状态,这里是STOP,对应的类是:MonkeyMap_STOP
%%...%%之间的部分定义每个状态。格式如下:
STOP // 状态名
Entry {
// 执行这个函数进入该状态
stop();
}
Exit {
// 执行这个函数退出该状态
exit();
}
{
// 状态切换逻辑
walk WALK {}
}
当运行下面的命令,会自动生成文件:Monkey_sm.h和Monkey_sm.cpp。连同自带的statemap.h一起加入到项目中。
java -jar Smc.jar Monkey.sm
2 实体类
业务逻辑仍然要我们自己实现,那就是写Monkey.h和Monkey.cpp。不过这次写Monkey类需要按一定的规则,下面是源代码:
// Monkey.h
//
#ifndef MONKEY_H_
#define MONKEY_H_
#include "cocos2d.h"
USING_NS_CC;
#include "Monkey_sm.h"
#define MAX_STOP_TIME 3
#define MAX_WALK_TIME 10
#define MAX_WALK_DIST 200
class Monkey : public Node
{
public:
CREATE_FUNC(Monkey);
virtual bool init();
void stop();
void walk();
void turn();
void exit();
private:
MonkeyContext * _fsm;
int _step;
int _curPos;
time_t _curTime;
// Sprite * _sprite;
private:
void onIdleStop(float dt)
{
int d = (int) (time(0) - _curTime);
if (d > MAX_STOP_TIME) {
_fsm->walk();
}
}
void onIdleWalk(float dt)
{
if (_curPos > MAX_WALK_DIST || _curPos < -MAX_WALK_DIST) {
_fsm->turn();
}
int d = (int) (time(0) - _curTime);
if (d > MAX_WALK_TIME) {
_fsm->stop();
}
_curPos += _step;
}
void onIdleTurn(float dt)
{
_fsm->walk();
}
};
#endif // MONKEY_H_
上面的onIdle????是触发状态的回调函数,实体状态改变的业务逻辑在这里实现。
// Monkey.cpp
//
#include "Monkey.h"
#include <time.h>
#include <assert.h>
void Monkey::exit()
{
this->unscheduleAllCallbacks();
cocos2d::log("exit()");
}
bool Monkey::init()
{
_step = 1;
_curPos = 0;
_curTime = time(0);
// _sprite = Sprite::create("monkey.png");
// addChild(_sprite);
_fsm = new MonkeyContext(*this);
assert(_fsm);
_fsm->setDebugFlag(true);
_fsm->enterStartState();
return true;
}
void Monkey::stop()
{
_curTime = time(0);
cocos2d::log("stop(): pos=%d", _curPos);
this->schedule(schedule_selector(Monkey::onIdleStop), 0.1f);
}
void Monkey::walk()
{
_curTime = time(0);
cocos2d::log("walk(): pos=%d", _curPos);
this->schedule(schedule_selector(Monkey::onIdleWalk), 0.1f);
}
void Monkey::turn()
{
_step *= -1;
cocos2d::log("turn(): step=%d", _step);
this->schedule(schedule_selector(Monkey::onIdleTurn), 0.1f);
}
3 状态机类
框架代码Smc已经帮我们生成好了:Monkey_sm.h和Monkey_sm.cpp:
//
// ex: set ro:
// DO NOT EDIT.
// generated by smc (http://smc.sourceforge.net/)
// from file : Monkey.sm
//
#ifndef MONKEY_SM_H
#define MONKEY_SM_H
#define SMC_USES_IOSTREAMS
#include "statemap.h"
// Forward declarations.
class MonkeyMap;
class MonkeyMap_STOP;
class MonkeyMap_WALK;
class MonkeyMap_TURN;
class MonkeyMap_Default;
class MonkeyState;
class MonkeyContext;
class Monkey;
class MonkeyState :
public statemap::State
{
public:
MonkeyState(const char * const name, const int stateId)
: statemap::State(name, stateId)
{};
virtual void Entry(MonkeyContext&) {};
virtual void Exit(MonkeyContext&) {};
virtual void stop(MonkeyContext& context);
virtual void turn(MonkeyContext& context);
virtual void walk(MonkeyContext& context);
protected:
virtual void Default(MonkeyContext& context);
};
class MonkeyMap
{
public:
static MonkeyMap_STOP STOP;
static MonkeyMap_WALK WALK;
static MonkeyMap_TURN TURN;
};
class MonkeyMap_Default :
public MonkeyState
{
public:
MonkeyMap_Default(const char * const name, const int stateId)
: MonkeyState(name, stateId)
{};
};
class MonkeyMap_STOP :
public MonkeyMap_Default
{
public:
MonkeyMap_STOP(const char * const name, const int stateId)
: MonkeyMap_Default(name, stateId)
{};
virtual void Entry(MonkeyContext&);
virtual void Exit(MonkeyContext&);
virtual void walk(MonkeyContext& context);
};
class MonkeyMap_WALK :
public MonkeyMap_Default
{
public:
MonkeyMap_WALK(const char * const name, const int stateId)
: MonkeyMap_Default(name, stateId)
{};
virtual void Entry(MonkeyContext&);
virtual void Exit(MonkeyContext&);
virtual void stop(MonkeyContext& context);
virtual void turn(MonkeyContext& context);
};
class MonkeyMap_TURN :
public MonkeyMap_Default
{
public:
MonkeyMap_TURN(const char * const name, const int stateId)
: MonkeyMap_Default(name, stateId)
{};
virtual void Entry(MonkeyContext&);
virtual void Exit(MonkeyContext&);
virtual void walk(MonkeyContext& context);
};
class MonkeyContext :
public statemap::FSMContext
{
public:
explicit MonkeyContext(Monkey& owner)
: FSMContext(MonkeyMap::STOP),
_owner(&owner)
{};
MonkeyContext(Monkey& owner, const statemap::State& state)
: FSMContext(state),
_owner(&owner)
{};
virtual void enterStartState()
{
getState().Entry(*this);
}
inline Monkey& getOwner()
{
return *_owner;
};
inline MonkeyState& getState()
{
if (_state == NULL)
{
throw statemap::StateUndefinedException();
}
return dynamic_cast<MonkeyState&>(*_state);
};
inline void stop()
{
getState().stop(*this);
};
inline void turn()
{
getState().turn(*this);
};
inline void walk()
{
getState().walk(*this);
};
private:
Monkey* _owner;
};
#endif // MONKEY_SM_H
//
// Local variables:
// buffer-read-only: t
// End:
//
//
// ex: set ro:
// DO NOT EDIT.
// generated by smc (http://smc.sourceforge.net/)
// from file : Monkey.sm
//
#include "Monkey.h"
#include "Monkey_sm.h"
using namespace statemap;
// Static class declarations.
MonkeyMap_STOP MonkeyMap::STOP("MonkeyMap::STOP", 0);
MonkeyMap_WALK MonkeyMap::WALK("MonkeyMap::WALK", 1);
MonkeyMap_TURN MonkeyMap::TURN("MonkeyMap::TURN", 2);
void MonkeyState::stop(MonkeyContext& context)
{
Default(context);
}
void MonkeyState::turn(MonkeyContext& context)
{
Default(context);
}
void MonkeyState::walk(MonkeyContext& context)
{
Default(context);
}
void MonkeyState::Default(MonkeyContext& context)
{
throw (
TransitionUndefinedException(
context.getState().getName(),
context.getTransition()));
}
void MonkeyMap_STOP::Entry(MonkeyContext& context)
{
Monkey& ctxt = context.getOwner();
ctxt.stop();
}
void MonkeyMap_STOP::Exit(MonkeyContext& context)
{
Monkey& ctxt = context.getOwner();
ctxt.exit();
}
void MonkeyMap_STOP::walk(MonkeyContext& context)
{
context.getState().Exit(context);
context.setState(MonkeyMap::WALK);
context.getState().Entry(context);
}
void MonkeyMap_WALK::Entry(MonkeyContext& context)
{
Monkey& ctxt = context.getOwner();
ctxt.walk();
}
void MonkeyMap_WALK::Exit(MonkeyContext& context)
{
Monkey& ctxt = context.getOwner();
ctxt.exit();
}
void MonkeyMap_WALK::stop(MonkeyContext& context)
{
context.getState().Exit(context);
context.setState(MonkeyMap::STOP);
context.getState().Entry(context);
}
void MonkeyMap_WALK::turn(MonkeyContext& context)
{
context.getState().Exit(context);
context.setState(MonkeyMap::TURN);
context.getState().Entry(context);
}
void MonkeyMap_TURN::Entry(MonkeyContext& context)
{
Monkey& ctxt = context.getOwner();
ctxt.turn();
}
void MonkeyMap_TURN::Exit(MonkeyContext& context)
{
Monkey& ctxt = context.getOwner();
ctxt.exit();
}
void MonkeyMap_TURN::walk(MonkeyContext& context)
{
context.getState().Exit(context);
context.setState(MonkeyMap::WALK);
context.getState().Entry(context);
}
//
// Local variables:
// buffer-read-only: t
// End:
//
4 总结
FSM是一种固定的范式,因此采用工具帮我们实现可以减少犯错误的机会。输入的文件就是:实体.sm。我们把重点放在业务逻辑上,所以与状态有关的代码smc都帮我们生成好了。对比一下我们手工创建和smc框架工具自动生成的类:
在cocos2d-x中使用很简单:
bool HelloWorld::init()
{
//////////////////////////////
// 1. super init first
if ( !Layer::init() )
{
return false;
}
auto rootNode = CSLoader::createNode("MainScene.csb");
addChild(rootNode);
auto closeItem = static_cast<ui::Button*>(rootNode->getChildByName("Button_1"));
closeItem->addTouchEventListener(CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));
/////////////////// test ///////////////////////
Monkey * mk = Monkey::create();
addChild(mk);
return true;
}
就这样了!不明白的地方请仔细阅读:
Cocos2d-x游戏开发之旅(钟迪龙)
cocos2d-x 游戏开发之有限状态机(FSM) (四)的更多相关文章
- cocos2d-x 游戏开发之有限状态机(FSM) (三)
cocos2d-x 游戏开发之有限状态机(FSM) (三) 有限状态机简称FSM,现在我们创建一个专门的FSM类,负责管理对象(Monkey)的状态.然后Monkey类就实现了行为与状态分离.Monk ...
- cocos2d-x 游戏开发之有限状态机(FSM) (一)
cocos2d-x 游戏开发之有限状态机(FSM) (一) 参考:http://blog.csdn.net/mgphuang/article/details/5845252<Cocos2d-x游 ...
- cocos2d-x 游戏开发之有限状态机(FSM) (二)
cocos2d-x 游戏开发之有限状态机(FSM) (二) 1 状态模式
- 《C++游戏开发》笔记十四 平滑过渡的战争迷雾(二) 实现:真正的迷雾来了
本系列文章由七十一雾央编写,转载请注明出处. http://blog.csdn.net/u011371356/article/details/9712321 作者:七十一雾央 新浪微博:http:/ ...
- iOS cocos2d 2游戏开发实战(第3版)书评
2013是游戏爆发的一年,手游用户也是飞速暴增.虽然自己不做游戏,但也是时刻了解手机应用开发的新动向.看到CSDN的"写书评得技术图书赢下载分"活动,就申请了一本<iOS c ...
- java游戏开发杂谈 - 有限状态机
在不同的阶段,游戏所运行的逻辑.所显示的界面,都是不同的. 以五子棋举例,游戏开始.游戏中.胜负已分,对应的界面和逻辑都不同. 在游戏中,又分为:自己下棋.对方下棋.游戏暂停.悔棋等多个状态. 再比如 ...
- Unity3D游戏开发从零单排(四) - 制作一个iOS游戏
提要 此篇是一个国外教程的翻译,尽管有点老,可是适合新手入门. 自己去写代码.debug,布置场景,能够收获到非常多.游戏邦上已经有前面两部分的译文,这里翻译的是游戏的最后一个部分. 欢迎回来 在第一 ...
- DirectX12 3D 游戏开发与实战第四章内容(上)
Direct3D的初始化(上) 学习目标 了解Direct3D在3D编程中相对于硬件所扮演的角色 理解组件对象模型COM在Direct3D中的作用 掌握基础的图像学概念,例如2D图像的存储方式,页面翻 ...
- DirectX12 3D 游戏开发与实战第四章内容(下)
Direct3D的初始化(下) 学习目标 了解Direct3D在3D编程中相对于硬件所扮演的角色 理解组件对象模型COM在Direct3D中的作用 掌握基础的图像学概念,例如2D图像的存储方式,页面翻 ...
随机推荐
- Mac 下安装运行Rocket.chat
最近花了一周的时间,复习了HTML.CSS.原生JS,并学习了Node.js.CoffeeScript.js.MongoDB,入了下门. 因为准备在Rocket.chat 上做二次开发,所以先下载和安 ...
- RxJava(十一)defer操作符实现代码支持链式调用
欢迎转载,转载请标明出处: http://blog.csdn.net/johnny901114/article/details/52597643 本文出自:[余志强的博客] 一.前言 现在越来越多An ...
- ANT不完全总结,包含各种命令,ant例子等,转自:http://lavasoft.blog.51cto.com/62575/87306
ANT不完全总结 好久没有用Ant了,最近让MyEclipse.JBuilder2008逼的重回Ant上了.手生了,写了一个脚本后,重新总结下.参考了官方的文档和网上一些资料. 一.ANT的介 ...
- 23 服务IntentService Demo6
MainActivity.java package com.qf.day23_service_demo2; import android.app.Activity; import android.co ...
- Android在一个TextView里显示不同样式的字体
在同一个TextView里显示不同样式的字体 public void setSpan(Object what, int start, int end, int flags); 样式1:背景色.粗体.字 ...
- XCode5添加新建类模板(Cocos2dx Template Class for Scene or Layer)
猴子原创,欢迎转载.转载请注明: 转载自Cocos2D开发网–Cocos2Dev.com,谢谢! 原文地址: http://www.cocos2dev.com/?p=505 因为常用cocos2dx开 ...
- SSH深度历险(七) 剖析SSH核心原理(一)
接触SSH有一段时间了,但是对于其原理,之前说不出来莫模模糊糊(不能使用自己的语言描述出来的就是没有掌握),在视频和GXPT学习,主要是实现了代码,一些原理性的内容还是欠缺的,这几天我自己也一直在反问 ...
- [java面试]宇信易诚 广州分公司 java笔试题目回忆录
本文地址:http://blog.csdn.net/sushengmiyan/article/details/28479895 作者:sushengmiyan -------------------- ...
- Cocos2D iOS之旅:如何写一个敲地鼠游戏(八):为动画建立属性列表
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流 ...
- Activity之间的数据传递-android学习之旅(四十七)
activity之间的数据传递主要有两种,一种是直接发送数据,另一种接受新启动的activity返回的数据,本质是一样的 使用Bundle传递数据 Intent使用Bundle在activity之间传 ...