Cocos2d-x 3.2中重要类的总结
来源:互联网 发布:淘宝个人闲置 编辑:程序博客网 时间:2024/05/12 22:48
本文转自:http://blog.csdn.net/ac_huang/article/details/39204317
本文基于Cocos2d-x3.2版本引擎。Cocos2d-x引擎中几个主要类做了简单的介绍:Director,Application,Node,Renderer,EventDispatcher,Scheduler等对于这些类简短的介绍,在心里有个大概。
1、Application
主要方法:
virtual
const
char
* getCurrentLanguage();
virtual
Platform getTargetPlatform();
virtual
void
setAnimationInterval(
double
interval);
int
run();
//启动主循环
run()函数:
int
Application::run()
{
...
while
(!glview->windowShouldClose())
{
QueryPerformanceCounter(&nNow);
if
(nNow.QuadPart - nLast.QuadPart > _animationInterval.QuadPart)
{
nLast.QuadPart = nNow.QuadPart;
director->mainLoop();
//Director进行这一帧的渲染
glview->pollEvents();
// This function processes only those events that have already been received and then returns immediately.
}
else
{
Sleep(0);
}
}
...
return
true
;
}
2、Director
主要函数预览:
//openGL Matrix Operate在3.0里面没有,尼吗我用的是3.0蛋疼无比
void
pushMatrix(MATRIX_STACK_TYPE type);
void
popMatrix(MATRIX_STACK_TYPE type);
void
loadIdentityMatrix(MATRIX_STACK_TYPE type);
void
loadMatrix(MATRIX_STACK_TYPE type,
const
Mat4& mat);
void
multiplyMatrix(MATRIX_STACK_TYPE type,
const
Mat4& mat);
Mat4 getMatrix(MATRIX_STACK_TYPE type);
void
resetMatrixStack();
//View Data
inline
double
getAnimationInterval();
inline
bool
isDisplayStats();
inline
GLView* getOpenGLView();
inline
Projection getProjection();
Size getVisibleSize()
const
;
Vec2 getVisibleOrigin()
const
;
Vec2 convertToGL(
const
Vec2& point);
Vec2 convertToUI(
const
Vec2& point);
float
getZEye()
const
;
// Scene 场景管理
inline
Scene* getRunningScene();
void
runWithScene(Scene *scene);
void
pushScene(Scene *scene);
// 控制绘制的暂停和恢复
void
end();
void
pause();
void
resume();
//绘制图形(界面展示最重要的函数)
void
drawScene();
//Getter and Setter
Scheduler* getScheduler()
const
{
return
_scheduler; }
void
setScheduler(Scheduler* scheduler);
ActionManager* getActionManager()
const
{
return
_actionManager; }
void
setActionManager(ActionManager* actionManager);
EventDispatcher* getEventDispatcher()
const
{
return
_eventDispatcher; }
void
setEventDispatcher(EventDispatcher* dispatcher);
Renderer* getRenderer()
const
{
return
_renderer; }
drawScene():主要绘制函数
// Draw the Scene
void
Director::drawScene()
{
...
if
(! _paused)
{
_scheduler->update(_deltaTime);
//Scheduler 定时器 更新
_eventDispatcher->dispatchEvent(_eventAfterUpdate);
//Dispatcher 抛发事件.
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//glClear
if
(_nextScene)
//取得下一个将要显示的Scene.
{
setNextScene();
}
pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
//将上一次绘制的Context放到堆栈
// draw the scene
if
(_runningScene)
{
_runningScene->visit(_renderer, Mat4::IDENTITY,
false
);
_eventDispatcher->dispatchEvent(_eventAfterVisit);
}
_renderer->render();
//渲染
_eventDispatcher->dispatchEvent(_eventAfterDraw);
popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
//返回到上一次绘制时的状态.
// swap buffers
if
(_openGLView)
{
_openGLView->swapBuffers();
//把上面渲染的结果显示到屏幕
}
...
}
3、Node
visit()的主要功能就是:
1)调用所有孩子的visit函数
2)调用self->draw()函数
void
Node::visit(Renderer* renderer,
const
Mat4 &parentTransform, uint32_t parentFlags)
{
// quick return if not visible. children won't be drawn.
if
(!_visible)
{
return
;
}
uint32_t flags = processParentFlags(parentTransform, parentFlags);
// IMPORTANT:
// To ease the migration to v3.0, we still support the Mat4 stack,
// but it is deprecated and your code should not rely on it
Director* director = Director::getInstance();
director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, _modelViewTransform);
int
i = 0;
if
(!_children.empty())
{
sortAllChildren();
// draw children zOrder < 0
for
( ; i < _children.size(); i++ )
{
auto node = _children.at(i);
if
( node && node->_localZOrder < 0 )
node->visit(renderer, _modelViewTransform, flags);
else
break
;
}
// self draw
this
->draw(renderer, _modelViewTransform, flags);
for
(auto it=_children.cbegin()+i; it != _children.cend(); ++it)
(*it)->visit(renderer, _modelViewTransform, flags);
}
else
{
this
->draw(renderer, _modelViewTransform, flags);
}
director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
}
draw()函数:
因为Node是所有可显示对象的父类,没有任何显示内容,所以draw函数为空。这里我们以Sprite::draw函数为例简单介绍下draw的作用:
void
Sprite::draw(Renderer *renderer,
const
Mat4 &transform, uint32_t flags)
{
// Don't do calculate the culling if the transform was not updated
_insideBounds = (flags & FLAGS_TRANSFORM_DIRTY) ? renderer->checkVisibility(transform, _contentSize) : _insideBounds;
if
(_insideBounds)
{
_quadCommand.init(_globalZOrder, _texture->getName(), getGLProgramState(), _blendFunc, &_quad, 1, transform);
renderer->addCommand(&_quadCommand);
}
}
我们看到,Sprite::draw函数主要实现了[添加一个QuadCommand到Render中去]的功能。
再看看Label的绘制函数:
void
Label::draw(Renderer *renderer,
const
Mat4 &transform, uint32_t flags)
{
// Don't do calculate the culling if the transform was not updated
_insideBounds = (flags & FLAGS_TRANSFORM_DIRTY) ? renderer->checkVisibility(transform, _contentSize) : _insideBounds;
if
(_insideBounds) {
_customCommand.init(_globalZOrder);
_customCommand.func = CC_CALLBACK_0(Label::onDraw,
this
, transform, flags);
renderer->addCommand(&_customCommand);
}
}
其实,跟Sprite::draw也差不多。关键在于这个RenderCommand怎么构造和执行的。
4、Renderer渲染器
主要函数预览:
void
initGLView();
/** Adds a `RenderComamnd` into the renderer */
void
addCommand(RenderCommand* command);
/** Adds a `RenderComamnd` into the renderer specifying a particular render queue ID */
void
addCommand(RenderCommand* command,
int
renderQueue);
/** Pushes a group into the render queue */
void
pushGroup(
int
renderQueueID);
/** Pops a group from the render queue */
void
popGroup();
/** Creates a render queue and returns its Id */
int
createRenderQueue();
/** Renders into the GLView all the queued `RenderCommand` objects */
void
render();
可见它主要由两个功能:
1)对ReanderCommand进行排序和分类管理。
2)进行渲染:render()
渲染函数Renderer::render()
void
Renderer::render()
{
...
if
(_glViewAssigned)
{
...
//排列渲染队列
for
(auto &renderqueue : _renderGroups)
{
renderqueue.sort();
}
//进行渲染
visitRenderQueue(_renderGroups[0]);
...
}
...
}
5、Schelduler
Schelduler是Cocos2d-x中实现延迟调用,定时调用时最重要的功能。类似于其他语言中的Timer他最核心的函数就是:
void
schedule(
const
ccSchedulerFunc& callback,
void
*target,
float
interval, unsigned
int
repeat,
float
delay,
bool
paused,
const
std::string& key);
用来启动一个定时操作:在延迟delay时间后,每隔repeat时间,调用一次callback.target用来标记这个操作属于谁,方便管理,比如在析构的时候调用voidunschedule(void*target)即可移除当前对象的所有定时操作。Schelduler的其它大部分方法,要么是它的衍生,为了减少调用参数;要么是对定时操作的控制,比如暂停、恢复、移除等。
6、EventDispatcher
EventDispatcher,EventListener,Event之间的关系如下:
1)EventDispatcher:事件分发器,相当于所有事件的中控中心。管理着EventListener,当一个Event到来的时候决定CallBack的调用顺序。
2)Event(EventTouch,EventKeyboard等),具体的事件数据等。
3)EventListener(EventListenerTouch,EventListenerKeyboard等):建立了Event到CallBack的映射关系,EventDispatcher根据这种映射关系调用对应的CallBack。
6.1 Event
Event有以下几种类型:
enum
class
Type
{
TOUCH,
KEYBOARD,
ACCELERATION,
MOUSE,
FOCUS,
CUSTOM
};
Event最重要的属性就是type,标识了它是那种类型的事件,也决定了由哪个EventListner来处理它。
6.2 EventListener
EventListner有以下几种类型:
enum
class
Type
{
UNKNOWN,
TOUCH_ONE_BY_ONE,
TOUCH_ALL_AT_ONCE,
KEYBOARD,
MOUSE,
ACCELERATION,
FOCUS,
CUSTOM
};
除了UNKNOWN,跟Event::Type相比,Event::Type::TOUCH会同时被两种类型的EventListener处理:TOUCH_ONE_BY_ONE和TOUCH_ALL_AT_ONCE。这两种EventListener分别处理单点触摸事件和多点触摸事件。多说几句:假如一个TouchEvent事件中有多个触摸点,那么类型为EventListener::Type::TOUCH_ONE_BY_ONE的EventListener会把这个事件分解成若干个单点触摸事件来处理。而类型为EventListener::Type::TOUCH_ALL_AT_ONCE的EventListener就是来处理多点触摸的,会一次处理它,其它几种类型都是一一对应的,即一种Event::Type的Event会被对应类型的EventListener接受。
6.3 存放EventListener的地方
在EventDispatcher中,它把以上7种EventListener::Type类型的EventListner放到7个队列中.也就是在这样一个字段中:
std::unordered_map<EventListener::ListenerID, EventListenerVector*> _listenerMap;
1)EventListener::ListenerID:每一种EventListener::Type有唯一的EventListener::ListenerID.其实通过这段代码typedefstd::stringListenerID;可知:EventListener::ListenerID就是简单string,就是一个名称而已。
2)EventListenerVector:顾名思义,就是一个EventListener的向量容器.相对于普通的向量容器,它增加了priority管理功能。
6.4 EventListener的fixedPriority
简单来说,每个EventListener有自己的fixedPriority属性,它是一个整数。
6.5 EventListener的遍历顺序
EventDispatcher在抛发事件的时候,会先处理Event的时候,会优先遍历fixedPriority低的EventListener,调用它的CallBack在某些条件下一个Event被一个EventListener处理之后,会停止遍历其它的EventListener。反映到实战中就是:你监听了某种事件,这种事件也出发了,但是对应的回调函数并没有被调用,也就是被优先级更高的EventListener截获了。
如果fixedPriority一样呢?按照什么顺序?
1、fixedPriority为0,这个值是专门为SceneObject预留的。即默认情况下,绝大多数继承自Node的对象添加的普通事件监听器,其fixedPriority都为0。此时,Node的globalZOrder决定了优先级,值越大,越先被遍历到,即在显示层中层级越高,越先接受事件,这在ui响应逻辑中也是合理的。
2、fixedPriority不为0,那就按添加顺序。
6.6 Event在什么条件下会被优先级更高的EventListener截获?
1)对于EventListenerTouchOneByOne,它有一个字段:_needSwallow,当它为true的时候,如果它接受了某个Event,优先级更低的EventListener就接受不到了。可以用EventListenerTouchOneByOne::setSwallowTouches(boolneedSwallow)来改变它。
2)对于其它类型的EventLIstener,只有在显示调用了Event::stopPropagation()的时候,才会中断遍历。
6.7 EventDispatcher::dispatchEvent()
下面我们看看EventDispatcher最核心的函数:
voidEventDispatcher::dispatchEvent(Event*event);
当有响应的事件到来的时候,都会调用这个函数来通知监听了此事件的对象。其实上面的介绍,已经把这个函数里绝大部分逻辑都描述了,这里做一个最后的总结。
事件抛发的简要流程如下:
1)检查_listenerMap中所有的EventListnerVector,如果哪个容器的EventListener优先级顺序需要更新,则重新排序。
2)对于类型为Event::Type::TOUCH的事件,则按照EventListener的遍历顺序遍历所有的EventListener。只有接受了EventTouch::EventCode::BEGAN事件的EventListener,才会收到其他类型的EventTouch事件。
3)对于其他类型的事件,也按照EventListener的遍历顺序的顺序遍历对应的EventListener。
6.8 总结
Eventdispatcher中的其它函数,主要功能都是添加EventListener,删除EventListener等,不做详细介绍。
总的来说,Eventdispatcher是一个中转器:
1)事件的产生模块儿,只关心自己构造正确的Event,调用EventDispatcher::dispatchEvent(Event*event)交给EventDispatcher。
2)需要监听事件的模块儿,只需调用EventDispatcher::addEventListener(EventListener*listener)(或者它的其它变种)来注册自己作为监听者。
3)EventDispatcher的作用是:
把特定类型的Event送给对应类型的EventListener。
对于同一种Event,规定了事件送达的优先级。
- Cocos2d-x 3.2中重要类的总结
- cocos2d-x 3.2 中的重要类总结
- cocos2d-x中Node中重要的属性
- cocos2d-x游戏开发(九)重要的基类CCNode
- cocos2d-x游戏开发(九)重要的基类CCNode
- cocos2d-x游戏开发(九)重要的基类CCNode
- cocos2d-x游戏开发(九)重要的基类CCNode
- cocos2d-x的几个重要概念
- cocos2d-x中缓存总结
- cocos2d-x中添加gameCenter的一些总结
- Cocos2d-x项目过程中遇到的一些问题总结
- Cocos2d-x项目过程中遇到的一些问题总结
- 关于Cocos2d-x中定时器的使用总结
- Cocos2d-x中动作类的扩展
- cocos2d-x 中JniHelper类的使用
- Cocos2d-x中,Follow类的使用
- Cocos2d-x中,Speed类的使用
- Cocos2d-x中,ProgressTo类的使用
- 【C++】总结
- 类基本概念2-作用域,构造函数上
- C# PInvoke(DllImport使用) 进阶教程(一)
- 在Oracle Enterprise Linux上配置iSCSI
- 选择排序
- Cocos2d-x 3.2中重要类的总结
- ssky-keygen + ssh-copy-id 无密码登陆远程LINUX主机【OK】
- EasyUI
- 模拟从后台取数据,用highchart画图
- .NET 产品版权保护方案 (.NET源码加密保护)
- 快速上手RaphaelJS--RaphaelJS_Starter翻译(三)
- 新游网络陈伟:Testin云测手游测试技术与服务一直遥遥领先
- 大话数据结构学习笔记(五)
- shell脚本实现无密码交互的SSH自动登陆