Cocos2d-X3.0 刨根问底三----- Director类源码分析


Cocos2d-X3.0 刨根问底(三)----- Director类源码分析

上一章我们完整的跟了一遍HelloWorld的源码,了解了Cocos2d-x的启动流程。其中Director这个类贯穿了整个Application程序,这章随小鱼一起把这个类分析透彻。

小鱼的阅读源码的习惯是,一层层地分析代码,在阅读Director这个类的时候,碰到了很多其它的Cocos2d-x类,我的方式是先大概了解一下类的作用,完整的去了解Director类,之后再去按照重要程度去分析碰到的其它类。

一点一点分析 CCDirector.h

#ifndef __CCDIRECTOR_H__
#define __CCDIRECTOR_H__

#include "CCPlatformMacros.h"

#include "CCRef.h"
#include "ccTypes.h"
#include "CCGeometry.h"
#include "CCVector.h"
#include "CCGL.h"
#include "CCLabelAtlas.h"
#include "kazmath/mat4.h"


NS_CC_BEGIN

/**
 * @addtogroup base_nodes
 * @{
 */

/* Forward declarations. */
class LabelAtlas;
class Scene;
class GLView;
class DirectorDelegate;
class Node;
class Scheduler;
class ActionManager;
class EventDispatcher;
class EventCustom;
class EventListenerCustom;
class TextureCache;
class Renderer;

#if  (CC_TARGET_PLATFORM != CC_PLATFORM_WINRT) && (CC_TARGET_PLATFORM != CC_PLATFORM_WP8)
class Console;
#endif

从ccdirector.h的包含文件和引用的类来看,我们可以看到Director类都管些什么,做个初步了解。

管理的有 Label(标签) 、Scene(场景)、 GLView(OpenGL渲染) 、Node(结点?不知道是什么玩意后面我们再仔细分析)、Scheduler(程序调度)、ActionManager(动画管理)、EventDispatcher(事件管理)、EventCuston(也和事件有关)、EventListenerCuston(事件侦听有关系)、TextureCache(纹理缓存)、Renderer(渲染器)、Console(控制台)

这个大管家管了这么多东西,后面的章节我来逐个分析这些东西是什么,现在只要不阻碍分析Director这个大管家类,可以暂时不用理会其它类的实现的具体内容。

继续往下看Director类的具体定义

class CC_DLL Director : public Ref

Director类继承了 Ref类,参看Ref类的定义可以大体了解到是一个用来做引用记数的类,相关还有PoolManager,AutoreleasePool,等,从命名可以了解cocos2d-x有自己的内存管理机制,用到了引用记数来确定对象是否应该释放,相应的有管理类来控制。后面我们单独去分析coocs2d-x的内存管理。在这里只知道Director类也是由统一的内存管理器来控制的。

下面看一下Director类的公有函数

static const char *EVENT_PROJECTION_CHANGED;
    
static const char* EVENT_AFTER_UPDATE;
    
static const char* EVENT_AFTER_VISIT;
    
static const char* EVENT_AFTER_DRAW;
const char *Director::EVENT_PROJECTION_CHANGED = "director_projection_changed";
const char *Director::EVENT_AFTER_DRAW = "director_after_draw";
const char *Director::EVENT_AFTER_VISIT = "director_after_visit";
const char *Director::EVENT_AFTER_UPDATE = "director_after_update";

最开始定义了几个事件Director类的事件类型, 依次是 工程类型改变,draw(渲染) visit(访问) update(更新)之后的事件 可猜测 当 draw visit update之后director可抛出相应事件外部捕获后进后自己的处理。

enum class Projection
    {
        /// sets a 2D projection (orthogonal projection)
        _2D,/// sets a 3D projection with a fovy=60,znear=0.5f and zfar=1500.
        _3D,/// it calls "updateProjection" on the projection delegate.
        CUSTOM,/// Default projection is 3D projection
        DEFAULT = _3D,};

