精华内容
下载资源
问答
  • cocos2dx面试题干货】--2020年度最新cocos2dx面试干货(引擎篇 ) 大家好,我是Lampard~~ 经过春招一番艰苦奋战之后,我终于是进入了心仪的公司。 今天给大家分享一下我在之前精心准备的一套面试知识。 ...

                【cocos2dx面试题干货】--2021年度最新cocos2dx面试干货(引擎篇 )

     

      大家好,我是Lampard~~

      经过春招一番艰苦奋战之后,我终于是进入了心仪的公司。

      今天给大家分享一下我在之前精心准备的一套面试知识。

      由于我面试的岗位是cocos2dx的开发岗,今天就先给大家分享一下引擎方面的知识。

      本人亲测80%的引擎相关题目都是围绕着我总结出来的知识点提出的 。

     

      一.cocos的内存管理方式

    cocos是通过引用计数方式管理内存,主要通过两种方式实现


    1.手动管理内存

    当我们创建一个实例时,基类Ref里面有一个叫referenceCount的参数就会置1,它代表我们引用的次数,使用retain()函数

    可以使refernceCount+1release()函数会使referenceCount-1当这个参数减至0时会被引擎delete掉释放内存

     

    2.自动回收池 

    有手动就会有自动。我们在create()一个对象时,调用new函数创建对象并且还会利用autorelease()方法把该对象的指针加入自动回收池,主线程每一帧在Application::getInstance()->run()的过程中会调用 mainloop()方法

    mainloop()方法中会利用单例的PoolManager类getCurPool()获取当前的自动回收池,并调用自动回收池中的clear()方法,

    clear()方法里,会遍历移除所有与该自动回收池相关联的对象,并调用一次release()方法,如果这个对象没被调用且referenceCount被减至0就会被delete掉。若这个对象已经addChild到其他控件上呗引用的话,则referenceCount不为0,等其父节点被清理时再回收

     

    好处:

    1.无需手动的release()retain(),避免内存泄漏。

    2.在每一帧结束后对无用的对象进行自动处理内存回收,方便可靠。

     

    可优化的地方:

    1.我们的PoolManager管理的是一个_releasePoolStack(存储自动回收池的栈),一般情况下,每一帧结束后我们只是把当前的池子给清空,然后执行下一帧的操作。但是我们也应该考虑到释放池本身维护着一个将要执行释放操作的对象列表,如果在一帧之内生成了大量的autorelease对象,将会导致释放池性能下降。因此,在生成autorelease对象密集的区域(通常是循环中)的前后,我们最好可以手动创建并释放一个回收池。

    2.autorelease()只有在自动释放池被释放时才会进行一次释放操作,如果对象释放的次数超过了应有的次数,则这个错误在调用autorelease()时并不会被发现,只有当自动释放池被释放时(通常也就是游戏的每一帧结束时),游戏才会崩溃。在这种情况下,定位错误就变得十分困难了。因此,我们建议在开发过程中应该避免滥用autorelease(),只在工厂方法等不得不用的情况下使用,尽量以release()来释放对象引用。

     

    二.cocos的渲染机制

    3.x之前是通过调用每一个nodedraw方法来使用OpenGL ES代码进行渲染,3.x之后则使用了新的渲染机制,统一把所有需要渲染的node安放在一个队列中再进行自动批处理渲染。

    主线程每一帧在Application::getInstance()->run()的过程中会调用 mainloop()方法,mainloop()方法中会调用一次drawScene()方法

    方法名是drawScene,那么重点肯定就是对当前场景需要渲染的结点进行渲染。先清除渲染状态,然后调用render()方法。

    接下来我们看看render函数具体是怎么实现的:它首先是使用visit方法让需要被渲染的结点进行排序并插入到渲染队列CommandQueue中,然后再一起自动批处理进行渲染。

    我们接着看visit方法,首先它根据localZOrder使用sortAllChildren()来进行排序

    紧接着对localZOrder<0的结点进行递归渲染。

    然后是渲染本身结点,最后再递归渲染localZOrder>0的子节点。其本质就是按照(左,中,右)中序遍历进行渲染

    往下看每个结点的draw函数,我们可以发现,相比于2.x的版本,3.x之后没有直接在draw函数中进行渲染,而是把渲染命令压入到渲染对列中去,最后再回到render函数中进行进行自动批处理渲染

    void Sprite::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
    {
        // 判定纹理是否有效
        if (_texture == nullptr)
        {
            return;
        }
    
    #if CC_USE_CULLING
        // Don't calculate the culling if the transform was not updated
        auto visitingCamera = Camera::getVisitingCamera();
        auto defaultCamera = Camera::getDefaultCamera();
        if (visitingCamera == defaultCamera) {
            _insideBounds = ((flags & FLAGS_TRANSFORM_DIRTY) || visitingCamera->isViewProjectionUpdated()) ? renderer->checkVisibility(transform, _contentSize) : _insideBounds;
        }
        else
        {
            // XXX: this always return true since
            _insideBounds = renderer->checkVisibility(transform, _contentSize);
        }
    
        // 判定渲染的纹理是否在可见区域内
        if(_insideBounds)
    #endif
        {    
            _trianglesCommand.init(_globalZOrder,
                                   _texture,
                                   getGLProgramState(),
                                   _blendFunc,
                                   _polyInfo.triangles,
                                   transform,
                                   flags);
            // 将绘制命令添加到renderer绘制栈RenderQueue中
            renderer->addCommand(&_trianglesCommand);
        }
    }

    render中,对队列中需要渲染的结点根据其GlobalZorder进行排序,globalZOrder 是一个 float (不是 int的参数。这个值在 渲染器 中用来给 RenderCommand 排序。较低的值拥有较高的优先级。这意味着一个 globalZorder 为 -10的节点会比一个 globalZOrder 为 10 的节点优先绘制.globalZOrder 为 0 (默认值)的节点将会根据 Scene Graph 顺序绘制。

    然后再对队列中的渲染命令调用OpenGL的API进行渲染。自此完成了整个渲染流程。

    总的来说:

    导演类的mainLoop中会调用drawScene,在drawScene中会调用场景类的render,render中会递归执行节点类的visit,visit中会调用精灵类的draw,draw中会执行渲染类的addCommand。对所有节点执行完addCommand后,会执行渲染类的processRenderCommand,接下来执行渲染类的drawBatchedTriangles,最终在drawBatchedTriangles内会调用多个openGL API完成渲染。


    三.cocos的cache缓存区

    TextureCache:加载大纹理图如背景图片(pkm,png)

    Director::getInstance()->getTextureCache()->addImage(filename)  // 存入
    
    Texture2D *texture = Director::getInstance()->getTextureCache()->getTextureForKey(textureKeyName)  // 使用
    
    Director::getInstance()->getTextureCache()->removeUnusedTextures() // 清理没被引用的
    Director::getInstance()->getTextureCache()->removeAllTextures()  // 清理全部

    SpriteFrameCache.:加载碎的精灵帧图片,plist文件

    SpriteFrameCache *frameCache = SpriteFrameCache::getInstance() // 存入
    
    frameCache->addSpriteFramesWithFile("boy.plist", 具体某张图) // 参数二可不填
    
    auto frame_sp = Sprite::createWithSpriteFrameName("boy1.png") // 取出
    
    SpriteFrameCache::getInstance()->removeUnusedSpriteFrames() // 清理没用的
    SpriteFrameCache::getInstance()->removeSpriteFramesFromFile(const std::string &plist) // 清理某plist
    SpriteFrameCache::getInstance()->removeSpriteFramesFromTexture(cocos2d::Texture2D *texture) // 清理某图片

    AnimationCache:把像走路,奔跑等多次重复的动作加载进缓存中

    AnimationCache::getInstance():addAnimation(Animation *animation, const std::string& name) // 存入
    
    AnimationCache::getInstance():getAnimation(const std::string& name) // 取出
    
    void removeAnimation(const std::string& name) // 移除

    他们的作用都是把图片/动作进行预加载,cache首先会对每种缓存类型进行拆分成键值对(比如纹理则存纹理类型,精灵帧则存精灵帧类型,动画则存动画类型)

    然后利用Map容器(Map是通过键值对的形式存储数据)储存之后,再次使用该资源时,就可从内存中直接取出,从而避免IO造成的卡顿现象

    顺带一提的是,纹理缓存和精灵帧缓存之间的区别是如果精灵帧缓存在缓存区中找不到想要的图片时,它会报null,而TextureCache则会在系统路径中查找该图,精灵帧缓存是基于纹理缓存再进行的封装。

    出于安全角度,建议的释放顺序是:动画缓存 先于 精灵帧缓存 先于 纹理缓存

     

    四.SpriteBatchNode精灵批处理类

    SpriteBatchNode* spriteBatchNode=  SpriteBatchNode::create();

    spriteBatchNode.addchild(纹理);

    对同一张纹理图进行多次重复的绘制,如子弹,粒子。而不用每一个粒子分开绘制,降低渲染批次从而提高效率。也就是说引擎只需要对spriteBatchNode这个对象进行渲染而不需要分开多次对不同精灵进行渲染。

    在3.0之前,SpriteBatchNode是一个很好的优化游戏方式,然而到了3.0版本之后,由于有了新的渲染系统机制,我们将不再需要甚至不推荐再使用这个类。

    限制

    Sprite 对象的孩子只能是 Sprite (否则,Cocos2d-x 会触发断言)

    •  Sprite 的父节点是 SpriteBactchNode 时,不能添加 ParticleSystem 作为 Sprite的子节点。
    • 这将导致当 Sprite 的父节点是 SpriteBatchNode 时,不能使用 ParallaxNode
    • 所有的 Sprite 对象必须共享相同的纹理ID (否则,Cocos2d-x 会触发断言)
    • Sprite 对象使用 SpriteBatchNode 的混合函数和着色器。

    v2.2 和 v3.0 最大的区别在于:

    • Sprite 对象可以有不同的纹理ID。
    • Sprite 对象可以有不同种类的 Node 作为子节点,包括 ParticleSystem
    • Sprite 对象可以有不同的混合函数和不同的着色器。

    但是如果你这么做,渲染器 可能无法对它所有的子节点进行批处理(性能较低)。但是游戏仍然可以正常运行,不会触发任何断言。

    优化

    • 保持将所有的精灵放在一张大的 spritesheet 中。
    • 使用相同的混合函数(使用默认)
    • 使用相同的着色器(使用默认)
    • 不要将精灵添加到 SpriteBatchNode

     

    五.cocos2d-x程序的开始与结束流程

    我们知道,无论是cocosluacocos2dx,还是cocosCreator,程序总是从AppDelegatedirector中调用mainloop进入主循环开始的。那么cocos引擎中是如何结束整个游戏进程的呢?

    在正个mainloop过程中,引擎首先会进行一次是否结束游戏进程的判断操作,那我们看看这个参数是什么时候被赋值的

    我们查询后发现,只有导演类调用end()函数的时候才会把该值赋为true,所以在这里我们知道了第一个结束进程的方式,就是手动调用导演类的end函数

    那么有没有是引擎本身调用end函数的时候呢?我们查找到,当场景栈全部pop出来,没有场景在场景栈中的时候,就会执行导演类的end函数,之前在学习cocos的时候我们就知道场景仿佛就是一个舞台,layer是一个画布,现在舞台都没有了那当然就执行结束流程了呀。

    我们回到mainLoop中,看到cocos是这样执行结束回收流程的:1.暂停计时器和事件派发器, 2.回收当前运行场景,3.销毁各种缓存区,4.对openGL执行end回收函数

    (下图为OpenGLend函数)

    CCEGLView* CCEGLView::sharedOpenGLView() 
    { 
        static CCEGLView* s_pEglView = NULL; 
        if (s_pEglView == NULL) 
        { 
            s_pEglView = new CCEGLView(); 
        } 
        return s_pEglView; 
    } 
    ... 
     
    // openglview 结束方法 
    void CCEGLView::end() 
    { 
        /* Exits from GLFW */ 
        glfwTerminate(); 
        delete this; 
        exit(0); 
    } 

    cocos2d-x 程序的结束流程

    程序运行时期,由 mainLoop 方法维持运行着游戏之内的各个逻辑,当在弹出最后一个场景,或者直接调用 CCDirector::end(); 方法后,触发游戏的清理工作,执行 purgeDirector 方法,从而结束了 CCEGLView(不同平台不同封装,PC使用OpenGl封装,移动终端封装的为 OpenGl ES) 的运行,调用其 end() 方法,从而直接执行 exit(0); 退出程序进程,从而结束了整个程序的运行。(Android 平台的 end() 方法内部通过Jni 方法 terminateProcessJNI(); 调用 Java 实现的功能,其功能一样,直接结束了当前运行的进程)

     

    六.如何构建序列帧动画

    之前我曾今分享过 一篇如何手动实现序列帧动画的博客

    创建序列帧动画方法

    大致的思路是:1.先把所用到的plist文件存入精灵帧缓存区

    2.循环遍历所需帧的图片,把一帧一帧的图片加载进实例化的Animation动作中

    3.把这个Animation作为参数,生成一个Animate动画。此时就已经生成出一个可播放的序列帧动画了。

     

    七.cocos2dx的屏幕适配方案

    常规做法:

    pEGLView::sharedOpenGLView()->setDesignResolutionSize()

    通过导演类调用OpenGl函数 设置屏幕的配置方案

    里面接五个参数

    KResolutionExactFit:拉伸变长宽比,全屏显示

    kResolutionFixedHeight:不变长宽比(保持传入的设计分辨率高度不变,根据屏幕分辨率修正设计分辨率的宽度),全屏但是有一部分宽度不显示

    kResolutionFixedWidth:不变长宽比(保持传入的设计分辨率宽度不变,根据屏幕分辨率修正设计分辨率的高度),全屏但是有一部分高度不显示

    KResolutionNoBorder:不变长宽比(取Max(设计高度 / 实际高度, 设计宽度 / 实际宽度)的值作为缩放比例),全屏但是有一部分不显示

    KResolutionShowAll:不变长宽比,有黑边

    我们看看前辈们测试的demo:

     

    以为这就已经问没解决问题了?

    NONONO,对于以前那些老机子来说,确实可以解决问题了

    但是现在手机换代越来越快,市面上推出了许许多多水滴屏,挖孔屏,刘海屏等奇奇怪怪的屏幕

    这个时候我们就得更灵活的去处理问题了,不然你好好的一个充值按钮被刘海给挡住了,那直接举双手GG。

    我们可以采取以下的方法解决问题:

    1.从设计开始避免,把重要的信息,按钮不要摆放到太靠边的位置。

    我们之后做的适配都是为了解决因为刘海屏,水滴屏而造成的游戏体验不好或者影响游戏操作的问题。那么既然如此为什么不从设计开始避免这些问题的出现呢?

    2.一般采用下图这种适配方案:

     

    • 1.IOS苹果手机因为机型类型比较少,所以游戏正文所占屏幕区域的宽高比(safeArea)我们可以直接配置,比如["iPhone Xs"] = 2、["iPhone Xs Max"] = 2。
    • 2.安卓机器机型比较多而杂,无法通过配置写死safeArea,所以通过代码取得,指的一提的是安卓9.0以下的时候没有统一的获取方式,华为 oppo Vivo 小米需要各自厂商不同的接口分别获取,安卓9.0以上可以统一获取。(具体可自行百度或者参考AppActivity.java)
      取得safeArea以后:
      local safeWidth = realHeight * safeArea (游戏正文宽度)
      local offset = (realWidth - safeWidth)/2 (左右刘海宽度)
      g_UIMainSceneLayer:setPositionX(offset) (将所有界面的父节点 右移offset)
      local safeSize = cc.size(safeWidth,realHeight)
      g_UIMainSceneLayer:setContentSize(safeSize) (设置contentSize为正文大小)
      如果界面不需要适配,需要全屏显示。比如有的背景界面需要在刘海区域显示,就需要将界面左移回来,并设置contentSize大小为realSize

     

    八.cocos事件分发机制

    • 事件源:场景中的对象,每个Node节点都可以触发事件
    • 事件监听者:监听器EventListener,负责监控对象是否触发某个事件, 如果触发就执行相应的回调函数。
    • 事件分发者:事件分发器EventDispatcher,负责分配事件监听器给对象。在游戏启动时,就会创建一个默认的EventDispatcher对象

      事件类型

    enum class Type
    {
        TOUCH,          // 触摸事件,单点触摸,多点触摸
        KEYBOARD,       // 键盘事件(按下,返回,弹出)
        ACCELERATION,   // 加速器事件(x,y,z轴的倾斜角度来判断加速状态)
        MOUSE,          // 鼠标事件
        FOCUS,          // 焦点事件
        CUSTOM          // 自定义事件
    };

    事件监听器类型

    enum class Type
    {
        UNKNOWN,            // 未知的事件监听器
        TOUCH_ONE_BY_ONE,   // 单点触摸事件监听器
        TOUCH_ALL_AT_ONCE,  // 多点触摸事件监听器
        KEYBOARD,           // 键盘事件监听器
        MOUSE,              // 鼠标事件监听器
        ACCELERATION,       // 加速器事件监听器
        FOCUS,              // 焦点事件监听器
        CUSTOM              // 自定义事件监听器
    };

    关于事件监听器的优先权

    通过 addEventListenerWithSceneGraphPriority 添加的监听器,优先权为0。

    通过 addEventListenerWithFixedPriority 添加的监听器,可以自定义优先权,但不能为0。

    优先级越低,越先响应事件。

    如果优先级相同,则上层的(z轴)先接收触摸事件

     

    当使用场景图优先级时,实际上是在树的上方向后移动。如果一个事件被触发,H会看一眼,要么吞下它,要么让它传递给I

    同样的事情,我要么消耗它要么让它传递给G,以此类推,先找监听器,再找Z轴最大的node结点,直到事件被它吞没或者没有得到回应,则整个事件触发机制结束

     

    九.cocos调度器schedule

     Cocos2d-Lua 引擎中的调度器是用来周期执行某个函数或延时执行某个函数的。功能类似于定时触发器,但它又与游戏紧密结合。

    schedule调度器利用了timer类来保存了调度任务的 时间线,重复次数,事件间隔,延迟等数据。timer把相关信息以结构体的形式存进了双向链表_hashForTimers

    每帧更新后Timer做事件累加,根据时间线去触发或者取消更新回调。

    每帧更新每帧更新的回调放在 _hashForUpdates结构中以target作为key,同时根据优先级放在不同的hash表中。
    
    自定义更新更新回调放在_hashForTimers hash表中,以target作为key.

    每帧开始绘制之前执行Scheduler::update(float dt)

    在里面遍历hash表,执行update更新回调,完成后移出。

    按照优先级<0 ==0 >0 自定义更新的顺序遍历执行。

     

    使用方法:Cocos2d-Lua 中的调度器分两种:全局调度器和节点调度器

    全局调度器模块提供了三种调度器以满足各种需求:

    (1)全局帧调度器: schduleUpdateGlobal(listener)

     顾名思义,全局帧调度器是游戏的每一帧都会触发的调度器。主要是在碰撞检测等每一帧都需要计算的地方。全局帧调度器不依赖任何场景,因此可以在整个游戏范围内实现较为精确的全局计时。

    
    示例代码:
    
    lcoal scheduler = require(cc.PACKAGE_NAME..".scheduler")
    
    local function onInterval(dt)
    
    print("update")
    
    end
    
    scheduler.scheduleUpdateGlobal(onInterval)
    
    回调函数onInterval的参数dt,是两次调度之间的时间间隔。

    (2)全局自定义调度器:schduleGlobal(listener,interval)

    全局帧调度器是全局自定义调度器的特例,自定义调度器可以指定调度时间,提供更高的灵活性

    由于引擎的调度机制,自定义时间间隔必须大于两帧的间隔,否则两帧内的多次调用会被合并成一次调用。所以自定义时间间隔应在1/60s以上(引擎默认每秒刷新60帧)

    示例代码:
    
    lcoal scheduler = require(cc.PACKAGE_NAME..".scheduler")
    
    local function onInterval(dt)
    
    print("Custom")
    
    end
    
    scheduler.scheduleGlobal(onInterval,0.5)
    
    每隔0.5秒控制台输出信息。

    (3)全局延时调度器:performWithDelayGlobal(listener,time)

     若在游戏中某些场合,只想实现一个单次的延时调用,就需要延迟调度器。scheduler.performWithDelayGlobal()会在等待指定时间后执行一次回调函数,然后自动取消该scheduler

    示例代码:
    
    lcoal scheduler = require(cc.PACKAGE_NAME..".scheduler")
    
    local function onInterval(dt)
    
    print("once")
    
    end
    
    scheduler.performWithDelayGlobal(onInterval,0.5)
    
    在控制台只会看到一次输出。

    节点调度器

    NodeCocos2d-Lua引擎中的基础类,它封装了很多基础方法与属性,其中调度器就是Node提供的方法之一。Node中的调度器只能在Node中使用,Node负责管理调度器的生命周期,当Node销毁的时候,会自动注销节点名下的所有调度器

    1、节点自定义调度器

    由于引擎的调度机制,自定义时间间隔必须大于两帧的间隔,否则两帧内的多次调用会被合并成一次调用。所以自定义时间间隔应在0.1s以上(引擎默认每秒刷新60帧)
    
    节点自定义调度器示例代码:
    
    self:schdule(function() print ("schdule") end,1.0)
    
    可以在Scene或Layer中调用上面的代码。

    2、节点延时调度器

    延时调度器等待指定的时间后执行一次回调函数,示例代码:
    
    self:performWithDelay(function() print("performWithDelay") end , 1.0)

     

    十.如何对游戏的卡顿问题进行优化

    造成卡顿也就是掉帧的原因主要是CPU计算量和GPU渲染压力过大,因而需要对资源进行合适的处理。

    首先对于图片方面:

    1.对资源进行预加载到缓存区避免游戏时出现卡顿

    2.使用TexturePacket/cocoStdio打包图片,多次渲染,重复生成的精灵打包在同一张纹理中,利用3.x的渲染机制对UI进行自动批处理渲染

    3.优化纹理大小、格式RGB8888(32位) -> RGB4444(16位))

    4.支持pvr图片的情况下,使用pvr格式的图片

    5.. 不要使用超大的纹理

    然后是对于音乐方面:

    1.对背景音乐进行裁剪,通过重复播放的形式节省内存

    2.使用的音乐应该要经过压缩,通过降低音质的方式来减少占用的内存

    最后是对于代码方面:

    1.写算法时,不要造成内存泄漏,使用算法尽量要用最优方案

    2.对于重复使用的纹理,精灵,动作要加载进缓存区,避免重复的删除创建

    3.已经没用的场景和精灵要及时的删除

     

    十一.cocos使用httpClient发送请求

    游戏开发的过程中难免需要和服务端进行数据交互,我们可以利用cocos给我们封装好的httpClient类来进行数据的交互。

    httpClient是一个单例的类,我们可以通过HttpClient:getInstrance()来获取这个单例。

    数据的交互分为请求request和返回response两个部分,作为客户端来说我们首先要把玩家操作的数据上传给服务端,然后再根据服务端发回来的结果进行一系列操作。

    (1)request请求

     coco2dx中我们可以直接new HttpRequest()来创造一个http请求,在quick中我们可以createHTTPRequest来实例一个request类。

    request类继承与Ref,同样受到cocos内存管理机制的管理。

    作为请求我们需要几个比较重要的信息:要连接的URL,回协议时的回调,与http交互的方式,自身的tag标签等等

     我们可以看看request类中的源码是怎么样对这些参数进行设置的

        inline void setRequestType(Type type)
        {
            _requestType = type;
        };
    
        inline void setUrl(const char* url)
        {
            _url = url;
        };
    
        inline void setTag(const char* tag)
        {
            _tag = tag;
        };
    
        inline void setUrl(const char* url)
        {
            _url = url;
        };
    
        inline void setResponseCallback(const ccHttpRequestCallback& callback)
        {
            _pCallback = callback;
        }

    注意,我们常用的TYPE是GET和POST,其中GET是把请求的数据跟在网址后面以 ? 分割 URL 和传输数据,多个参数用 & 连接,而POST则url只填网址,把请求的指令放在setRequestData()中 

    对于GET和POST的具体区别可以看看这个文章:

    GET和POST的区别可以看看这个文章

    当设置完成后我们就可以让httpClient类来发送这个请求。与服务端链接成功之后,交互的信息会封装在response类中随着回调函数返回来。

     

     (2)response回复

      这个类十分简单,我们首先来看一看这个类中究竟有什么元素:

        HttpRequest*        _pHttpRequest;  /// the corresponding HttpRequest pointer who leads to this response 
        bool                _succeed;       /// to indecate if the http reqeust is successful simply
        std::vector<char>   _responseData;  /// the returned raw data. You can also dump it as a string
        std::vector<char>   _responseHeader;  /// the returned raw header data. You can also dump it as a string
        long                _responseCode;    /// the status code returned from libcurl, e.g. 200, 404
        std::string         _errorBuffer;   /// if _responseCode != 200, please read _errorBuffer to find the reason 

      其实就是请求的指针,是否成功,返回的数据,返回码(链接失败发404),和报错的数据而已

      所有我们只需要在回调函数中,对是否请求成功做出判断,就可以输出错误日志或者执行之后的操作了。

     下面给大家看一个例子:

    auto request = new HttpRequest();
    request->setUrl("http://www.baidu.com");    // 设置请求连接的Url
    request->setReqeustType(HttpRequest::Type::GET);    // 设置发送数据的模式:get/post/put/delete
    request->setReqeustCallback(CC_CALLBACK_2(requestCallback, this));    // 设置连接成功时候的回调
    HttpClient:getInstrance()->send(request);    // 发送这个请求
    
    void requestCallback(HttpClient *sender, HttpResponse *response)
    {
        if (response->isSucceed())
        {
            cout << "error msg:" << response->getErrorBuffer() << endl;
            return;
        } 
        
        vector<char> *buffer = response->getResponseData();    // 请求服务端得到的数据
        long statusCode = response->getResponseCode();    // 返回码
        
        /*
            do callBack
        */
    }

    至此就完成一个利用http协议和服务端交互数据的流程。

     

    十二.cocos使用webSocket发送请求

    WebSocketHTML5开始提供的一种浏览器与服务器间进行全双工通讯的网络技术。在WebSocket API中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。

    Cocos2d-x引擎集成libwebsockets,并在libwebsockets的客户端API基础上封装了一层易用的接口,使得引擎在C++, JS, Lua层都能方便的使用WebSocket来进行游戏网络通讯。

    构建一个webSocket的过程如下:

    • 创建并初始化一个webSocket
    •  与服务端进行连接
    • 监听服务端的发送的数据&向服务端发送数据
    • 关闭socket连接

    (1) 创建并初始化一个webSocket

    cocos2d::network::WebSocket* _wsiSendText = new network::WebSocket(); 

    (2) 与服务端进行连接

     第一个参数是委托,传递自身的*this,第二个参数是要连接的URL

    _wsiSendText->init(*this, "ws://echo.websocket.org") 

    如果连接成功,WebSocket就会调用onOpen,告诉调用者,客户端到服务器的通讯链路已经成功建立,可以收发消息了。此时自身对的state会处在CONNECTING状态。

    如果连接失败,会触发onError函数,并返回一个errorCodeerrorCode的类型有三种:

        enum class ErrorCode
        {
            TIME_OUT,           /** &lt; value 0 */
            CONNECTION_FAILURE, /** &lt; value 1 */
            UNKNOWN,            /** &lt; value 2 */
        };

     此时我们可以选择重连或者断开连接报错。

    (3)监听服务端的发送的数据&向服务端发送数据

    network::WebSocket::Data对象存储客户端接收到的数据, isBinary属性用来判断数据是二进制还是文本,len说明数据长度,bytes指向数据

    客户端依靠onMessage来监听服务端发送的数据:

    void WebSocketTestLayer::onMessage(network::WebSocket* ws, const network::WebSocket::Data& data) {
         if (!data.isBinary){ 
            _sendTextTimes++;
            char times[100] = {0};
            sprintf(times, "%d", _sendTextTimes);
            std::string textStr = std::string("response text msg: ")+data.bytes+", "+times;         
            log("%s", textStr.c_str());
            _sendTextStatus->setString(textStr.c_str());
    } } 

    客户端通过send向服务端发送数据: send有文本和二进制两种模式

    _wsiSendText->send("Hello WebSocket, I'm a text message."); 
    _wsiSendBinary->send((unsigned char*)buf, sizeof(buf)); 

    (4)主动关闭WebSocket

    这是让整个流程变得完整的关键步骤, 当某个WebSocket的通讯不再使用的时候,我们必须手动关闭这个WebSocket与服务器的连接。close会触发onClose消息,而后onClose里面,我们释放内存

    wsSendText:close() 

     至此就完成一个利用WebSocket协议和服务端交互数据的流程。

     

    十三.cocos包体的压缩

    对于上线 项目来说安装包每大一M都是钱啊!所以对包体要进行适当的压缩:删除没有用到的引擎代码块,对图片以及声音资源进行压缩,尽量使用系统的字库。采用分包下载的方式,将游戏资源进行拆分,等玩家进入游戏后进行二次下载。

     

    十四.cocos的数据存储

    Userdefault:本质是一颗XML文件,是cocos提供的方案优点时cocos自带的存储方案,调用比较方便缺点:都要遍历整个文件,效率不高&&不没有数据类型的安全

    SQList:轻量的嵌入式数据库,可高速且安全的在本地存储数据。

    FileUtils:用文件存储,比较麻烦和效率低

     

    十五.中文乱码怎么解决

    1.在Vs2017中另存项目,找到无签名的UTF-8进行储存

    2.对于一些系统需要的字体logo,使用Plist文件把字体当作精灵贴图上去

    3.先写一个XML文件,里面存储着所使用的字体,当需要调用时直接再XML文件中寻找

    Dictionary* strings = Dictionary::createWithContentsOfFile("string.xml");
    const char * str;
     str = ((String *)strings->objectForKey("menulogo"))->getCString();

     

    十六.Cocos2d-x中所使用的设计模式

    单例模式Dictor,OpenGl,cache,userfault等只需要一个实例

    单例模式的实现方式:

    饿汉模式

       在类中声明并实现了对象,如果调用getInstance则返回这个对象,立刻被加载,如果没有使用到会造成内存的浪费

    懒汉模式

    在类中声明了对象(但是还没有实例化),在调用getInstance才对其调用进行实例化

    单例模式好处:只允许创建一个对象,因此节省内存,加快对象访问速度,操作方便,这样就 防止其它对象对自己的实例化,确保所有的对象都访问一个实例避免对共享资源的多重占用

    单例模式坏处:就是不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。
     

    工厂模式基类只定义接口(规定生产什么产品),由子类来具体实现。对于需求量大的类这样做简化代码,方便调用

    管理者模式:如三个cache,对于体积大又要重复使用的数据,这样做可以避免多次加载 

    观察者模式: 指被观察者含有一个数组,里边存放了所有观察者的引用,在被观察者的状态发生改变的时候,通过调用观察者的

    函数来通知观察者(事件监听),实现了信息的传递。如血量变化。

     

    十七.场景切换的内存处理过程是什么?

    一般情况下先构建新场景,然后显示新场景,然后释放旧场景。

    1、如果没有切换效果,则为B的ctor(),A的onExit(),B的onEnter()  

    2、如果有切换效果,则为B的ctor(),B的onEnter(),A的onExit()  

     

    十八.cocos2d 3.x的新特性

    1.使用了新的渲染机制(上述一)

    2.使用了C++11的新特性:如auto关键字,Lamdar表达式等(详见2020c++面试题)

    3.去除了ObjectC模式,删除了CC前缀

     

    OK,以上就是我呕心沥血总结出来的引擎常见的面试题

    如果对大家有帮助记得点赞呀,谢谢大家 !


     


     

    展开全文
  • cocos2dx面试题

    2014-08-29 18:16:21
    1,阐述cocos2d-x 中CCScene CCLayer CCSprite CCNode CCScene: CCScene是app工作流程上独立块,一个app可能拥有多个scene,但是在任何时候只能有一个是激活状态的。一个CCScene对象由一个或多个...

    1,阐述cocos2d-x 中CCScene CCLayer CCSprite CCNode

    CCScene:

    CCScene是app工作流程上独立块,一个app可能拥有多个scene,但是在任何时候只能有一个是激活状态的。一个CCScene对象由一个或多个CCLayer组成,layer之间是前后相连的。Layer提供了scene的外观和行为。通常的用法是直接用一个或多个layer实例化一个scene

    CCScene的子类CCTrasitionScene实现移动transitions,提供两个scene之间的转移效果,由于scene是CCNode的子类,所以scene可以手工或者用aciton来转变坐标。所有层和精灵都是他的(子节点)children。

    CCScene的4个基本方法:

    runWithScene(运行画面),

    replaceScene(替换场景 例如从主菜单进入游戏界面),

    pushScene(暂停界面),

    popScene(从暂停的界面还原到游戏界面)

     

    Layers

    CCLayer同样是CCNode的子类,通常用addChild方法添加子节点。

    CCLayer对象定义了可描绘的区域,定义了描绘的规则。CCLayer可以实现半透明的效果,

    层的事件相应机制 : 最外层最先接受到事件(屏幕触碰),最后是底层,如果在某层处理了该事件,则后面的层不会在接受到事件信号

    Sprites
    cocos2dsprite对象就是一个可以移动、选择、伸缩、动画的2d图形,CCSprite对象的子成员中可以包含其它的CCSprite 对象。当CCSprite 对象转换坐标系的时候,它所包含的CCSprite 对象也会转换转换坐标系。sprites CCNode 的子类所以他们也可以使用actions来转换坐标. See Actions for more detail about actions.

     

    CCNode是场景、层、菜单、精灵等所有节点的父类,它是一个抽象类,没有可视化表示形式,定义了所有node共有的属性和方法。

    2,说一下CCAction和CCActionMessager

    CCAction是动作的基类,主要使用CCFiniteTimeAction有限次动作执行,就是按时间顺序执行一系列动作,执行完后动作结束;

    CCFiniteTimeAction又分为CCActionInstanse(瞬时动作的基类)和CCActionInterval(延时动作的基类)。CCActionInstanse:没什么特别,跟CCActionInterval主要区别是没有执行过程,动作瞬间就执行完成了;CCActionInterval:执行需要一定的时间(或者说一个过程)。我们用的最多的就是延时动作,下面对它进行单独介绍。

     

    CCActionMessage是管理所有Action的单例,一般情况下并不直接使用这个单例,而是使用CCNode的接口,但是假如你想操作的目标不是CCNode的子类或者你想暂停/恢复行动就要使用到CCActionMessager

     

    3,你常用的cocos2d-x工具

    TiledMap (地图编辑器)ParticleEditor粒子编辑器)cocosBuilder(可视化编辑)Texture Packer(图片组合工具)等

     

    4,简述:CCDirector CCEGLViewCCEGLViewProtocol

    CCDirectorsingleton模式的共享的对象。它知道当前哪个scene是激活。 CCDirectorstack的方式处理scenes的调用(当另一个scene进入的时候,暂停当前的scene,完成之后再返回原来的 scene),CCDirector 负责更换CCScene, CCLayer push的时候,更换或结束当前的scene。另外:CCDirector 负责初始化OpenGL ES

    作用:

    1.访问和改变场景

    2.访问cocos2d的配置细节

    3.访问视图,(openGL, UIView, UIWindow)

    4.暂停,恢复和结束游戏

    5.在UIKit和OpenGL之间转换坐标

    CCEGLView是CCEGLViewProtocol的子类,是用于屏幕适配(这个问题还没全解决啊)

     

     

     

    5,简述CCSpriteframeCache CCSpriteBatchNode,并说出CCNode,CCSprite是如何实现绘制的?

    CCSpriteFrameCache 缓存了所有CCSpriteFrame. 可以一下方式获取特定frame并设定给Sprite. 前提是文件已经缓存

    CCSpriteBatchNode 中的所有CCSprite只会被渲染1次,因此可以提高游戏的FPS。

    限制:加入到CCSpriteBatchNode 中的CCSprite必须使用同一张纹理图。

    比如游戏中的子弹 就很适合用它,因为子弹都是一个样子。通过TexturePacker生成的纹理图也适合使用它。

    (第二问不会)

    6,cocos2d-x的屏幕适配解决方案

    Cocos2d-x2.0.4之后

    pEGLView->setDesignResolutionSize(480, 320, kResolutionNoBorder);第三个参数,找到定义:

    讲得很清楚了:
    kResolutionExactFit
    :会靠拉伸来填满屏幕,本例来说背景图会变形来填充屏幕,因为1024:768=1.3, 480:320=1.5,宽高比不同,图片也就无法等比缩放来填满屏幕,只能变形了。
    kResolutionNoBorder: 看不到黑边,实际就是宽高等比缩放,但缩放比例取宽比和高比之中大的那一个。
    kResolutionShowAll:全部显示,可以理解为保证内容都显示在屏幕之内,实际也是宽高等比缩放,但缩放比例取宽比和高比之中小的那一个。

    一般来说,我们希望设计时一屏的内容,用户在实际设备上也能在一屏内看到,拿本例来说,1024x768分辨率时,右下角的按钮却跑到屏幕外去了。看完上面的分析,你应该知道如何解决了: 对了,改变pEGLView->setDesignResolutionSize(480, 320, kResolutionNoBorder);第三个参数为kResolutionShowAll。

     

    7,cocos2d-x聊天的实现,对话框 字符集 字体描边 输入法

     

     

    8,cocos2d-x游戏储存

    CCUserDefault和SQList

    CCUserDefalt存在的的问题

    1.没有记录和表的概念

    你会发现,如果要设置多存档,必须自己操作,而且代码会变得复杂,容易出错。

    对于简单的游戏可以使用CCUserDefalt,但是对于复杂游戏,可以考虑使用SQLite。

    2.没有数据类型安全

    比如,如果你错写把一个Integer按Bool读取,是没有错误提示的

    3.没有存档数据完整性的校验

    我们找到之前的存档记录,用CCUserDefault::getXMLFilePath()可以获得存档位置,打开它

     

     

    9,cocos2d-x内存管理

    cocos2d-x最初移植自cocos2d的objective C版本。因此,在内存管理上,使用了和NSObject类似的引用计数器方法,相关接口放置在CCObject类中。

    引用计数器——手动管理内存

    CCObject的及其子类的对象在创建时,引用计数自动设置为1。之后每次调用retain,引用计数+1。每次调用release,引用计数-1;若引用计数=0,则直接delete this。

    retain是在指针传递和赋值时使用的,他的含义是表示拥有。这经常用在指针赋值上。

    自动释放池——自动管理内存

    对于使用autorelease的对象,不必管它,每帧结束后会自动释放。

    CCNode节点管理

    cocos2d-x使用节点组成一棵树,渲染的时候要遍历这棵树。CCNode是所有节点类的父类,他内部使用了一个CCArray对象管理他的所有子节点,当对象被添加为子节点时,实际上是被添加到CCArray对象中,同时会调用这个对象的retain方法。同理,从CCArray中移除时,也会调用release方法。

    静态工厂

    cocos2d-x中存在大量的静态工厂方法,这些方法中,全都对this指针调用了autorelease函数。

    cache机制类


    cache内部也使用了ratainrelease方法,防止这些资源被释放掉。

    使用这些cache,我们可以保存预加载的一些资源,在方便的时候调用它,去绑定给一些对象。注意,这些cache在场景切换时,不会自动删除,需要手动调用purgeXXXX方法,进行清理。

     

     

    10,用cocos2d-x绘制一个三角形,并计算面积命名

     

    11,UI不能模态解决方案

    展开全文
  • Cocos2dx面试题》 版本 作者 参与者 完成日期 备注 Cocos2dx_JobView_V01_1.0 严立钻   2018.08.22 ...

    《Cocos2dx面试题》

    版本

    作者

    参与者

    完成日期

    备注

    Cocos2dx_JobView_V01_1.0

    严立钻

     

    2018.08.22

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    ##《Cocos2dx面试题》发布说明:

    ++++“Cocos2dx”是2014年比较流行的2D游戏引擎,当然也有3D版本,最近一直在做Unity3d相关的工作,所以对于Cocos2dx没有特别关注,但是作为一款优秀的游戏引擎,还是值得我们参考学习的;

    ++++“Cocos2dx面试题”:不仅仅包含Cocos2dx内容,还包括相关C++、Lua相关知识点;通过这篇博文,让大家熟悉一下Cocos2dx面试相关内容;

     

     

     

    ##《Unity面试题》目录:

    #第一篇:一场模拟面试

    #第二篇:Cocos2dx和C++知识点

     

     

     

     

     

     

    #第一篇:一场模拟面试

    #第一篇:一场模拟面试

    #第一篇:一场模拟面试

    ++++立钻哥哥:由于整理Cocos2dx的时间比较仓促,也没有特别在意章节排版,直接利用一场模拟面试来揭开Cocos2dx剖析之路;

    ++++A.1、请列举标准C/C++的基本变量类型(例如:int),以及它们的字节长度(2分)

    ++++A.2、请用#define语句完成以下需求(4分)

    ++++A.3、请计算sizeof的值(5分)

    ++++A.4、在VC6下定义如下结构(4分)

    ++++A.5、头文件中的ifndef/define/endif 干什么用?(2分)

    ++++A.6、简述进程和线程的区别?(2分)

    ++++A.7、多线程编程时,线程间同步的方法有哪些?(2分)

    ++++A.8、#include<filename.h>和#include “filename.h”有什么区别?(2分)

    ++++A.9、有关内存的思考题?(8分)

    ++++A.10、请写出下面代码的输出结果?(8分)

    ++++A.11、请写出下面代码的输出结果?(8分)

    ++++A.12、下面一段代码会产生内存泄露,请问如何修改能避免内存泄露? 并简述理由?(8分)

    ++++A.13、编写strcpy()函数?(10分)

    ++++A.14、如下两种写法有什么区别?(5分)

    ++++A.15、关键字static在C语言中的作用?(5分)

    ++++A.16、C++是安全类型的语言吗?(2分)

    ++++A.17、一个空类的大小,并解释?(2分)

    ++++A.18、面向对象与面向过程?(2分)

    ++++A.19、引用与指针?(2分)

    ++++A.20、多态?(2分)

    ++++A.21、深度优先遍历与广度优先遍历?(2分)

    ++++A.22、内存对齐问题?(2分)

    ++++A.23、写一个链表逆序?(2分)

    ++++A.24、写一个根据概率随机掉装备的函数?(2分)

    ++++A.25、四人过桥问题?(2分)

    ++++A.26、输入任意四个0~9中的数,通过+-*/()运算得到24,写算法或伪代码?

     

     

     

     

    ##A.1、请列举标准C/C++的基本变量类型(例如:int),以及它们的字节长度(2分)

    ##A.1、请列举标准C/C++的基本变量类型(例如:int),以及它们的字节长度(2分)

    ++A.1、请列举标准C/C++的基本变量类型(例如:int),以及它们的字节长度(2分)

    ++++立钻哥哥:

    bool

    1个字节[*]

    char

    1个字节[*]

    short

    2个字节[**]

    int

    4个字节[****]

    float

    4个字节[****]

    long

    4个字节[****]

    double

    8个字节[********]

    #include <stdio.h>

     

    int main(void ){

        printf(int = %d\n, sizeof(short int));

        printf(int = %d\n, sizeof(int));

        printf(long int = %d\n, sizeof(long int));

        printf(char=%d\n, sizeof(char));

        printf(float=%d\n, sizeof(float));

        printf(double=%d\n, sizeof(double));

    }    //立钻哥哥:int main(void){}

    16位系统

    long4字节

    int是2字节

    32位系统

    long4字节

    int是4字节

    64位系统

    long8字节

    int是4字节

     

     

     

     

     

    ##A.2、请用#define语句完成以下需求(4分)

    ##A.2、请用#define语句完成以下需求(4分)

    ++A.2、请用#define语句完成以下需求(4分)

    --A、定义一个常量MSOFDAY,表示1天多少毫秒?

    --B、定义一个宏x(a),计算数组元素的个数,a为数组变量名称,x(a)返回数组元素个数?

    ++++立钻哥哥:

    #define MSOFDAY 1*24*60*60*1000

    #define x(a) sizeof(a)/sizeof(*a)

     

     

     

     

     

    ##A.3、请计算sizeof的值(5分)

    ##A.3、请计算sizeof的值(5分)

    ++A.3、请计算sizeof的值(5分)

    char str[] = Hello;

    char *p = str;

    int n = 10;

    请计算:

    ===>sizeof(str) =

    ===>sizeof(p) =

    ===>sizeof(n) =

    ++++立钻哥哥:

    char str[] = Hello;

    char *p = str;

    int n = 10;

    ===>sizeof(str) = 6;

    ===>sizeof(p) = 4;

    ===>sizeof(n) = 4;

     

    ++A.3.1、

    void Func(char str[100]){

    请计算:

        sizeof(str) =

    }

    ++++立钻哥哥:

    void Func(char str[100]){

        sizeof(str) = 4;

    }

     

    ++A.3.2、

    void *p = malloc(100);

    请计算:

    sizeof(p) =

    void *p = malloc(100);

    sizeof(p) = 4;

     

     

     

     

     

    ##A.4、在VC6下定义如下结构(4分)

    ##A.4、在VC6下定义如下结构(4分)

    ++A.4、在VC6下定义如下结构(4分)

    typeof struct{

        char c1;

        char c2;

        long n;

    }stru;

    请问sizeof(stru)等于多少?

    并说明理由?

    ++++立钻哥哥:8字节

    ++++结构体采取的内存分配原则是:四字节对齐

    ++++CPU在读取内存数据的时候:4字节对齐会取得更快的速度

    ++++1字节8位,4字节正好32位;

    ++++而32位机器的寄存器,地址什么的都是32位,正好一次处理就完成;

    ++++补充:如果double n ===>立钻哥哥:12字节

     

     

     

     

     

    ##A.5、头文件中的ifndef/define/endif 干什么用?(2分)

    ##A.5、头文件中的ifndef/define/endif 干什么用?(2分)

    ++A.5、头文件中的ifndef/define/endif 干什么用?(2分)

    ++++立钻哥哥:定义并防止重复定义

    ++++可以在其中声明函数;

     

     

     

     

     

    ##A.6、简述进程和线程的区别?(2分)

    ##A.6、简述进程和线程的区别?(2分)

    ++A.6、简述进程和线程的区别?(2分)

    ++++立钻哥哥:进程是系统分配内存的最小开销,一个进程可以有多个线程,线程依附于进程而存在;线程可以共享进程中的局部变量

    ++++一个进程内的所有线程共享同一全局内存空间;(这使得线程间很容易共享信息,但是这种容易性也会带来了同步问题);

    ++++进程:是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单元

    ++++线程:是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位

    ++++线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源;

    ++++一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行;

    ++++进程和线程都是由操作系统所体会的程序运行的基本单元,系统利用该基本单元实现系统对应用的并发性

    ++++进程和线程的区别在于:简而言之,一个程序至少有一个进程,一个进程至少有一个线程

    ++++线程的划分尺度小于进程,使得多线程程序的并发性高;

    ++++进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率;

    ++++线程在执行过程中与进程还是有区别的:每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口;但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制;

    ++++进程和线程的区别:

    --A、地址空间和其他资源:进程间相互独立,同一进程的各线程间共享;某进程内的线程在其它进程不可见;

    --B、通信:进程间通信IPC:线程间可以直接读写进程数据段(如全局变量)来进行通信;

    --C、调度和切换:线程上下文切换比进程上下文切换要快得多;

     

     

     

     

     

    ##A.7、多线程编程时,线程间同步的方法有哪些?(2分)

    ##A.7、多线程编程时,线程间同步的方法有哪些?(2分)

    ++A.7、多线程编程时,线程间同步的方法有哪些?(2分)

    ++++立钻哥哥:互斥量、信号量、事件、临界区

    ++++Windows中的4种线程同步技术:

    --A、Events(事件):CEvent:作为标志在线程之间的传递信号;简单地说:类似一个布尔型变量的开关作用;

    --B、Critical Sections(临界段):CCriticalSection:在进程中作为关键字以获得对“共享资源”的访问;

    --C、Mutexes(互斥量):CMutex:与临界段的工作方式相似,只是该对象可以用于多进程中的线程同步,而不是用于单进程中;

    --D、Semaphores(信号量):CSemaphore:在给定的限制条件下,允许多个进程同时访问共享资源;

    ++Linux进程通讯方式:

    ++++立钻哥哥:管道、共享内存、消息队列、信号、socket等

    ++++IPC(Interprocess Communication,IPC):进程间通信

    --A、消息传递:(管道、FIFO(有名管道)、消息队列);

    --B、同步:(互斥量、条件变量、读写锁、信号量);

    --C、共享内存区:(匿名共享内存区、有名共享内存区);

    --D、进程调用:(Solaris门、SunRPC);

    ++Linux下如何创建线程:

    ==>pthread_create(&id, NULL, move, stack);

    ==>pthread_join(pthread_t tid, void** status);

     

     

     

     

     

    ##A.8、#include<filename.h>和#include filename.h有什么区别?(2分)

    ##A.8、#include<filename.h>和#include filename.h有什么区别?(2分)

    ++A.8、#include<filename.h>和#include filename.h有什么区别?(2分)

    ++++立钻哥哥:

    ++++<filename.h>:编译器从开发环境设置的路径开始搜索filename.h;

    ++++“filename.h”:编译器从用户的工作路径开始搜索filename.h;

     

     

     

     

     

    ##A.9、有关内存的思考题?(8分)

    ##A.9、有关内存的思考题?(8分)

    ++A.9、有关内存的思考题?(8分)

    ++++立钻哥哥:

    ++请问运行Test函数会有什么样的结果?

    void GetMemory(char* p){

        p = (char*)malloc(100);

    }

     

    void Test(void){

        char* str = NULL;

        GetMemory(str);

        strcpy(str, hello world);

        printf(str);

    }

    ++++立钻哥哥:会中断,因为str并没有提前分配内存

    ++++程序崩溃:因为GetMemory并不能传递动态内存,Test函数中str一直都是NULL,strcpy(str, helloworld);,将使程序崩溃

     

    ++请问运行Test函数会有什么样的结果?

    char* GetMemory(void){

        char p[] = helloword;

        return p;

    }

     

    void Test(void){

        char* str = NULL;

        str = GetMemory();

        printf(str);

    }

    ++++立钻哥哥:程序报错,因为栈区分配空间已经被释放

    ++++可能是乱码:因为GetMemory返回的是指向“栈内存”的指针,该指针的地址不是NULL,但其原有的内容已经被清除,新内容不可知

     

    ++请问运行Test函数会有什么样的结果?

    void GetMemory(char** p, int num){

        *p = (char*)malloc(num);

    }

     

    void Test(void){

        char* str = NULL;

        GetMemory(&str, 100);

        strcpy(str, hello);

        printf(str);

    }

    ++++立钻哥哥:hello

    ++++能够输出“hello”,内存泄露

     

    ++请问运行Test函数会有什么样的结果?

    void Test(void){

        char* str = (char*)malloc(100);

        strcpy(str, hello);

        free(str);

     

        if(str != NULL){

            strcpy(str, world);

            print(str);

        }

    }

    ++++立钻哥哥:world

    ++++篡改动态内存区的内容,后果难以预料,非常危险,因为free(str)之后,str成为野指针,if(str != NULL)语句不起作用

     

     

     

     

     

     

    ##A.10、请写出下面代码的输出结果?(8分)

    ##A.10、请写出下面代码的输出结果?(8分)

    ++A.10、请写出下面代码的输出结果?(8分)

    class MyClass{

        public:

        MyClass(){

            printf(Construct MyClass\n);

        };

     

        void SayHello(void){

            printf(Hello\n);

        }

    };

     

    void TestMyClass(void){

        static MyClass MyClassForTesting;

        MyClassForTesting.SayHello();

    }

     

    int main(void){

        TestMyClass();

        TestMyClass();

     

        return 0;

    }

    ++++立钻哥哥:construct MyClass   Hello   Hello

    ++++补充拓展:总结static的应用和作用:

    --A、函数体内static变量的作用范围为该函数体,不同于auto变量,该变量的内存只被分配一次,因此其值在下次调用的时候仍然维持上次的值;

    --B、在模块内的static全局变量可以被模块内所有函数访问,但不能被模块外其他函数访问;

    --C、在模块内的static函数只可以被这一模块内的其他函数调用,这个函数的使用范围被限制在声明它的类模块中;

    --D、在类中的static成员变量属于整个类所拥有,对类的所有对象只有一份拷贝;

    --E、在类中的static成员函数属于整个类所拥有,这个函数不接受this指针,因而只能访问类的static成员变量;

     

     

     

     

     

    ##A.11、请写出下面代码的输出结果?(8分)

    ##A.11、请写出下面代码的输出结果?(8分)

    ++A.11、请写出下面代码的输出结果?(8分)

    class Base{

        public:

        Base(){};

        ~Base(){};

     

        virtual void WhoAmI(void){

            printf(Base\n);

        };

     

        void OutPutMessage(void){

            WhoAmI();

        };

    };

     

    class Derived : public Base{

        public:

        Derived(){};

        ~Derived(){};

     

        virtual void WhoAmI(void){

            printf(Derived\n);

        };

    };

     

    int main(void){

        Derived D;

        Base *pB = &D;

        D.OutputMessage();

        pB->OutputMessage();

     

        return 0;

    }

    ++++立钻哥哥:Derived    Derived

     

     

     

     

     

    ##A.12、下面一段代码会产生内存泄露,请问如何修改能避免内存泄露? 并简述理由?(8分)

    ##A.12、下面一段代码会产生内存泄露,请问如何修改能避免内存泄露? 并简述理由?(8分)

    ++A.12、下面一段代码会产生内存泄露,请问如何修改能避免内存泄露? 并简述理由?(8分)

    class Base{

        public:

        Base(){  m_piPtr = new int;  }

        ~Base(){  delete m_piPtr;  }

     

        private:

        int *m_piPtr;

    };

     

    class Derived : public Base{

        public:

        Derived(){  m_plDerived = new long;  }

        ~Derived(){  delete m_plDerived;  }

     

        private:

        long* m_plDerived;

    };

     

    int main(void){

        Base* p = new Derived;

        delete p;

     

        return 0;

    }

    ++++立钻哥哥: virtual ~Base(){  delete m_piPtr;  }

    ++++拓展说明1:C++中为什么基类析构函数一般要声明为虚函数

    --1.A、类析构函数要声明为虚函数:这样派生类调用析构函数才能层层回调,释放资源;(这也是虚函数的作用:提供回调的指针

    ++++拓展说明2:基类的析构函数为什么是虚函数:

    --2.A、一般情况下类的析构函数里面都是释放内存资源,而析构函数不被调用的话就会造成内存泄露

    --2.B、当用一个基类的指针删除一个派生类的对象时,派生类的析构函数会被调用

    ++++拓展说明3:并不是要把所有类的析构函数都写成虚函数:

    --3.A、因为当类里面有虚函数的时候,编译器会给类添加一个虚函数表,里面来存放虚函数指针,这样就会增加类的存储空间;所以,只有当一个类被用来作为基类的时候,才把析构函数写成虚函数

     

    ++补充:《EffectiveC++》条款07:

    ++++立钻哥哥:条款07:为多态基类声明virtual析构函数

    ++++析构函数的运作方式是:最深沉派生的那个class其析构函数最先被调用,然后是其每一个base class的析构函数被调用;

    ++++请记住:polymorphic(带多态性质的)base classes应该声明一个virtual析构函数;

    --如果class带有任何virtual函数,它就应该拥有一个virtual析构函数

    ++++Classes的设计目的:如果不是作为base classes使用,或不是为了具备多态性(polymorphically),就不该声明virtual析构函数;

     

     

     

     

     

    ##A.13、编写strcpy()函数?(10分)

    ##A.13、编写strcpy()函数?(10分)

    ++A.13、编写strcpy()函数?(10分)

    已知strcpy函数原型是:

    char *strcpy(char *strDest, const char *strSrc);

    其中:strDest是目的字符串,strSrc是源字符串;

    不调用C++/C的字符串函数,请编写函数strcpy。

    ++++立钻哥哥:

    char *myStrcpy(char *strDest, const char* strSrc){

        if(strDest == NULL || strSrc == NULL){

            return NULL;

        }

     

        char *strDestCopy = strDest;

        while((*strDest++ = *strSrc++) != \0);

     

        return strDestCopy;

    }

     

    char *myStrcpy(char *strDest, const char* strSrc){

        Assert((strDest != NULL) && (strSrc != NULL));

     

        char *tmp = strDest;

        while((*strDest++ = *strSrc++) != \0);

     

        return tmp;

    }

     

     

    char *myStrcpy(char *dst, const char* src){

        char *dcp;

        for(dcp = dst;  *dcp = *src;  dcp++, src++);

        

        return dst;

    }

     

     

     

     

     

     

    ##A.14、如下两种写法有什么区别?(5分)

    ##A.14、如下两种写法有什么区别?(5分)

    ++A.14、如下两种写法有什么区别?(5分)

    1、

    for(int i = 0;  i < NUM;  i++){

        if(a < b){

            DoSomething1();

        }else{

            DoSomething2();

        }

    }

     

    2、

    if( a < b){

        for(int i = 0;  i < NUM;  i++){

            DoSomething1();

        }

     

    }else{

        for(int i = 0;  i < NUM;  i++){

            DoSomething2();

        }

    }

     

    ++++立钻哥哥:

    ++++第一种写法:

    --优点:程序简洁

    --缺点:多执行了N-1次逻辑判断,并且打断了循环“流水线”作用,使得编译器不能对循环进行优化处理,降低了效率;

    ++++第二种写法:

    --优点:循环的效率高

    --缺点:程序不简洁;

     

     

     

     

     

    ##A.15、关键字static在C语言中的作用?(5分)

    ##A.15、关键字static在C语言中的作用?(5分)

    ++A.15、关键字static在C语言中的作用?(5分)

    ++++立钻哥哥:

    ++++1、在函数体内,一个被声明为静态的变量在这一函数调用过程中维持不变;

    ++++2、在模块内(一个.c文件内),被声明的静态变量可以被模块内所有函数访问,但不能被模块外的其他函数访问;

    ++++3、在模块内,一个被声明为静态的函数只能被同一模块内的其他函数调用;

     

     

     

     

     

    ##A.16、C++是安全类型的语言吗?(2分)

    ##A.16、C++是安全类型的语言吗?(2分)

     

     

     

     

     

     

     

     

     

     

    #第二篇:Cocos2dx和C++知识点

    #第二篇:Cocos2dx和C++知识点

    #第二篇:Cocos2dx和C++知识点

    ++++B.1、对Cocos2dx的整体描述,整体认识?

    ++++B.2、如何阅读分析Cocos2dx源码及整体框架?

    ++++B.3、介绍一下你的项目?

    ++++B.4、使用Cocos2dx的心得?

    ++++B.5、是否了解CocoStudio?

    ++++B.6、用过哪些UI控件?

    ++++B.7、Cocos2dx的消息传递机制?

    ++++B.8、Cocos2dx内存自动回收机制?

    ++++B.9、Cocos2dx触摸机制?

    ++++B.10、在CCLayer处理用户触摸?

    ++++B.11、Cocos2dx触摸分发器?

    ++++B.12、Cocos2dx中图片的缓存和加载方式?

    ++++B.13、常见的内存管理的方式?

    ++++B.14、C++显式堆内存管理?

    ++++B.15、C++11中的智能指针?

     

     

     

     

    ##B.1、对Cocos2dx的整体描述,整体认识?

    ##B.1、对Cocos2dx的整体描述,整体认识?

    ++B.1、对Cocos2dx的整体描述,整体认识?

    ++++立钻哥哥:

    ++++Cocos2dx的游戏元素是:大总管CCDirector,场景CCScene,层CCLayer,精灵CCSprite,再加上动作CCAction,再配合一些动画CCAnimation和粒子特效CCParticleSystem等就构成了Cocos2dx游戏

    ++++游戏领域作为GUI的先驱,其计算机技术应用也引领着软件开发前沿,比如Cocos2d-3.0系列大量采用了C++11特性:override和final、lambda表达式等;

    ++++Cocos2dx游戏框架:内存管理、图层渲染

     

    ++Cocos2dx是一个简单而强大的二维游戏引擎

    ++++立钻哥哥:Cocos2dx的原型是Cocos2d,目的是封装底层绘图代码,简化2D游戏的开发过程,避免每次都“重新发明轮子”

    ++++从本质上说:Cocos2d是一个图形引擎,封装了复杂的图形接口,通过抽象出精灵、动作等概念,降低了游戏开发难度,简化了开发过程;

    ++++Cocos2dx:基于Cocos2d-iPhone的多平台二维游戏引擎,为开发者封装了功能强大的绘图代码,使开发者专注于游戏开发而不是绘图操作;

    ++++AppDelegate:Cocos2dx项目中的程序入口文件,提供对程序生命周期的控制事件;

    ++++CCNode::addChild方法:用于将一个游戏元素添加到另一个元素中;

     

    ++简单介绍一下Cocos2d的特性:

    ++++流程控制(flow control):非常容易管理不同场景(scene)之间的流程控制;

    ++++精灵(sprite):快速而方便的精灵用于显示一切可见的元素;

    ++++节点(node):基于树结构的分层组织方式,方便管理不同层次的游戏元素,同时提供了统一管理的计时器(scheduler);

    ++++动作(action):应用于精灵或其他游戏元素的动画效果,可以组合成复杂的动作,如移动(move)、旋转(rotate)和缩放(scale)等;

    ++++特效(effect):包括波浪(wave)、旋转(twirl)和透镜(lens)等视觉特效;

    ++++平面地图(tiled map):支持矩形和六边形的平面地图;

    ++++菜单(menu):创建游戏中常见的菜单;

    ++++用户输入:提供接受用户触摸事件、传感器(如加速度计)等输入的简单解决方案;

    ++++文档(document):编程指南,API参考、视频教学以及很多简单可靠的测试样例;

    ++++MIT许可:免费开放的协议,但是请谨记尊重版权;

    ++++基于OpenGL:深度优化的绘制方式,支持硬件加速;

     

    ++导演(CCDirector)

    ++++立钻哥哥:在Cocos2dx引擎中,CCDirector类是整个游戏的组织和控制核心,游戏的运行规则,游戏内的CCScene(场景)、布景(CCLayer)、角色(CCSprite)等的运动,均由CCDirector管理,其在游戏中起着指定游戏规则让游戏内的场景、布景和任务有序的运行

    +++++在整个游戏里面,一般只有一个导演,游戏开始和结束时,都需要调用CCDirector的方法完成游戏初始化或销毁工作,其提供了一些场景管理的方法,如runWithScenedrawScenepushScenereplaceScene等;

    ++++CCDirector控制FPS的显示隐藏,窗口大小,游戏的进入,退出,关卡的切换,取得正交模式,取得正在运行的场景,取得GL视图,游戏主循环入口等等;

     

     

     

     

     

    ##B.2、如何阅读分析Cocos2dx源码及整体框架?

    ##B.2、如何阅读分析Cocos2dx源码及整体框架?

    ++B.2、如何阅读分析Cocos2dx源码及整体框架?

    ++++立钻哥哥:阅读源代码的最好方式是top-down的方式:先弄懂整个框架,再重点突破重要和感兴趣的模块

    ++1、先看看测试用例TestCpp中的主函数,也是整个Win32程序的入口

    int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int mCmdShow){

        UNREFERENCED_PARAMETER(hPrevInstance);

        UNREFERENCED_PARAMETER(lpCmdLine);

     

        //create the application instance

        AppDelegate app;

        CCEGLView* eglView = CCEGLView::sharedOpenGLView();

        eglView->SetViewName(TestCpp);

        eglView->setFrameSize(1028, 720);

     

        return CCApplication::sharedApplicaiton()->run();

    }    //立钻哥哥:int APIENTRY _tWinMain(){}

    ++++这个入口有2个非常重要的类CCEGLViewCCApplication,在整个程序中都是单例;

    +++++[CCEGLView]:是用来管理窗口和绘制;在CCEGLView::Create()中做了一下工作:

    --A、registerClass注册窗口:其中非常重要的消息处理函数CCEGLView::_WindowProc()就是在这个地方定义的;整个游戏中的窗口的键盘、鼠标消息响应就可以在这个函数中进行处理;

    --B、initGL初始化OpenGL引擎;(CCEGLView::initGL()中设置了像素的格式,创建了OpenGL的RenderContext,OpenGL最终渲染的结果会显示到该窗口的DC上)

     

    ++2、再看看CCApplication

    ++++立钻哥哥:CCApplication是用来管理程序的逻辑,最后一句CCApplication::sharedApplication()->run(); :整个程序就开始告诉运转起来了

    CCApplication* CCApplication::sharedApplication(){

        CC_ASSERT(sm_pSharedApplication);

        return sm_pSharedApplicaition;

    }

     

    ++AppDelegateApplication的子类,在这个子类的构造函数中声明了这个全局唯一的静态变量:sm_pSharedApplication

    CCApplication:CCApplication() : m_hInstance(NULL), m_hAccelTable(NULL){

        m_hInstance = GetModuleHandle(NULL);

        m_nAnimationInterval.QuadPart = 0;

        CC_ASSERT(!sm_pSharedApplication);

        sm_pSharedApplication = this;

    }    //立钻哥哥:CCApplication::CCApplication(){}

    +++Application::Run()做了什么,让整个程序运行起来了:

    int CCApplication::run(){

        PVRFrameEnableControlWindow(false);

     

        //Main message Loop:

        MSG msg;

        LARGE_INTEGER nFreq;

        LARGE_INTEGER nLast;

        LARGE_INTEGER nNow;

     

        QueryPerformanceFrequency(&nFreq);

        QueryPerformanceCounter(&nLast);

     

        //Initialize instance and cocos2d

        if(!applicationDidFinishLaunching()){

            return 0;

        }

     

        CCEGLView* pMainWnd = CCEGLView::sharedOpenGLView();

        pMainWnd->centerWindow();

        ShowWindow(pMainWnd->getHWnd(), SW_SHOW);

     

        while(1){

            if(!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){

                //Get current time tick

                QueryPerformanceCounter(&nNow);

     

                //If its the time to draw next frame, draw it, else sleep a while.

                if(nNow.QuadPart - nLast.QuadPart > m_nAnimationInterval.QuadPart){

                    nLast.QuadPart = nNow.QuadPart;

                    CCDirector::sharedDirector()->mainLoop();

                }else{

                    Sleep(0);

                }

                continue;

            }    //立钻哥哥:if(!PeekMessage()){}

     

            if(WM_QUIT == msg.message){

                //Quit message loop

                break;

            }

     

            //Deal with windows message

     

            if(!m_hAcceelTable || !TranslateAccelerator(msg.hwnd, m_hAccelTable, &msg)){

                TranslateMessage(&msg);

                DispatchMessage(&msg);

            }

     

            return (int)msg.wParam;

     

        }    //立钻哥哥:while(1){}

     

    }    //立钻哥哥:int CCApplication::run(){}

    ++++[applicationDidFinishLaunching()]:这部分和测试用例有关系;

    ++++在while(1){}主循环中做了两件事

    --1A、转发窗口消息,交给之前定义的CCEGLView::_WindowProc()进行处理;

    --2B、每隔m_nAnimationInterval.QuadPart时间,也就是游戏的一帧,进行一次处理;

     

    ++3、最重要的一个类CCDirector导演类

    ++++立钻哥哥:CCDirector导演类是一个单例,负责整个游戏场景管理,逻辑更新以及绘制

    ++++CCDirector::sharedDirector()->mainLoop()的每帧的mainLoop()都做了啥事情:

    void CCDisplayLinkDirector::mainLoop(void){

        if(m_bPurgeDirectorInNextLoop){

            m_bPurgeDirectorInNextLoop = false;

            purgeDirector();

        }else if(!m_bInvalid){

            drawScene();

     

            //release the objects

            CCPoolManager::sharedPoolManager()->pop();

        }

     

    }    //立钻哥哥:void CCDisplayLinkDirector::mainLoop(){}

    ++++CCDirector导演类的每帧做的最重要的事情就是drawScene()

    void CCDirector::drawScene(void){

        ... ...

     

        if(!m_bPaused){

            m_pScheduler->update(m_fDeltaTime);

        }

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

     

        //draw the scene

        if(m_pRunningScene){

            m_pRunningScene->visit();

        }

     

        //swap buffers

        if(m_pobOpenGLView){

            m_pobOpenGLView->swapBuffers();

        }

     

    }    //立钻哥哥:void CCDirector::drawScene(){}

    ++++CCDirector::drawScene()做了两方面的工作

    --1A、更新调度器m_pScheduler:比如场景中的动作等;

    --2B、绘制场景中的对象结点,树形的方式;

     

     

     

     

     

     

    ##B.3、介绍一下你的项目?

    ##B.3、介绍一下你的项目?

    ++B.3、介绍一下你的项目?

    ++++立钻哥哥:我一共准备了N个项目,其中2个项目已发布在360平台上

    ++++《ylzServPlane》:飞机大战,是基于Cocos2dx-2.2.3框架,利用这个小游戏,主要是熟悉Cocos2dx-2.2.3开发环境,掌握利用Cocos2dx框架开发游戏的基本技能;

    ++++《ylzServFind》:找宝石,是基于Cocos2dx-3.2框架,利用这个小游戏,主要是熟悉Cocos2dx-3.2开发环境,掌握3.0系列与2.0系列的差异和相关开发技能;

    ++++项目练习是我以后一个重要的学习途径:通过一个项目熟悉一个开发框架;

    ++++现在正在做的还有:《ylzServGuess》猜猜看,这个游戏很重要,肩负着三大任务:http、sqlite、UI等任务,这个项目基于Cocos2dx-2.2.2框架;

    ++++以后会陆续改写更多项目:《ylzServ塔防》《ylzServ找你妹》《ylzServ太空大战》《ylzServ****》

    ++++以后重点突破领域有:TileMap瓦片地图项目、CocosStudioUI场景动画项目等

     

     

     

     

     

    ##B.4、使用Cocos2dx的心得?

    ##B.4、使用Cocos2dx的心得?

    ++B.4、使用Cocos2dx的心得?

    ++++立钻哥哥:Cocos2dx本身是C++的,尽管开发团队为了降低学习难度和入门门框做了很多工作,但是如果C++功底不够,我觉得也学不到什么东西,充其量学会了使用一个工具而已

    ++++作为一个优秀的程序员,数学是非常重要的;

    ++++C/C++还是值得学习的,虽然这个比较难,但是自有其价值所在;

     

     

     

     

     

    ##B.5、是否了解CocoStudio?

    ##B.5、是否了解CocoStudio?

    ++B.5、是否了解CocoStudio?

    ++++立钻哥哥:CocoStudio作为触控推出的一款工具,肯定是有其战略意义的

    ++++CocoStudio作为专业的UI、场景、动画、数据等开发工具,其功能相当强大,是以后必须认真学习掌握的必备工具;

    ++++CocosStudio是一套专业的永久免费的游戏开发工具集,帮助开发快速创建游戏资源,将大部分繁琐的游戏开发工作使用编辑器来快速制作;

    ++++CocoStudio包含了游戏开发中核心的几个游戏编辑器:UI编辑器、动画编辑器、场景编辑器、数据编辑器,用于处理游戏中的动画资源、UI界面、游戏场景、游戏数据,针对于开发团队中不同的职业进行深度设计,规范了整个开发流程,让开发团队中每个人各执其职,发挥自己最大的作用;

    ++++[动画编辑器]:用于编辑游戏中使用的角色动画、特效动画、场景动画等动态的游戏资源;(主要使用人员是:美术设计师)

    ++++[UI编辑器]:用于编辑游戏中的所有的图形界面;(主要使用人员是美术设计师)

    ++++[数据编辑器]:用于将数值策划编辑的数值表导入数据编辑器中,将复杂表进行分解,导出成属性表,数值表等几种常用的数据文件;

    ++++[场景编辑器]:用于编辑游戏中的场景元素、游戏关卡;(主要使用人员是策划或者关卡设计师)

     

     

     

     

     

    ##B.6、用过哪些UI控件?

    ##B.6、用过哪些UI控件?

    ++B.6、用过哪些UI控件?

    ++++立钻哥哥:UI控件其实很多的,留意了,用过一次,基本就会了,如果没有注意到,就不会

    ++++常见UI控件:CCSpriteCCNodeCCLayerCCScene

    ++++[CCScale9Sprite]:九宫格Sprite;

    ++++[CCControlButton]:事件按钮;

    ++++[CCControlSlider]:拖动条;

    ++++[CCControlColorPicker]:颜色选择器;

    ++++[CCControlSwitch]:开关控件;

    ++++[CCControlPotentionmeter]:压力计;

    ++++[CCControlStepper]:分段控件;

    ++++[CCScrollView]:滚动视图;

    ++++[CCTableView]:列表视图;

     

     

     

     

     

    ##B.7、Cocos2dx的消息传递机制?

    ##B.7、Cocos2dx的消息传递机制?

    ++B.7、Cocos2dx的消息传递机制?

    ++++立钻哥哥:

    ++++[1、采用函数回调]:主要是用于MenuItem:

    ++++[2、TouchEvent响应]:为更多的响应处理提供可能;

    ++++[3、触摸监听绑定]:触摸函数可以用lambda来写;

     

     

     

     

     

    ##B.8、Cocos2dx内存自动回收机制?

    ##B.8、Cocos2dx内存自动回收机制?

    ++B.8、Cocos2dx内存自动回收机制?

    ++++立钻哥哥:Cocos2dx提供了一种类似Java的内存回收机制;(在C++中,不再使用的变量,需要手动释放(delete),不然内存就会溢出)

    ++++在使用Cocos2dx时,在新创建实例时,加入autorelease(),这样就可以自动释放不再需要的内存了:

    {

        CCScene* pScene = CCScene::node();

        CCLayer* pLayer = new MyTestController();

        pLayer->autorelease();

    }

    ++++为了实现对象的引用计数记录,Cocos2dx实现了自己的根类CCObject,引擎中的所有派生类都派生自CCOject,CCObject的定义:

    class CC_DLL CCObject : public CCCopying{

    public:

        unsigned int m_uID;    //对象id,在脚本引擎中使用

        int m_nLuaID;    //Lua中的引用ID,同样被脚本引擎使用

     

    protected:

        unsigned int m_uReference;    //引用数量

        bool m_bManaged;    //标识此对象是否已设置为autorelease

     

    public:

        CCObject(void);

        virtual ~CCObject(void);

        void release(void);

        void retain(void);

        CCObject* autorelease(void);

        CCObject* copy(void);

        bool isSingleRefrence(void);

        unsigned int retainCount(void);

        virtual bool isEqual(const CCObject* pObject);

        virtual bool update(ccTime dt){  CC_UNUSED_PARAM(dt);  };

        friend class CCAutoreleasePool;

    };    //立钻哥哥:class CC_DLL CCObject:public CCCopying{}

    ++++每个对象包含一个用来控制生命周期的引用计数器,它就是CCObject的成员变量m_uReference;

    ++++我们可以通过retainCount()方法获得对象当前的引用计数值;

    ++++autorelease()的作用是将对象放入自动回收池(CCAutoreleasePool):当回收池自身被释放的时候,就会对池中的所有对象执行一次release()方法,实现灵活的垃圾回收;

    ++++通过回收池管理器CCPoolManager的push()或pop()方法来创建或释放回收池,其中CCPoolManager也是一个单例对象;

    ++++引擎维护着一个回收池,所有的autorelease对象都添加到了这个池中;

    ++++自动回收池是可嵌套的:多个自动回收池排列成栈结构,当我们手动创建了回收池后,回收池会压入栈的顶端,autorelease对象仅添加到顶端的池中;当顶层的回收池被弹出释放时,它内存所有的对象都会被释放一次,此后出现的autorelease对象则会添加到下一个池中

    //步骤a

    obj1->autorelease();

    obj2->autorelease();

     

    //步骤b

    CCPoolManager::sharedPoolManager()->push();

     

    //步骤c

    for(int i = 0;  i < n;  i++){

        obj_array[i]->autorelease();

    }

     

    //步骤d

    CCPoolManager::sharedPoolManager()->pop();

     

    //步骤e

    obj3->autorelease();

     

    ++++当执行步骤a时,obj1和obj2被加入到回收池1中;

    ++++步骤b创建了一个新的回收池,此时回收池2接管所有autorelease操作;

    ++++步骤c是一个循环,其中把n个对象加入回收池2中;

    ++++步骤d释放了回收池2,因此回收池2中的n个对象都被释放了一次,同时回收池1接管autorelease操作;

    ++++步骤e调用obj3的autorelease()方法,把obj3加入回收池中;

     

    ++Cocos2dx内存管理原则

    ++++1A、程序段必须成对执行retain()和release()或者执行autorelease()来开始和结束对象的引用

    ++++2B、工厂方法返回前,应通过autorelease()结束该对象的引用

    ++++3C、对象传值前,应考虑到新旧对象相同的特殊情况

    ++++4D、尽量使用release()而不是autorelease()来释放对象引用,以确保性能最优

    ++++5E、保存CCObject的子类对象时,应严格使用Cocos2dx提供的容器,避免使用STL容器,对象必须以指针形式存入

    ++++6F、如果希望自定义的类也拥有Cocos2dx的内存管理功能,可以把CCObject作为自定义的基类,并在实现类时严格遵守Cocos2dx的内存管理原则

     

    ++复杂的内存管理

    ++++内存管理一直是一个不易处理的问题,开发者必须考虑分配回收的方式和时机,针对堆和栈做不同的优化处理等等;

    ++++内存管理的核心是动态分配的对象必须保证在使用完毕后有效地释放内存,即管理对象的生命周期

    ++++过于零碎的对象分配回收可能导致堆中的内存碎片化,降低内存的使用效率;

    ++++Boost库引入的智能指针(smart pointer)从对象所有权传递的角度来解决内存管理问题;(各种基于C++的第三方工具库和引擎往往都会实现自己的智能内存管理机制来解决内存管理的难题,试图将开发者从烦琐而晦涩的内存管理中解放出来)

     

    ++现有的智能内存管理技术

    ++++立钻哥哥:实现智能管理内存的技术主要有两种:一是引用计数;二是垃圾回收

    ++++[引用计数]:它是一种很有效的机制,通过给每个对象维护一个引用计数器,记录该对象当前被引用的次数;引用计数的重要规则是每一个程序片段必须负责任地维护引用计数,在需要维持对象生存的程序段的开始和结束分别增加和减少一次引用计数,这样我们就可以实现十分灵活的智能内存管理了;(引用计数解决了对象的生命周期管理问题,但堆碎片化和管理烦琐的问题仍然存在)

    ++++[垃圾回收]:它通过引入一种自动的内存回收器,试图将程序员从复杂的内存管理任务中完全解放出来;垃圾回收器还可以压缩使用中的内存,以缩小堆所需要的工作空间;

     

    ++工厂方法

    ++++立钻哥哥:工厂方法是程序设计中一个典型的设计模式,指的是基类中只定义创建对象的接口,将实际的实现推迟到子类中

    ++++工厂方法返回前,通过autorelease()结束该对象的引用

    CCObject* factoryMethod(){

        CCObject* ret = new CCObject();

     

        ... ...

        //这里对ret对象进行必要的初始化操作

     

        ret->autorelease();

        return ret;

    }

     

    ++释放:release()还是autorelease()

    ++++立钻哥哥:autorelease()并不是毫无代价的,其背后的垃圾池机制同样需要占用内存和CPU资源,每次执行autorelease()的过程,实际上对应的是执行成对的retain()和release(),以及一次成对的容器存取,还包括其他的逻辑判断

    ++++过多不必要的autorelease()将导致垃圾池臃肿膨胀,在存在大量内存操作的过程中会尤为严重地挤占本来就紧张的系统资源;

    ++++建议在开发过程中应该避免滥用autorelease(),只在工厂方法等不得不用的情况下使用,尽量以release()来释放对象引用

     

    ++Cocos2dx中与内存管理有关的宏

    ++++[CC_SAFE_DELETE(p)]:使用delete操作符删除一个C++对象p,如果p为NULL,则不进行操作;

    ++++[CC_SAFE_DELETE_ARRAY(p)]:使用delete[]操作符删除一个C++数组p,如果p为NULL,则不进行操作;

    ++++[CC_SAFE_FREE(p)]:使用free()函数删除p,如果p为NULL,则不进行操作;

    ++++[CC_SAFE_RELEASE(p)]:使用release()方法释放Cocos2dx对象p的一次引用,如果p为NULL,则不进行操作;

    ++++[CC_SAFE_RELEASE_NULL(p)]:使用release()方法释放Cocos2dx对象p的一次引用,再把p赋值为NULL,如果p已经为NULL,则不进行操作;

    ++++[CC_SAFE_RETAIN(p)]:使用retain()方法增加Cocos2dx对象p的一次引用;如果p为NULL,则不进行操作;

     

     

     

     

     

    ##B.9、Cocos2dx触摸机制?

    ##B.9、Cocos2dx触摸机制?

    ++B.9、Cocos2dx触摸机制?

    ++++立钻哥哥:返回true,则本层接受;如果是false,就不接受,向下传递

    //2.0版本

    virtual void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent);

    virtual void ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent);

    virtual void ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent);

    virtual void ccTouchesCancelled(CCSet *pTouches, CCEvent *pEvent);

    ++++[ccTouchesBegan]:触摸事件开始,也就是手指按下时;

    ++++[ccTouchesMoved]:触摸移动事件,也就是手指在屏幕滑动的过程;

    ++++[ccTouchesEnded]:触摸事件结束,也就是手指松开时;

    ++++[ccTouchesCancelled]:打断触摸事件,一般是系统层次的消息,如手机来电话,触摸事件就会被中断;

     

    //3.0版本

    //单点触摸

    virtual bool onTouchBegan(Touch *touch, Event *unused_event);

    virtual void onTouchMoved(Touch *touch, Event *unused_event);

    Virtual void onTouchEnded(Touch *touch, Event *unused_event);

    virtual void onTouchCancelled(Touch *touch, Event *unused_event);

     

    //多点触摸

    virtual void onTouchesBegan(const std::vector<Touch*>& touches, Event *unused_event);

    virtual void onTouchesMoved(const std::vector<Touch*>& touches, Event *unused_event);

    virtual void onTouchesEnded(const std::vector<Touch*>& touches, Event *unused_event);

    virtual void onTouchesCancelled(const std::vector<Touch *>& touches, Event* unused_event);

    ++++【单点触摸】:只有注册的Layer才能接收触摸事件:

    --A、[onTouchBegan()]

        ----A.1、如果返回true:本层的后续Touch事件可以被触发,并阻挡向后层传递;

        ----A.2、如果返回false:本层的后续Touch事件不能被触发,并向后传递,也就是不会调用;

    --B、[onTouchMoved()]

    virtual bool onTouchBegan(CCTouch *pTouch, CCEvent *pEvent);

            ----B.1、返回false,则ccTouchMoved(), ccTouchEnded()不会再接收到消息;

            ----B.2、返回true,则ccTouchMoved(), ccTouchEnded()可以接受到消息;

     

    ++小结

    ++++[CCLayer触摸支持]:CCLayer提供了一套现成的触摸实现,只需启用TouchEnable属性即可接收Cocos2dx的标准触摸事件;(开发者需要重载以ccTouches为前缀的响应函数

    ++++[标准触摸事件]:Cocos2dx提供的一种触摸事件,注册了这种事件的所有对象都会平等地接收到触摸事件,并且对于多点触摸,标准触摸事件会同时提供所有的触摸点;

    ++++[带目标的触摸事件]:这是另一种触摸事件,注册了这种事件的对象会按照优先级投递,先接收到事件的对象有权吞噬此事件,以阻止把事件分发给其他对象;(利用吞噬功能屏蔽某个事件)(例如:一个提示框可以屏蔽掉提示框以外的所有对象接收到触摸事件)

    ++++[触摸分发器(CCTouchDispatcher)]:由引擎调度、负责接收来自系统的触摸事件;(这允许任何对象在分发器中注册触摸事件,并根据Cocos2dx的机制把触摸事件分发给注册者)(开发者可以利用addStandardDelegateaddTargetedDelegate方法把自己注册为事件接收者,利用removeDelegate方法取消曾经注册过的触摸事件)

     

     

     

     

     

    ##B.10、在CCLayer处理用户触摸?

    ##B.10、在CCLayer处理用户触摸?

    ++B.10、在CCLayer处理用户触摸?

    ++++立钻哥哥:CCLayer继承自CCNode,在CCLayer中可以实现单点触摸、多点触摸和重力感应回调等3种不同形式的交互

    ++++这里我们来重点讨论一下:在CCLayer处理用户触摸

     

    ++在用户自定义的图层处理用户触摸事件步骤

    ++++A、步骤1:编写图层类继承CCLayer

    ++++B、步骤2:在初始化阶段(init方法),将此层的属性设置为接收触摸消息:

    setTouchEnabled(true);    //开启屏幕触摸

    ++++C、步骤3:重载CCLayer函数virtual void registerWithTouchDispatcher(void);,因为默认的方式为:[Standard Touch Delegate],需要在函数中添加以下语句:

    CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, 0, true);

    --第二个参数是代理的优先级,如果数值越小优先级越高;

    --第三个参数是true:表示当前图层处理消息后不再进行消息的后续传递,如果需要继续传递消息需要设置为false;

    ++++D、步骤4:重载触摸响应函数,接收触摸消息需要重载以下函数:

    ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);    //按下

    ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent);    //滑动

    ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);    //抬起

    ++++E、步骤5:在触摸响应函数中通过pTouch得到用户的触摸点

    CCPoint point = pTouch->getLocation();

     

     

     

     

     

    ##B.11、Cocos2dx触摸分发器?

    ##B.11、Cocos2dx触摸分发器?

    ++B.11、Cocos2dx触摸分发器?

    ++++立钻哥哥:为了实现触摸事件,CCLayer已经封装好了简单的接口(继承了CCTouchDelegate类)来实现触摸事件的响应

    ++++触摸事件有两种:标准触摸代理和目标触摸代理;

    ++++[标准触摸]:在层初始化时调用setTouchEnable(true); 方法,即可实现标准触摸,实现处理事件回调函数,处理触摸事件即可;

    //optional

    virtual void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent);

    virtual void ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent);

    virtual void ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent);

    virtual void ccTouchesCancelled(CCSet *pTouches, CCEvent *pEvent);

     

    void TouchLayer::ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent){

        if(pTouches->Count() == 1){

            CCTouch *touch = dynamic_cast(pTouches->anyObject());

     

            //由于在不同平台下触摸点的坐标系与OpenGL呈现区域的参数可能不尽相同

            CCPoint position = touch->locationInView();    //获取游戏画面中的点位置

            positon = CCDirector::sharedDirector()->convertToGL(position);

     

            //此处处理触摸事件

     

        }else{

            //如果不止一个触摸点,则在此处理多点触摸事件

        }

     

    }    //立钻哥哥:void TouchLayer::ccTouchesMoved(){}

    void CCLayer::setTouchEnabled(bool enabled){

        if(m_bTouchEnabled != enabled){

            m_bTouchEnabled = enabled;

            if(m_bRunning){

                if(enabled){

                    this->registerWithTouchDispatcher();

                }else{

                    CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this);

                }

            }

        }

    }    //立钻哥哥:void CCLayer::setTouchEnabled(){}

    ++++进入[registerWithTouchDispatcher()]方法中看到调用了:pDispatcher->addStandardDelegate(this, 0); 方法,也就是将该对象注册为标准代理;

    ++++对于标准代理,只要事件分发器接收到用户的触摸事件,就会分发给所有的订阅者;

    ++++当系统存在多个触摸点时,所有的触摸点都会传递给回调函数,然后许多情况下每个触摸点之间是独立的,屏幕上是否存在其他触摸点我们并不关心;

    ++++[目标代理]:要我该层使用目标代理,首先调用addTargetedDelegate()开启目标代理;

    ++1、首先调用addTargetedDelegate()开启目标代理:

    CCTouchDispatcher::sharedDispatcher()->addTargetedDelegate(this, 0, true);

    ++++第二个参数为优先级;第三个参数为是否吞噬触摸;

     

    ++2、然后重载事件回调函数:

    virtual bool ccTouchesBegan(CCTouch *pTouches, CCEvent *pEvent);

    virtual void ccTouchesMoved(CCTouch *pTouches, CCEvent *pEvent);

    virtual void ccTouchesEnded(CCTouch *pTouches, CCEvent *pEvent);

    virtual void ccTouchesCancelled(CCTouch *pTouches, CCEvent *pEvent);

    ++++第一个参数为CCTouch*,已不再是CCSet*集合,而是一个触摸点;

    ++++ [ccTouchBegan()]方法返回的是一个布尔值,表示声明是否要捕捉传入的这个触摸点,返回true表示要捕捉,那么在后面Moved和Ended中处理触摸事件即可;

    ++++如果注册的时候选择了要吞噬触摸,触摸事件不会再分发下去,则优先级低的对象无法接收到触摸;

     

    ++3、实现一个对象的触摸代理分以下几步:

    ++++A、第1步:此对象继承CCStandardTouchDelegate/CCTargetedTouchDelegate接口

    ++++B、第2步:使用addStandardDelegate/addTargetedDelegate方法把自己注册给触摸事件分发器CCTouchDispatcher;

    ++++C、第3步:重载事件处理回调函数;(注意目标代理触摸开始事件Began中必须针对需要接受的事件返回true)

    ++++D、第4步:当不再需要接收触摸事件,使用removeDelegate方法来注销触摸事件的接收

     

     

    ++触摸分发器原理

    //来看看CCDispatcher的主要成员

     

    //注册标准触摸事件

    void addStandardDelegete(CCTouchDelegate *pDelegate, int nPriority);

     

    //注册目标触摸事件

    void addTargetedDelegate(CCTouchDelegate *pDelegate, int nPriority, bool bSwallowsTouches);

     

    //注销触摸派发

    void removeDelegate(CCTouchDelegate *pDelegate);

    void removeAllDelegate(void);

     

    //重新设定指定对象的事件优先级

    void setPriority(int nPriority, CCTouchDelegate *pDelegate);

     

    //分发事件

    void touches(CCSet *pTouches, CCEvent *pEvent, unsigned int uIndex);

     

    protected:

    CCArray* m_pTargetedHandlers;    //记录注册了带目标的触摸事件对象

    CCArray* m_pStandardHandlers;    //记录注册了标准触摸事件的对象

     

     

     

     

     

    ##B.12、Cocos2dx中图片的缓存和加载方式?

    ##B.12、Cocos2dx中图片的缓存和加载方式?

    ++B.12、Cocos2dx中图片的缓存和加载方式?

    ++++立钻哥哥:在Cocos2dx中进行图片加载时,如果是第一次加载图片就要把图片加载到缓存,然后从缓存中加载图片,如果缓存中已经有了,就直接从缓存中加载

    ++++图片的缓存有两种类型:一种是CCTextureCache,另一种是CCSpriteFrameCache

    ++++[CCTextureCache]:是普通的图片加载缓存,一般直接加载的图片都会放到这个缓存里面,这是一个会经常用到的缓存,这个缓存如果不手动释放,它是会一直占用内存的,它有很多函数接口,都是为了方便进行内存管理等的;

    --[removeAllTextures()]:清空所有的缓存;

    --[removeUnusedTextures()]:清除没用的缓存;

    --[dumpCachedTextureInfo()]:输出缓存的信息;

     

     

     

     

     

    ##B.13、常见的内存管理的方式?

    ##B.13、常见的内存管理的方式?

    ++B.13、常见的内存管理的方式?

    ++++立钻哥哥:

    ++++1A、在适当的时候释放内存

    ++++2B、使用纹理贴图集的方法,尽量拼接图片,使得图片的边长保持在2的N次方,同时最好将有一点逻辑关系的图片打包在一张大图里,从而能够有效地节约内存;

    ++++3C、使用CCSpriteBatchNode来减少相同图片的渲染操作

     

     

     

     

     

    ##B.14、C++显式堆内存管理?

    ##B.14、C++显式堆内存管理?

    ++B.14、C++显式堆内存管理?

    ++++立钻哥哥:C++使用new关键字在运行时给一个对象动态分配内存,并返回堆上内存的地址供应用程序访问,通过动态分配的内存需要在对象不再被使用时通过delete运算符将其内存归还给内存池

    ++++显式的内存管理在性能上有一定优势,但是极其容易出错,事实上,我们总是不能通过人的思维去保证一个逻辑的正确;

    ++++不能正确处理堆内存的分配与释放通常会导致以下问题:

    --1A、野指针:指针指向的内存单元已经被释放,但是其他一些指针可能还指向它,这些内存可能已经被重新分配给其他对象,从而导致不可预测的结果;

    --2B、重复释放:重复释放一个已经被释放的内存单元,或者释放一个野指针(也是重复释放)都会导致C++运行时错误;

    --3C、内存泄露:不再被使用的内存单元如果不被释放就会一直占用内存单元,如果这些操作不断重复就会导致内存占用不断增加,在游戏中内存泄露尤其严重,因为可能每一帧都在创建一个永远不会被回收的游戏对象;

     

     

     

     

     

    ##B.15、C++11中的智能指针?

    ##B.15、C++11中的智能指针?

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    ++立钻哥哥推荐的拓展学习链接(Link_Url)

    ++++立钻哥哥Unity 学习空间: http://blog.csdn.net/VRunSoftYanlz/

    ++++Unity5.x用户手册https://blog.csdn.net/VRunSoftYanlz/article/details/81712741

    ++++Unity面试题ABChttps://blog.csdn.net/vrunsoftyanlz/article/details/78630687

    ++++Unity面试题Dhttps://blog.csdn.net/VRunSoftYanlz/article/details/78630838

    ++++Unity面试题Ehttps://blog.csdn.net/vrunsoftyanlz/article/details/78630913

    ++++Unity面试题Fhttps://blog.csdn.net/VRunSoftYanlz/article/details/78630945

    ++++Cocos2dx面试题https://blog.csdn.net/VRunSoftYanlz/article/details/78630967

    ++++Unity知识点0001https://blog.csdn.net/vrunsoftyanlz/article/details/80302012

    ++++Unity知识点0008https://blog.csdn.net/VRunSoftYanlz/article/details/81153606

    ++++Unity引擎基础https://blog.csdn.net/vrunsoftyanlz/article/details/78881685

    ++++Unity面向组件开发https://blog.csdn.net/vrunsoftyanlz/article/details/78881752

    ++++Unity物理系统https://blog.csdn.net/vrunsoftyanlz/article/details/78881879

    ++++Unity2D平台开发https://blog.csdn.net/vrunsoftyanlz/article/details/78882034

    ++++UGUI基础https://blog.csdn.net/vrunsoftyanlz/article/details/78884693

    ++++UGUI进阶https://blog.csdn.net/vrunsoftyanlz/article/details/78884882

    ++++UGUI综合https://blog.csdn.net/vrunsoftyanlz/article/details/78885013

    ++++Unity动画系统基础https://blog.csdn.net/vrunsoftyanlz/article/details/78886068

    ++++Unity动画系统进阶https://blog.csdn.net/vrunsoftyanlz/article/details/78886198

    ++++Navigation导航系统https://blog.csdn.net/vrunsoftyanlz/article/details/78886281

    ++++Unity特效渲染https://blog.csdn.net/vrunsoftyanlz/article/details/78886403

    ++++Unity数据存储https://blog.csdn.net/vrunsoftyanlz/article/details/79251273

    ++++Unity中Sqlite数据库https://blog.csdn.net/vrunsoftyanlz/article/details/79254162

    ++++WWW类和协程https://blog.csdn.net/vrunsoftyanlz/article/details/79254559

    ++++Unity网络https://blog.csdn.net/vrunsoftyanlz/article/details/79254902

    ++++C#事件https://blog.csdn.net/vrunsoftyanlz/article/details/78631267

    ++++C#委托https://blog.csdn.net/vrunsoftyanlz/article/details/78631183

    ++++C#集合https://blog.csdn.net/vrunsoftyanlz/article/details/78631175

    ++++C#泛型https://blog.csdn.net/vrunsoftyanlz/article/details/78631141

    ++++C#接口https://blog.csdn.net/vrunsoftyanlz/article/details/78631122

    ++++C#静态类https://blog.csdn.net/vrunsoftyanlz/article/details/78630979

    ++++C#中System.String类https://blog.csdn.net/vrunsoftyanlz/article/details/78630945

    ++++C#数据类型https://blog.csdn.net/vrunsoftyanlz/article/details/78630913

    ++++Unity3D默认的快捷键https://blog.csdn.net/vrunsoftyanlz/article/details/78630838

    ++++游戏相关缩写https://blog.csdn.net/vrunsoftyanlz/article/details/78630687

    ++++设计模式简单整理https://blog.csdn.net/vrunsoftyanlz/article/details/79839641

    ++++专题:设计模式(精华篇)https://blog.csdn.net/VRunSoftYanlz/article/details/81322678

    ++++U3D小项目参考https://blog.csdn.net/vrunsoftyanlz/article/details/80141811

    ++++UML类图https://blog.csdn.net/vrunsoftyanlz/article/details/80289461

    ++++U3D_Shader编程(第一篇:快速入门篇)https://blog.csdn.net/vrunsoftyanlz/article/details/80372071

    ++++U3D_Shader编程(第二篇:基础夯实篇)https://blog.csdn.net/vrunsoftyanlz/article/details/80372628

    ++++框架知识点https://blog.csdn.net/VRunSoftYanlz/article/details/80862879

    ++++游戏框架(UI框架夯实篇)https://blog.csdn.net/vrunsoftyanlz/article/details/80781140

    ++++游戏框架(初探篇)https://blog.csdn.net/VRunSoftYanlz/article/details/80630325

    ++++Lua快速入门篇(基础概述)https://blog.csdn.net/VRunSoftYanlz/article/details/81041359

    ++++Lua快速入门篇(XLua教程):https://blog.csdn.net/VRunSoftYanlz/article/details/81141502

    ++++Lua快速入门篇(Xlua拓展):https://blog.csdn.net/VRunSoftYanlz/article/details/81173818

    ++++UnityAPI.Rigidbody刚体https://blog.csdn.net/VRunSoftYanlz/article/details/81784053

    ++++UnityAPI.Material材质https://blog.csdn.net/VRunSoftYanlz/article/details/81814303

    ++++UnityAPI.Android安卓https://blog.csdn.net/VRunSoftYanlz/article/details/81843193

    ++++UnityAPI.AndroidJNI安卓JNIhttps://blog.csdn.net/VRunSoftYanlz/article/details/81879345

    ++++UnityAPI.Transform变换https://blog.csdn.net/VRunSoftYanlz/article/details/81916293

    ++++立钻哥哥Unity 学习空间: http://blog.csdn.net/VRunSoftYanlz/

    --_--VRunSoft:lovezuanzuan--_--

     

    展开全文
  • cocos2dx面试题整理

    2019-10-06 04:21:04
    1、cocos2d-x 3.0里面的数据结构有哪些?简要说明其作用 回答:Cocos2d-x 3.0用Vector和Map<K, V>代替了之前的CCArray和CCDictionary,新的容器类使用模板类来避免了不必要的数据类型转换,同时能够...
    1、cocos2d-x 3.0里面的数据结构有哪些?简要说明其作用

    回答:Cocos2d-x 3.0用Vector和Map<K, V>代替了之前的CCArray和CCDictionary,新的容器类使用模板类来避免了不必要的数据类型转换,同时能够完美地支持标准库中的各种迭代操作,例如std::find(),std::sort()等等。实际上,在3.0中Vector和Map<K,T>是对标准库中std::vector和std::unordered_map<K,T>的封装,使其能够结合Cocos2d-x的内存管理方式
    cocos2d::Vector<T>的一些操作的时间复杂度如下:随机访问,O(1);将元素插入到尾部或者删除尾部的元素,O(1);随机插入或删除, O(n)
    cocos2d::Map<K,V>是使用std::unordered_map作为底层结构的关联式容器。std::unordered_map是一个存储键值对的关联式容器,它可以通过它们的键快速检索对应的值。使用unordered_map,键通常是唯一的,而值则与这个键对应。
           Vector<T>和 Map<K,V>通常用来和 autorelease 一起工作,我们通常应该将一个autorelease 对象加入到 Vector 或者 Map 中,例如 Node 将所有的子元素存储在一个 Vector<Node*>中。Vector 和 Map 对新加入的元素执行 retain 操作,并对从中移除的元素执行 release 操作,这样元素在从 Vector 或者 Map 中移除的时候就会被自动释放。
    2、 Cocos2d-­‐x 内存管理机制 

    回答:Cocos2d-­‐x 中所有内存管理方式的基础是引用计数,动态分配一个 Ref 对象后其引用计数为 1,并通过 retain 和 release 来增持和减少其引用计数。引用计数本身并不能帮助我们进行内存管理。 为了正确地释放对象的内存, Cocos2d-­x 使用 Objective-­C 里面的自动回收池的机制来管理对象内存的释放。Autorelease 有点类似于一个共享的”智能指针”,该”智能指针”的作用域为一帧,该帧结束后,它将释放自己的引用计数,此时,如果该对象没有被其他”共享指针”引用, 则对象被释放。 如果对象被引用, 则保留。

    3、cocos2d-x的图形渲染机制?
    回答: 顶点着色(顶点坐标变幻等一系列操作)———>几何着色器(添加或删除部分顶点)———>光栅化(把数据信息转化成像素信息)———>片段着色器(把像素显示到屏幕上)着色器==其他操作(比如深度测试,光线叠加等)
    CCApplication::sharedApplication()->run()----》 CCDirector::sharedDirector()->mainLoop()----》drawScene();
    4、cache的机制原理
    回答:把新加进内存的资源做一个hashmap存储,每一个资源加一个key。每次加载资源的时候,先查找资源是否存在,存在直接返回,否则加载进内存。
    5、场景切换的内存处理过?
    回答:先构建新场景,然后显示新场景,然后释放旧场景。
    但是在新场景onEnter,旧场景onExit的时候,会调用旧场景的cleanup,清理schedule相关部分。
    6、动作回掉函数是怎么作用的气原理是什么?
    回答:target(回调对象指针)加 selector(回调函数指针)。
    7、有哪些操作会导致内存泄露,如果发生内存泄露如何处理?
     回答:在堆上分配动态内存和释放动态内存的方法是 new 和 delete,在申请内存之后,如果不使用了就需要delete掉,不然就会造成内存的溢出。解决办法:使用vld、memwatch加载到项目中,调试
    8、cocos2d-x游戏储存
    回答:CCUserDefault和SQList
    CCUserDefalt存在的的问题
    1.没有记录和表的概念
    你会发现,如果要设置多存档,必须自己操作,而且代码会变得复杂,容易出错。
    对于简单的游戏可以使用CCUserDefalt,但是对于复杂游戏,可以考虑使用SQLite。
    2.没有数据类型安全
    比如,如果你错写把一个Integer按Bool读取,是没有错误提示的
    3.没有存档数据完整性的校验
    我们找到之前的存档记录,用CCUserDefault::getXMLFilePath()可以获得存档位置,打开它。
    9、简述CCSpriteframeCache CCSpriteBatchNode?
    回答:CCSpriteFrameCache 缓存了所有CCSpriteFrame. 可以一下方式获取特定frame并设定给Sprite. 前提是文件已经缓存
    CCSpriteBatchNode 中的所有CCSprite只会被渲染1次,因此可以提高游戏的FPS。
    限制:加入到CCSpriteBatchNode 中的CCSprite必须使用同一张纹理图。
    10、cocos2d-x的屏幕适配解决方案?
    回答:pEGLView->setDesignResolutionSize(480, 320, kResolutionNoBorder);第三个参数,
    kResolutionExactFit:会靠拉伸来填满屏幕,举例来说背景图会变形来填充屏幕,因为1024:768=1.3, 480:320=1.5,宽高比不同,图片也就无法等比缩放来填满屏幕,只能变形了。
    kResolutionNoBorder: 看不到黑边,实际就是宽高等比缩放,但缩放比例取宽比和高比之中大的那一个。
    kResolutionShowAll:全部显示,可以理解为保证内容都显示在屏幕之内,实际也是宽高等比缩放,但缩放比例取宽比和高比之中小的那一个。
    11、减少内存开销的方法有哪些?图片压缩方法有哪些?
    回答:及时释放,减少泄露,重用资源,plist,延迟加载,分部加载等。
    调整加载图片的方式,改变图片的格式,.pvr,pngquant压缩图片 、32位图片改为16图片加载。
    12、autorelease和release的区别?
    autorelease封装了retain和release,它会把类加入到autoreleaseManager进行管理,在autoreleaseManager里,通过autoreleasePool进行自动加减引用数目(refrence),retain 和release类似于new 跟delete,
    retain会对object引用计数加1,release会对object引用计数减1,retain跟release要成对使用,如果我们新创建一个实例,这个实例已经加入到autorelease,但是我们没有马上使用这个实例,我们需要对这个实例进行retain操作,在其他地方引用之后,对其进行release操作。
    release是立即释放引用计数,如果到达0,对象被销毁。autorelease是延迟释放,是为了更好管理内存产生的。
    autorelease的实现机制,是将对象加入一个pool统一管理,当pool被release时,pool里面每个对象都会被release。pool基于一个栈式结构管理,每一个mainloop会pop一次。同一个mainloop里面调用autorelease,会把引用加入栈顶pool。

    转载于:https://www.cnblogs.com/Anzhongliu/p/6091808.html

    展开全文
  • cocos2dx面试题-第二波

    千次阅读 2014-10-06 11:27:56
    作者:xxiaoye ...昨天听了腾讯2015校招的在线宣讲会,看到了游戏技术大拿Steven,他总结了需要的达人得爱技术,... 网上关于cocos2d-x的面试题比较少,这里搜集和整理了一写网上关于cocos2d-x游戏开发的面试题
  • cocos2dx面试题(2)

    2014-08-29 18:31:05
    2.cocos2d-x的图形渲染机制是什么  只知道是每一帧调用mainloop,然后drawScene。 3.cache机制原理是什么  把新加进内存的资源做一个hashmap存储,每一个资源加一个key。每次加载资源的时候...
  • 阐释cocos2dx的框架(内存管理,调度,事件等)? 写出下面函数的输出结果是多少,假设x=88 int f(int input) {  int encounter = 0;  while(input)  {  encounter++;  input = input&(input-1);  }  ...
  • [Cocos2dx]面试题汇总一

    千次阅读 2017-02-08 21:54:47
    最新在网上找Cocos2dx/C++的面试题,觉得很是麻烦,特别在这总结一下,有些是亲身经历有些是朋友经历。 1、int占多少字节? 4位 2、sizeof和strlen的区别 ...3、static_cast, dynamic_cas
  • Cocos2d-X面试题

    2015-10-12 23:29:54
    cocos2dx面试题,面试必备品
  • 几道关于cocos2dx面试题

    千次阅读 2016-07-04 13:22:53
    网上关于cocos2d-x的面试题比较少,这里搜集和整理了一写网上关于cocos2d-x游戏开发的面试题。希望对找工作的同学有帮助。如有错误,请拍砖。   1、Cocos2d-x是怎样实现跨平台?    AppDelegate 作为跨平台程序...
  • [Cocos2dx]面试题汇总三

    2017-02-09 21:17:24
    1.autorelease和release的区别 ... 如果不调用语句1语句2,会导致内存泄露,根据函数定义原则,谁污染谁治理,如果要求外部调用者释放,不科学。  如果调用语句1,会立即被释放,外部调用者无法获取对象。  调用
  • [Cocos2dx]面试题汇总二

    2017-02-09 20:41:40
    2cocos2d-x内管管理  目前主要有两种实现智能管理内存的技术,一种是引用计数,一种是垃圾回收。Cocos2d-x 采用的是引用计数机制。为此实现了自己的根类Ref,每个对象都包含了一个用来控制生命周期的引用...
  • Cocos2dx基础使用相关面试题

    万次阅读 2016-04-16 16:39:25
    根据上次去面试人家HR所提的一些问题做的整理,答案部分是网上找的,关于基础使用,大致会问如下几个问题: Cocos2d-x的执行流程和基础对象 Cocos2d-x对相关工具的了解 Cocos2d-x其他常见问题 如是如何进行...
  • 面试题目cocos2dx和c++

    2015-04-14 10:29:10
    c++面试题,给面试者一个学习的机会,我们公司就是用这个面试题招人的,加油,小伙伴们!
  • cocos2d-x面试题(一)

    千次阅读 2016-09-27 15:55:13
    cocos2dx
  • 1、内存 2、内存管理方法 3、适配 4、图片处理 5、卡顿问题
  • 在前天去面试实习生的时候,前台给了一张答题卷填写,因为我也不知道我具体能做什么,对做游戏也是感兴趣,所以就选了游戏开发,第一页大多都是问一些概念与看法,后一页则是一些算法,做了前面的小,我感觉有几个...
  • 今天去面试一道上机,要求实现一个效果,一个精灵围绕另一个精灵旋转。 结果发现,精灵旋转的中心位置不对,老是围绕中心精灵的左下角旋转。 我以为设置锚点可以解决这个问题,可是反复试了好几次都没有...
  • 手游2dx面试笔记一

    千次阅读 2013-09-26 23:11:54
    第一轮IQ测试:都来面试程序了,相信IQ再怎么也坑不到...第二轮一问一答:描述简绘cocos2dx框架、游戏架构、cocos2dx切换场景时做了什么事、排序算法、设计模式、接入sdk做分享功能、做过什么游戏(做过什么游戏的什么
  • 面试题2

    2016-07-08 15:26:40
    1、如何避免内存泄漏,如何查找内存泄漏。 -1....2、列举cocos2dx内常用设计模式,并举例说明。 -1:单例模式:Director,FileUtils,UserDefaults等等 -2:观察者模式: -3:工厂模式 -4:二段式
  • 仅仅是本人收到的,一般是电面。 MS: 口语介绍自己和项目 tech: c++ 虚函数应用 ...cocos2dx内存管理机制 使用c++内存管理的效率和经验 网易: 数据查询优化策略 list和map的实现 多线程valitil
  • java程序员面试中的多线程问题

    千次阅读 2016-04-17 18:11:53
    原文:Sachin FromDev 编译:伯乐在线 –刘志军 来源: 伯乐在线 SpringMVC数据绑定入门 征战Objective-C ...Cocos2dx坦克大战–中 很多核心Java面试题来源于多线程(Multi-Threading)和集合框架

空空如也

空空如也

1 2
收藏数 32
精华内容 12
关键字:

cocos2dx面试题