花了两个月陆陆续续地把这本书读完,觉得总体上是一本很不错的书。作者以前参与过cocos引擎的开发,因此是以自己的角度讲解cocos引擎,不同于市面上很多单纯罗列cocos api和代码的书,而是结合OpenGL ES和图形学,对于cocos的讲解深入到引擎实现层面。看完之后,对于cocos引擎的各方面:渲染、纹理、事件分发、物理引擎等都有比较深入的了解。
另外也有一些不足之处:部分章节编排显得散乱,正如作者所写,他的写作方法是先把相关资料都搜罗在一起,然后再整理目录结构。在讲解渲染的时候,作者本意是想融合OpenGL ES和图形学的知识,但是有的地方讲解不甚清楚,跳跃性较强,需要较好的图形学功底才容易理解。另外,最后几章的结束显得略微草率。
第一章 全新的Cocos2d-x 3.0
- cocos2d-x 3.x的几项重大改动:新的渲染系统、统一的事件系统、深度集成的物理系统、C++的命名风格
- 基于RenderCommand 的新渲染系统
- 可组合(自动批处理),减少绘制次数,提升性能
- 可排序:globalZOder > localZOrder > orderOfArrival
- Sprite的自动剔除
- 统一的事件分发器EventDispatcher,将事件关联到UI元素
- cocos 3.x新的数据结构:Vector<T>和Map<K, V>,push时retain, popBack时release
- cocos的内存管理机制:
- 继承Ref类的对象都可以被管理,每一帧都会把引用计数为0的对象释放
- retain会让计数加1,release会减1
- addChild会自动调用retain
- create会自动调用autoRelease
- C++风格:随着与cocos-iPhone的分离,从OC风格转成C++,CCSprite -> Sprite
第2章 Cocos2d-x架构一瞥
- cocos引擎的主要组成:渲染系统、物理系统、事件系统、动画及纹理系统、内存管理及调度器
- 内存管理详解:
- new会让引用计数加1
- create = new + autorelease(添加到AutoreleasePool)
- 每一帧对Pool中每个对象,做release(引用计数减1,若减到0则释放)
- 对于想提前释放的Ref对象,可以使用自定义AutoreleasePool来即时清理
- anchorPoint和position共同决定了元素的位置
- UI树和绘制顺序
- localZOrder:将UI树结构和绘制顺序绑定
- globalZOrder:更灵活
- 具体绘制流程
- 对globalZOrder不为0的元素按值排序
- 对其余元素,按localZOrder。对每个元素做中序遍历:
- 遍历左边子节点(所有localZOrder小于0的直接子节点,且按升序排列)
- 遍历当前元素
- 遍历右边子节点(所有localZOrder大于0的直接子节点,且按升序排列)
- autorelease本质是延迟释放,将Pool中所有不在UI树中的元素释放;addChild/removeFromParent -> Vector的push/popBack -> retain/release
- Application的子类AppDelegate定义了游戏生命周期各个阶段的处理:启动后,切后台,切前台
- 设计分辨率和实际分辨率
- pushScene和replaceScene
- 游戏循环详细过程:用户输入 -> 动画 -> 物理模拟 -> 逻辑更新(与物理模拟顺序不一定) -> UI树遍历 -> 渲染 -> 交换缓冲区 -> 自动释放
- Scheduler的两种方式:
- scheduleUpdate: 可指定priority,性能更好
- schedule:可指定interval,repeat,delay
- Scheduler的priority根据逻辑而不是对象:
- ActionManager:永远最低
- PhysicsWorld:0
- CustomLogic:自定义
- 避免在每帧做复杂的查找或者迭代运算,以免影响性能
- Cocos2d-x是一个单线程的引擎,许多异步处理的结果须在主线程完成;如异步纹理加载,回调addImageAsyncCallBack每一帧处理一个纹理,上传到GL内存中(GL命令耗时且必须在主线程中执行)
第3章 OpenGL ES 2.0概览
- GPU vs CPU: 并行 vs 串行;衡量GPU性能参数:pps
- OpenGL ES渲染管线:
- 顶点数组:所有图元primitive的顶点信息
- 顶点着色器:计算顶点的坐标、颜色、光照等;顶点坐标变换;提供易变变量
- 图元组装:视锥体相关的一些坐标变换
- 光栅化:图元转成片段fragment(像素),计算插值
- 片段着色器:计算每个片段(像素)的颜色值,实现特殊效果(阴影、描边、闪光
- 片段测试:深度测试、模板测试、混合
- 帧缓冲:每个像素点的最终信息(颜色、深度、模板值),双buffer切换
第4章 全新的绘制系统
- 新的绘制系统的特点:
- UI树遍历和绘制分离
- 自动批处理和自动裁剪
- 自定义绘制命令
- 绘制流程
- 遍历UI树并生成RenderCommand(根据localZOrder:遍历顺序)
- 排序(根据globalZOrder:绘制顺序)
- 执行绘制(自动批处理)
- RenderCommand分类:
- QuadCommand:Sprite和ParticleSystem;自动批处理:相邻的QuadCommand使用同样的纹理
- BatchCommand:TextureAtlas,性能更好,但不能参与自动批绘制
- GroupCommand:ClippingNode和RenderTexture,包装多个RenderCommand且不参与全局排序
- CustomCommand:自定义
- 自定义RenderCommand例子:新手教程实现其余区域半透明
- 多重采样:抗锯齿
第5章 纹理
- 纹理:通过TextImage2D命令定义的像素矩形;纹素
- 纹理 + 光栅化采样 -> 片段着色器
- 纹理坐标:uv型(纹理宽高)和st型(最大是1)
- 解包:客户端(format和type定义格式的像素数据) -> GL服务端(浮点型RGBA像素值);打包:GL服务端 -> 客户端
- PNG、JPG等格式在使用时需先转成cocos支持的指定格式(如RGBA8888)
- 纹理缩放
- 缩小:多个纹素 -> 一个像素
- 放大:一个纹素 -> 多个像素
- 多级纹理:通过图像金字塔适配不同分辨率
- 纹理压缩:
- ios:PVRTC
- android:ETC
- 纹理对象的管理:
- TextureCache
- 自己封装ResourceManager
- 纹理所占内存的计算 result = width * height * bpp / 8
- 纹理使用优化:
- 引擎商和硬件商合作定制优化
- 提前加载资源
- 即使清除不用的资源
- 合图
- 多级纹理:
- 减少内存:只上传所需级别的纹理
- 减少计算量:无需加载时再计算
- 选择适当的资源格式(RGBA8888,RGBA4444)
- 使用压缩纹理
第6章 精灵
- 精灵:游戏中的元素,纹理的一部分(关联到Texture2D对象)
- 使用精灵的好处:
- 自动批绘制
- 在一组元素中使用精灵,单个的属性(位置、颜色、缩放等)控制比较灵活
- RGBA
- R、G、B:三基色通道,0-255,值越大越亮,0表示黑色,255表示最亮,都为255时为白色。
- A:Alpha通道,不透明度,0-1,值越大越不透明
- 颜色混合:多个图层之间的混合
- 混合规则:定义RGBA各向量的加成规则
- 深度测试会将较远的位于非透明图元之后的部分丢弃
- 颜色叠加:将一个颜色作用在当前图层,如角色受攻击后闪动红色
- 颜色叠加可以沿UI树递归传递
- 每个Node拥有displayColor = realColor * parentColor / 255
- Alpha预乘:
- 对于颜色混合的计算:(Rs, Gs, Bs) * As + (Rd, Gd, Bd) * (1 - As),提前乘好Alpha通道的值
- 优点:减少计算量,提高性能;缺点:预乘减小了颜色精度
- 精灵表:合图,将多个精灵合并在一张图上,通过配置文件(plist)表示每个精灵的位置
- frameCache:addSpriteFrames(.plist) 通过plist将spriteFrame加入spriteFrameCache
- 同时会将对应的纹理加入textureCache
- 精灵动画:都通过配置文件来定义
- 帧动画:每帧间隔、关键帧的spriteFrame、来自精灵表
- 骨骼动画:
- 使用SpriteBatchNode的批绘制
- 多个Sprite需放在同一个SpriteBatchNode下
- 使用不便,不如自动批绘制
- 部分拉伸:Scale9Sprite,底层使用SpriteBatchNode
- 自动批绘制的条件(同一次绘制)
- 同一张纹理
- 相同的BlendFunc设置
- 相同的Shader程序
- 顺序上相邻
第7、8章 OpenGL ES着色语言和程序
- OpenGL ES着色语言可以用来编写着色器程序
- 存储限定符
- attribute:应用程序传给顶点着色器
- uniform:应用程序传给顶点着色器和片段着色器
- varying:顶点着色器传给片段着色器,经过插值的易变量
- 顶点缓冲对象,顶点数组对象(VAO)
- cocos着色器子系统:Node 多<->一 GLProgramState 多<->一 GLProgram
- 着色器编辑工具
第9、10章 帧缓冲、片段操作
- GroupCommand <-> RenderTexture <-> 帧缓冲
- 帧缓冲的逻辑缓冲区:
- 颜色
- 深度
- 模板
- 片段操作和测试:从片段着色器到帧缓冲
- 像素所有权测试
- 裁剪测试
- 模板测试:裁剪、光照阴影
- 深度测试:遮挡
第11章 多分辨率支持
- 资源分辨率,设计分辨率,应用分辨率
- 5种缩放策略:
- EXACT_FIT(非等比)
- NO_BORDER
- SHOW_ALL
- FIXED_HEIGHT
- FIXED_WIDTH
- 不要写死绝对坐标,而是根据visibleSize自适应
- 设置资源缩放因子,程序中提供一套不同分辨率的资源,使用不同的搜索路径
第12章 事件分发
- 事件分发模型:订阅者模式,事件分发者,订阅者,好处:解耦合
- 订阅时可指定关联Node或优先级,对于多个订阅者,分发的顺序:
- 优先级小于0的订阅者
- Node绘制的顺序
- 优先级大于0的订阅者
- 多点触摸 EventListenerTouchAllAtOnce 单点触摸 EventListenerTouchOneByOne
- 飞机移动例子:指定关联到fighter,再实现began和move事件的处理函数
- setSwallowTouches可以阻止一个触摸点向后面的订阅者继续分发
第13章 字体的故事
- 轮廓字的发展:PostScript(Adobe) -> Type 1(Adobe) -> TrueType(Apple, MS) -> FreeType(iOS, Android,cocos支持)
- Label的创建
- createWithTTF:轮廓字,效率稍低
- createWithBMFont:点阵字,通过纹理生成,效率高,但不支持所有中文
- Label的特效:阴影,描边,发光
第14章 动画系统
- 动画系统基于线性插值
- Action,MoveTo, Sequence, Spwan, Repeat
- 加速是通过dt * speed(基于时间片而不是帧率)
- 收到伤害时闪白的实现:在动画开始时使用自定义的着色器
第15章 碰撞及物理引擎
- Box2D和Chipmunk2D(cocos使用)
- 碰撞检测基于刚体,刚体有自己的范围
第16、17章 运行时对象数据模型、Genius-x开源框架
- Entity Component System:以属性为中心的架构风格
- 代表:genius-x,cocos creator
第18章 脚本
- lua使用虚拟栈和C传递值
- cocos 3.0使用bindings-generator来生成绑定代码,基于tolua++,比原来的tolua更方便