这个枚举定义了工程类型 有 2D 3D 和自定义,默认为3D游戏类型。

/** returns a shared instance of the director */
    static Director* getInstance();

    /** @deprecated Use getInstance() instead */
    CC_DEPRECATED_ATTRIBUTE static Director* sharedDirector() { return Director::getInstance(); }
    /**
     * @js ctor
     */
    Director(void);
    /**
     * @js NA
     * @lua NA
     */
    virtual ~Director();

这段代码可以知道 Director也是单例创建型。并且提供了外部得到实例的接口sharedDirector;

virtual bool init();

init整个director对象的初始化工作都在这里面。这个函数很重要,我们稍后单独分析它

后面代码里很多方法注释里面已经描述的很详细了,这里我们简单过一遍,大多是些Get Set的方法。

/** 得到director当前正在运行的场景,director同一时间只能有一个场景在运行*/
    inline Scene* getRunningScene() { return _runningScene; }

    /** 得到动画的帧速率*/
    inline double getAnimationInterval() { return _animationInterval; }
    /** 设置动画的帧频,这里看到这是一个纯虚函数,所以Director是一个抽象类,不能被实例化,使用的时候必须继承这个类开实现自己的Director. */
    virtual void setAnimationInterval(double interval) = 0;

    /** 询问是否在左下角显示帧频,我们看helloworld里面有一个fps显示,这里应该就是控制显示fps的地方 */
    inline bool isDisplayStats() { return _displayStats; }
    /** 设置是否要在左下角显示帧频*/
    inline void setDisplayStats(bool displayStats) { _displayStats = displayStats; }
    
    /** 得到每一帧消耗时间多少秒 如每秒60的帧频那么这个返回值就是 1/60秒*/
    inline float getSecondsPerFrame() { return _secondsPerFrame; }
/** 得到封装OpenGl操作的对象GLView的接口 
    * @js NA
    * @lua NA
    */
    inline GLView* getOpenGLView() { return _openGLView; }
    void setOpenGLView(GLView *openGLView);

纹理缓存的对象

TextureCache* getTextureCache() const;

下面几个函数是用来控制游戏循环中帧与帧之间的时间间隔的,其中涉及到两个成员变量

/* 标记是否下次帧逻辑时是否清除(忽略)_deltaTime */
    bool _nextDeltaTimeZero;    
/* 上一次逻辑帧运行到当前的时间间隔,用来判断是否应该进行下次逻辑帧,上一次帧执行的时间记录在 _lastUpdate 变量里面*/
    float _deltaTime;

下面两个函数是用来操作下一次的 _deltaTime是否有效的,当整个游戏暂停的时候,这时_deltaTime会不断累计,就会用到了_nextDeltaTimeZero这个变量,标记着下次的_deltaTime为0这样就会不出现恢复暂停后跳帧,而是继续当前帧顺序开始。

inline bool isNextDeltaTimeZero() { return _nextDeltaTimeZero; }
    void setNextDeltaTimeZero(bool nextDeltaTimeZero);

计算_deltaTime的函数,会在每个逻辑循环里面都调用。

/** 计算 deltaTime 上次逻辑帧调用的时间和当前时间的时间间隔。如果 nextDeltaTimeZero为true则deltaTime为0*/    
    void calculateDeltaTime();    
/*上次主循环帧执行到当前的时间间隔 _deltaTime*/
    float getDeltaTime() const;

继续看代码

/** 询问当前是否是暂停状态 游戏暂停用 _paused这个变量记录 */
    inline bool isPaused() { return _paused; }

    /** director运行后一共执行了多少帧*/
    inline unsigned int getTotalFrames() { return _totalFrames; }
    
    /** 设置/读取 _projection变量,标记工程类型 2d?3d?
     @since v0.8.2
     * @js NA
     * @lua NA
     */
    inline Projection getProjection() { return _projection; }
    void setProjection(Projection projection);
    
    /** 设置opengl的viewport*/
    void setViewport();

下面是一些坐标的操作方法

/** 可以得到通知消息的node结点,具体后面分析Node再讨论,现在大概了解一下*/
    Node* getNotificationNode() const { return _notificationNode; }
    void setNotificationNode(Node *node);
    
    // 下面是设置和获得窗口尺寸的一些函数 注释已经很详细了,这里就不翻译了
    /** returns the size of the OpenGL view in points.
    */
    const Size& getWinSize() const;

    /** returns the size of the OpenGL view in pixels.
    */
    Size getWinSizeInPixels() const;
    
    /** returns visible size of the OpenGL view in points.
     *  the value is equal to getWinSize if don't invoke
     *  GLView::setDesignResolutionSize()
     */
    Size getVisibleSize() const;
    
    /** returns visible origin of the OpenGL view in points.
     */
    Point getVisibleOrigin() const;

    /** converts a UIKit coordinate to an OpenGL coordinate
     Useful to convert (multi) touch coordinates to the current layout (portrait or landscape)
     */
    Point convertToGL(const Point& point);

    /** converts an OpenGL coordinate to a UIKit coordinate 坐标转换
     Useful to convert node points to window points for calls such as glScissor
     */
    Point convertToUI(const Point& point);

    /// XXX: missing description 
    float getZEye() const;

下面是场景管理的一些方法 这部分挺重要的,我们深入分析

先看一下关于Scene场景的一些属性

/* 当前正在执行的场景,由这个变量可以知道,Cocos2d-x同一时间只能执行一个场景。*/
    Scene *_runningScene;
    
    /* 下一个要执行的场景,这块肯定是在场景切换的时候要用到的 */
    Scene *_nextScene;
    
    /* 是否清除场景的标记,当为真时,旧的场景就收到清除消息 */
    bool _sendCleanupToScene;

    /* 场景的堆栈 */
    Vector<Scene*> _scenesStack;

通过这几个关于场景的属性可以大体了解到,Cocos2d-x同时只能执行一个场景,场景切换的时候有一个 _nextScene。清除场景时有一个标记 _scendCleanupToScene,等待执行的场景都存在 一个栈里面 _scenesStack

/** 设置要执行的场景     */
    void runWithScene(Scene *scene);

    /** 将新的场景加入到执行堆栈里面,新加入的场景将会被立即执行,使用的时候避免这个堆栈里的场景太多,防止设备内存不足,当已经有场景在执行的时候可以调用此方法来切换场景     */
    void pushScene(Scene *scene);

    /** 从堆栈中弹出最后加入的场景,在使用这个函数的时候要确保已经有一个场景在执行且在堆栈里面。弹出的场景会被清除,如果栈空了,那么Director就会停止     */
    void popScene();

    /** 通过调用 `popToSceneStackLevel(1)` 这个方法来实现清理栈里的场景只留下根场景,就是剩下第一个入栈的场景     */
    void popToRootScene();

    /** 按栈的层次来清理栈里的场景,level=0全清除 =1时 为 popToRootScene() 如果值超出了栈里的场景数量则不处理     */
     void popToSceneStackLevel(int level);

    /** 当有场景在执行的时候,替换当前运行的场景     */
    void replaceScene(Scene *scene);

    /** 停止当前场景     */
    void end();

    /** 暂停场景     */
    void pause();

    /** 暂停后恢复场景
     */
    void resume();
/** 停止动画及所有逻辑     */
    virtual void stopAnimation() = 0;

    /**开始动画循环
     */
    virtual void startAnimation() = 0;

    /** 渲染场景
    */
    void drawScene();

下面是一些内存控制的

/** 清除Direct的内存缓存,看下源码可以大概了解都有字体,纹理,文件等内存资源     */
    void purgeCachedData();

    /** 设置默认值,具体有哪些看下代码就知道了,很清楚写的*/
    void setDefaultValues();

OpenGl的一些操作

/** 设置OpenGl的默认值*/
    void setGLDefaultValues();

    /** 设置是否开启透明*/
    void setAlphaBlending(bool on);

    /** 设置是否开启深度测试*/
    void setDepthTest(bool on);

Director主循环 所有Director场景逻辑都会在这里触发

virtual void mainLoop() = 0;

还有一些方法,简单过一遍,从命名上就可以知道大概的含义了,有些后面我们分章节来详细分析

/** 设置/获得缩放比例    */
    void setContentScaleFactor(float scaleFactor);
    float getContentScaleFactor() const { return _contentScaleFactor; }

    /** 得到调度控制对象 ,这个Scheduler应该是类似一个定时期和一堆回调方法的东西,后面我们专门分析这玩意     */
    Scheduler* getScheduler() const { return _scheduler; }
    
    /** 设置定时器     */
    void setScheduler(Scheduler* scheduler);

    /** 获得、设置动作管理器对象    后面单独分析这个类 */
    ActionManager* getActionManager() const { return _actionManager; }
    void setActionManager(ActionManager* actionManager);
    
    /**事件分发器的 get set操作     后面单独分析这个类*/
    EventDispatcher* getEventDispatcher() const { return _eventDispatcher; }
    void setEventDispatcher(EventDispatcher* dispatcher);

    /** 渲染器 后面单独分析这个类     */
    Renderer* getRenderer() const { return _renderer; }

上面解剖了Director类,有几个方法我们着重看一下

先看返回单例对象的方法

Director* Director::getInstance()
{
    if (!s_SharedDirector)
    {
        s_SharedDirector = new DisplayLinkDirector();
        s_SharedDirector->init();
    }

    return s_SharedDirector;
}

值得注意的是,返回的是DisplayLinkDirector这个类,并且在创建完 DisplayLinkDirector对象后调用了init方法,

咱们先不管DisplayLinkDirector类是什么,肯定是一个Director的一个子类,因为Director是一个抽象类

先看一下init方法 从这个方法里面我们再一次了解一下,Director具体都能干什么,和一些内部初始化的工作是怎么完成的

bool Director::init(void)
{
    setDefaultValues();

    // scenes
    _runningScene = nullptr;
    _nextScene = nullptr;

    _notificationNode = nullptr;

    _scenesStack.reserve(15);

    // FPS
    _accumDt = 0.0f;
    _frameRate = 0.0f;
    _FPSLabel = _drawnBatchesLabel = _drawnVerticesLabel = nullptr;
    _totalFrames = _frames = 0;
    _lastUpdate = new struct timeval;

    // paused ?
    _paused = false;

    // purge ?
    _purgeDirectorInNextLoop = false;

    _winSizeInPoints = Size::ZERO;

    _openGLView = nullptr;

    _contentScaleFactor = 1.0f;

    // scheduler
    _scheduler = new Scheduler();   //init()方法中new了Scheduler和ActionManager对象,但是Director的析构函数并没有直接delete,
    // action manager               //而是 CC_SAFE_RELEASE(_scheduler); CC_SAFE_RELEASE(_actionManager); 即调用了release()
    _actionManager = new ActionManager();
    _scheduler->scheduleUpdate(_actionManager,Scheduler::PRIORITY_SYSTEM,false);

    _eventDispatcher = new EventDispatcher();
    _eventAfterDraw = new EventCustom(EVENT_AFTER_DRAW);
    _eventAfterDraw->setUserData(this);
    _eventAfterVisit = new EventCustom(EVENT_AFTER_VISIT);
    _eventAfterVisit->setUserData(this);
    _eventAfterUpdate = new EventCustom(EVENT_AFTER_UPDATE);
    _eventAfterUpdate->setUserData(this);
    _eventProjectionChanged = new EventCustom(EVENT_PROJECTION_CHANGED);
    _eventProjectionChanged->setUserData(this);


    //init TextureCache
    initTextureCache();

    _renderer = new Renderer;

#if (CC_TARGET_PLATFORM != CC_PLATFORM_WINRT) && (CC_TARGET_PLATFORM != CC_PLATFORM_WP8)
    _console = new Console;
#endif
    return true;
}

可以看到,Director这个大管家初始化了 ActionManager 动作管理器 并将 _actionManager加到了定时器里

初始化了EventDispatcher EventCustom 等事件

初始化了纹理 和渲染器 Renderer

下面我们再看一下DisplayLinkDirector这个类

这是Director的实体类。

class DisplayLinkDirector : public Director
{
public:
    DisplayLinkDirector() 
        : _invalid(false)
    {}

    //
    // Overrides
    //
    virtual void mainLoop() override;
    virtual void setAnimationInterval(double value) override;
    virtual void startAnimation() override;
    virtual void stopAnimation() override;

protected:
    bool _invalid;
};

这个类实现了Director的几个关键的虚函数。

mainLoop这个是最主要的了,上面我们一再说逻辑循环 逻辑循环,其实都是指这个函数,所有的操作,动画,渲染,定时器都在这里驱动的。

游戏主循环里反复的调度 mainLoop来一帧一帧的实现游戏的各种动作,动画……. mainLoop来决定当前帧该执行什么,是否到时间执行等等。

void DisplayLinkDirector::mainLoop()
{
    if (_purgeDirectorInNextLoop)
    {
        _purgeDirectorInNextLoop = false;
        purgeDirector();
    }
    else if (! _invalid)
    {
        drawScene();
     
        // release the objects
        PoolManager::getInstance()->getCurrentPool()->clear();
    }
}

代码很简单,根据对 purgeDirectorInNextLoop 判断来决定mainLoop是否应该清除。

_invalid来决定 Director是否应该进行逻辑循环

这段代码很简单,主要操作都封闭到了 drawScene里面后面我们跟进drawScene来看看每个逻辑帧都干了些什么。

后面还有一个代码PoolManager::getInstance()->getCurrentPool()->clear(); 从命名上来看是做清除操作,应该是内存操作,每帧回收不用的引用对象应该是在这里触发的,我们在内存应用的章节再回过头来讨论这块。

下面看drawScene的代码

void Director::drawScene()
{
    // 计算帧之间的时间间隔,下面根据这个时间间隔来判断是否应该进行某某操作
    calculateDeltaTime();
    
    // skip one flame when _deltaTime equal to zero.
    if(_deltaTime < FLT_EPSILON)
    {
        return;
    }

    if (_openGLView)
    {
        _openGLView->pollInputEvents();
    }

    //Director没有暂停的情况下,更新定时器,分发 update后的消息
    if (! _paused)
    {
        _scheduler->update(_deltaTime);
        _eventDispatcher->dispatchEvent(_eventAfterUpdate);
    }
 //opengl清理
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    /*设置下个场景*/
    if (_nextScene)
    {
        setNextScene();
    }

    kmGLPushMatrix();

    // global identity matrix is needed... come on kazmath!
    kmMat4 identity;
    kmMat4Identity(&identity);

    // 渲染场景
    if (_runningScene)
    {
        _runningScene->visit(_renderer,identity,false);
        // 分发场景渲染后的消息 
        _eventDispatcher->dispatchEvent(_eventAfterVisit);
    }

    // 渲染notifications 结点,这个结点有什么用现在还看不太清楚,后面章节我们一定会摸清楚的
    if (_notificationNode)
    {
        _notificationNode->visit(_renderer,false);
    }

    if (_displayStats)// 渲染 FPS等帧频显示
    {
        showStats();
    }

    _renderer->render(); // 调用了渲染器的render方法,具体我们在分析Render类的时候再回过来看都干了些什么
    _eventDispatcher->dispatchEvent(_eventAfterDraw);

    kmGLPopMatrix();

    _totalFrames++;

    // swap buffers
    if (_openGLView)
    {
        _openGLView->swapBuffers();
    }

    if (_displayStats)
    {
        calculateMPF();
    }
}

到现在,我们完整的分析了Director类,了解了这个大管家都管理了哪些对象。下面我们做个总结。

Director主要管理了场景,四个事件的分发,渲染,Opengl对象,等

它主要是以场景为单位来控制游戏的逻辑帧,通过场景的切换来实现游戏中不同界面的变化。

其实 mainloop这个函数 调用 了drawscene来实现每一帧的逻辑主要是渲染逻辑。

上一章节,我们读到了application里面有一个run方法 ,在run方法里面有一个死循环,那个是游戏的主循环,在那个死循环里不断的调用 director->mainLoop这个就是在主游戏循环里不断的执行逻辑帧的操作.

下一节我们从最基本的开始分析,看一下 ref这个类cocos2d-x的内存管理机制。



版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


    本文实践自 RayWenderlich、Ali Hafizji 的文章《How To Create Dynamic Textures with CCRenderTexture in Cocos2D 2.X》,文中使用Cocos2D,我在这里使用Cocos2D-x 2.1.4进行学习和移植。在这篇文章,将会学习到如何创建实时纹理、如何用Gimp创建无缝拼接纹
Cocos-code-ide使用入门学习地点:杭州滨江邮箱:appdevzw@163.com微信公众号:HopToad 欢迎转载,转载标注出处:http://blog.csdn.netotbaron/article/details/424343991.  软件准备 下载地址:http://cn.cocos2d-x.org/download 2.  简介2.1         引用C
第一次開始用手游引擎挺激动!!!进入正题。下载资源1:从Cocos2D-x官网上下载,进入网页http://www.cocos2d-x.org/download,点击Cocos2d-x以下的Download  v3.0,保存到自定义的文件夹2:从python官网上下载。进入网页https://www.python.org/downloads/,我当前下载的是3.4.0(当前最新
    Cocos2d-x是一款强大的基于OpenGLES的跨平台游戏开发引擎,易学易用,支持多种智能移动平台。官网地址:http://cocos2d-x.org/当前版本:2.0    有很多的学习资料,在这里我只做为自己的笔记记录下来,错误之处还请指出。在VisualStudio2008平台的编译:1.下载当前稳
1.  来源 QuickV3sample项目中的2048样例游戏,以及最近《最强大脑》娱乐节目。将2048改造成一款挑战玩家对数字记忆的小游戏。邮箱:appdevzw@163.com微信公众号:HopToadAPK下载地址:http://download.csdn.net/detailotbaron/8446223源码下载地址:http://download.csdn.net/
   Cocos2d-x3.x已经支持使用CMake来进行构建了,这里尝试以QtCreatorIDE来进行CMake构建。Cocos2d-x3.X地址:https://github.com/cocos2d/cocos2d-x1.打开QtCreator,菜单栏→"打开文件或项目...",打开cocos2d-x目录下的CMakeLists.txt文件;2.弹出CMake向导,如下图所示:设置
 下载地址:链接:https://pan.baidu.com/s/1IkQsMU6NoERAAQLcCUMcXQ提取码:p1pb下载完成后,解压进入build目录使用vs2013打开工程设置平台工具集,打开设置界面设置: 点击开始编译等待编译结束编译成功在build文件下会出现一个新文件夹Debug.win32,里面就是编译
分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!http://www.captainbed.net前言上次用象棋演示了cocos2dx的基本用法,但是对cocos2dx并没有作深入的讨论,这次以超级马里奥的源代码为线索,我们一起来学习超级马里奥的实
1. 圆形音量button事实上作者的本意应该是叫做“电位计button”。可是我觉得它和我们的圆形音量button非常像,所以就这么叫它吧~先看效果:好了,不多解释,本篇到此为止。(旁白: 噗。就这样结束了?)啊才怪~我们来看看代码:[cpp] viewplaincopyprint?CCContro
原文链接:http://www.cnblogs.com/physwf/archive/2013/04/26/3043912.html为了进一步深入学习贯彻Cocos2d,我们将自己写一个场景类,但我们不会走的太远,凡是都要循序渐进,哪怕只前进一点点,那也至少是前进了,总比贪多嚼不烂一头雾水的好。在上一节中我们建
2019独角兽企业重金招聘Python工程师标准>>>cocos2d2.0之后加入了一种九宫格的实现,主要作用是用来拉伸图片,这样的好处在于保留图片四个角不变形的同时,对图片中间部分进行拉伸,来满足一些控件的自适应(PS: 比如包括按钮,对话框,最直观的形象就是ios里的短信气泡了),这就要求图
原文链接:http://www.cnblogs.com/linji/p/3599478.html1.环境和工具准备Win7VS2010/2012,至于2008v2版本之后似乎就不支持了。 2.安装pythonv.2.0版本之前是用vs模板创建工程的,到vs2.2之后就改用python创建了。到python官网下载版本2.7.5的,然后
环境:ubuntu14.04adt-bundle-linux-x86_64android-ndk-r9d-linux-x86_64cocos2d-x-3.0正式版apache-ant1.9.3python2.7(ubuntu自带)加入环境变量exportANDROID_SDK_ROOT=/home/yangming/adt-bundle-linux/sdkexportPATH=${PATH}:/$ANDROID_SDK_ROOTools/export
1开发背景游戏程序设计涉及了学科中的各个方面,鉴于目的在于学习与进步,本游戏《FlappyBird》采用了两个不同的开发方式来开发本款游戏,一类直接采用win32底层API来实现,另一类采用当前火热的cocos2d-x游戏引擎来开发本游戏。2需求分析2.1数据分析本项目要开发的是一款游
原文链接:http://www.cnblogs.com/linji/p/3599912.html//纯色色块控件(锚点默认左下角)CCLayerColor*ccc=CCLayerColor::create(ccc4(255,0,0,128),200,100);//渐变色块控件CCLayerGradient*ccc=CCLayerGradient::create(ccc4(255,0,0,
原文链接:http://www.cnblogs.com/linji/p/3599488.html//载入一张图片CCSprite*leftDoor=CCSprite::create("loading/door.png");leftDoor->setAnchorPoint(ccp(1,0.5));//设置锚点为右边中心点leftDoor->setPosition(ccp(240,160));/
为了答谢广大学员对智捷课堂以及关老师的支持,现购买51CTO学院关老师的Cocos2d-x课程之一可以送智捷课堂编写图书一本(专题可以送3本)。一、Cocos2d-x课程列表:1、Cocos2d-x入门与提高视频教程__Part22、Cocos2d-x数据持久化与网络通信__Part33、Cocos2d-x架构设计与性能优化内存优
Spawn让多个action同时执行。Spawn有多种不同的create方法,最终都调用了createWithTwoActions(FiniteTimeAction*action1,FiniteTimeAction*action2)方法。createWithTwoActions调用initWithTwoActions方法:对两个action变量初始化:_one=action1;_two=action2;如果两个a
需要环境:php,luajit.昨天在cygwin上安装php和luajit环境,这真特么是一个坑。建议不要用虚拟环境安装打包环境,否则可能会出现各种莫名问题。折腾了一下午,最终将环境转向linux。其中,luajit的安装脚本已经在quick-cocos2d-x-develop/bin/中,直接luajit_install.sh即可。我的lin
v3.0相对v2.2来说,最引人注意的。应该是对触摸层级的优化。和lambda回调函数的引入(嗯嗯,不枉我改了那么多类名。话说,每次cocos2dx大更新。总要改掉一堆类名函数名)。这些特性应该有不少人研究了,所以今天说点跟图片有关的东西。v3.0在载入图片方面也有了非常大改变,仅仅只是