Cocos2d-x Architectural Patterns
Cocos2d-x has a mature scene-graph architecture centered on the Director and Node tree. Understanding its internals lets you design for performance: batched rendering, minimal state changes, and memory discipline on mobile.
1. The Director Lifecycle
The Director singleton drives the game.
Director::mainLoop()
-> calculateDeltaTime()
-> update() // scheduled updates + physics step (if enabled)
-> drawScene() // render current scene
Director::runWithScene() sets the initial scene.
Director::replaceScene() swaps current scene (with optional transition).
Director::pushScene()/popScene() for pause menus layered over gameplay.
1.1 Frame pacing
Director::setAnimationInterval(1.0/60.0) sets the desired FPS.
- On mobile, respect
setProjection/retina scaling (CC_CONTENT_SCALE_FACTOR).
- Headless tests:
Director::setHighResFactor(0) for pure-logic runs.
2. Scene Graph & Node Tree
Node is the base: position, rotation, scale, skew, opacity, anchor point, children, z-order.
- Transform hierarchy: local transforms multiplied up the chain → world MVP.
addChild(node, zOrder).
- Depth-first traversal via
visit().
2.1 Transforms & Anchor Points
setAnchorPoint() affects position relative to bounds (Cocos uses anchor = [0,1] vs Unity center).
- 2D games: work with
Vec2/Size; world coordinates via convertToWorldSpaceAR.
- Be careful with parent scale/rotation affecting child positions — standard matrix chaining.
2.2 Event System
EventListenerTouchOneByOne / EventListenerTouchAllAtOnce.
- Custom events:
EventDispatcher::dispatchCustomEvent("name", &data).
- Input -> mouse/touch classification abstracted by
Input singleton.
- Listeners attach to nodes (
node->addEventListener()); remember to remove on onExit.
3. Rendering Architecture: The Render Queue
Draw calls are NOT issued during traversal. Node::visit() pushes RenderCommands into a Renderer queue:
visit() -> pushCommand(RenderCommand) for each node
Renderer::render() -> sort commands (by z-order; transparent after opaque)
-> group by texture/shader to batch draw calls
-> flush GPU commands
3.1 Batching Strategy
- SpriteBatchNode /
TextureAtlas: keep many sprites sharing ONE texture; they draw in one batch.
Renderer batches consecutive commands with the same texture + shader.
- Sorting: opaque up-front (no blending), transparent sorted back-to-front.
3.2 Reducing Draw Calls (mobile gold)
- Pack art into atlases → fewer texture switches.
- Use
SpriteBatchNode for repeated textures.
- Keep materials/shader switches minimal (MVV per vertex, no per-sprite shader).
- Avoid per-node opacity/rotation trick for static UI; group static UI into one node.
- Disable depth test for 2D when not needed.
3.3 Custom Rendering
- Subclass
Node and override draw(Renderer*) to push custom TrianglesCommand/CustomCommand.
Renderer supports custom geometry (a quad list) — great for particle trails, vector UI.
4. Action System (Animation Without Code)
Actions: MoveTo, Sequence, Spawn, RepeatForever, EaseIn.
node->runAction(...); actions run inside Node::i update loop on the main thread.
- Hierarchy:
Sequence/Spawn composite actions; ActionInterval for timed.
Director::getScheduler() controls update priorities of actions.
4.1 Scheduler
scheduler->schedule(...) with time intervals; update(dt) for every frame.
scheduleUpdate() / unscheduleUpdate() on nodes.
- Pause/Resume: scheduler respects
Director::pause().
5. Physics in Cocos2d-x
- 2D: Box2D is the common physics backend (via
PhysicsBody / PhysicsWorld or direct Box2D).
- 3D: Cocos2d-x has a lightweight 3D physics module (mostly unmaintained → prefer external).
PhysicsBody::createBox, PhysicsWorld integrated to scene.
- Fixed timestep via scheduler; collisions:
EventListenerPhysicsContact.
5.1 Sensor pattern
Create a body with PhysicsMaterial(), set setSensor(true) for triggers, listen onContactBegin for overlap detection.
6. Memory & Resource Management
Ref/RefCounted-style retention: retain()/release() (Cocos uses its own Ref).
TextureCache::sharedTextureCache()->addImage() caches textures (avoid duplicate loads).
SpriteFrameCache for atlases.
ResourcesManager for transparent asset handling.
- Rule: keep references to big assets;
removeUnusedTextures() after scene transitions.
6.1 Pooling Pattern
// recycle simple objects to avoid alloc/free churn
auto pool = NodePool::getInstance("bullet");
auto bullet = pool->getFromPoolOrCreate(...);
bullet->setPosition(pos);
this->addChild(bullet);
// on death: pool->returnToPool(bullet)
7. Cross-Platform Build Pattern
- Engine wraps platform code (
platform/): iOS/Win32/Android/Mac/Linux; define __APPLE__, CC_PLATFORM_* macros.
- Resource paths: use
FileUtils::getInstance()->fullPathForFilename(); Assets folder mapped per-platform.
- Audio:
AudioEngine::play2d; OGG/MP3/WAV platform-specific loading via AudioDecoder.
- Bundle assets: pack into
.res or Atlas; on Android use assets/.
7.1 Cocos Creator 3.x vs Cocos2d-x
|
Cocos2d-x (C++) |
Cocos Creator (TS/editor) |
| Language |
C++ |
TypeScript |
| Rendering |
OpenGL ES/Metal |
Vulkan/GL/Metal (multibackend) |
| Editor |
none (code-first) |
full editor + scene system |
| Use case |
perf-critical, engine-level |
team-based game dev |
8. Common Anti-Patterns
| Anti-pattern |
Consequence |
Fix |
| One texture per sprite |
Draw call explosion |
atlas + batch node |
per-node retain() leaks |
memory growth |
pooled/refcache |
| Actions recreated each frame |
alloc churn |
reuse cached actions |
Global Director misuse in logic |
scene-restart bugs |
keep in scene node |
| blocking file loads |
UI stalls |
async load + cache |
9. Decision Tree
flowchart TD
A{2D game?} -->|Yes| B{Same texture heavy?}
A -->|No| C[Use full 3D engine instead]
B -->|Yes| D[SpriteBatchNode + Atlas]
B -->|No| E[Standard Sprite renderer]
D --> F[pool + async load]
E --> F
10. References
skills/game/cocos2d/SKILL.md — full Cocos2d game dev guide
- Cocos2d-x docs on Renderer, Director, Node, Actions, Physics
1---2name: cocos2d-patterns3description: Cocos2d-x architectural patterns - Director main loop, scene graph, render queue and batching, event system, memory management, and cross-platform build patterns.4---56# Cocos2d-x Architectural Patterns78Cocos2d-x has a mature scene-graph architecture centered on the `Director` and `Node` tree. Understanding its internals lets you design for performance: batched rendering, minimal state changes, and memory discipline on mobile.910## 1. The Director Lifecycle1112The `Director` singleton drives the game.1314```15Director::mainLoop()16 -> calculateDeltaTime()17 -> update() // scheduled updates + physics step (if enabled)18 -> drawScene() // render current scene19```2021- `Director::runWithScene()` sets the initial scene.22- `Director::replaceScene()` swaps current scene (with optional transition).23- `Director::pushScene()/popScene()` for pause menus layered over gameplay.2425### 1.1 Frame pacing2627- `Director::setAnimationInterval(1.0/60.0)` sets the desired FPS.28- On mobile, respect `setProjection`/retina scaling (`CC_CONTENT_SCALE_FACTOR`).29- Headless tests: `Director::setHighResFactor(0)` for pure-logic runs.3031## 2. Scene Graph & Node Tree3233- `Node` is the base: position, rotation, scale, skew, opacity, anchor point, children, z-order.34- Transform hierarchy: local transforms multiplied up the chain → world MVP.35- `addChild(node, zOrder)`.36- Depth-first traversal via `visit()`.3738### 2.1 Transforms & Anchor Points3940- `setAnchorPoint()` affects position relative to bounds (Cocos uses anchor = [0,1] vs Unity center).41- 2D games: work with `Vec2`/`Size`; world coordinates via `convertToWorldSpaceAR`.42- Be careful with parent scale/rotation affecting child positions — standard matrix chaining.4344### 2.2 Event System4546- `EventListenerTouchOneByOne` / `EventListenerTouchAllAtOnce`.47- Custom events: `EventDispatcher::dispatchCustomEvent("name", &data)`.48- Input -> mouse/touch classification abstracted by `Input` singleton.49- Listeners attach to nodes (`node->addEventListener()`); remember to remove on `onExit`.5051## 3. Rendering Architecture: The Render Queue5253Draw calls are NOT issued during traversal. `Node::visit()` pushes `RenderCommand`s into a `Renderer` queue:5455```56visit() -> pushCommand(RenderCommand) for each node57Renderer::render() -> sort commands (by z-order; transparent after opaque)58 -> group by texture/shader to batch draw calls59 -> flush GPU commands60```6162### 3.1 Batching Strategy6364- **SpriteBatchNode / `TextureAtlas`**: keep many sprites sharing ONE texture; they draw in one batch.65- `Renderer` batches consecutive commands with the same texture + shader.66- Sorting: opaque up-front (no blending), transparent sorted back-to-front.6768### 3.2 Reducing Draw Calls (mobile gold)69701. Pack art into atlases → fewer texture switches.712. Use `SpriteBatchNode` for repeated textures.723. Keep materials/shader switches minimal (MVV per vertex, no per-sprite shader).734. Avoid per-node opacity/rotation trick for static UI; group static UI into one node.745. Disable depth test for 2D when not needed.7576### 3.3 Custom Rendering7778- Subclass `Node` and override `draw(Renderer*)` to push custom `TrianglesCommand`/`CustomCommand`.79- `Renderer` supports custom geometry (a quad list) — great for particle trails, vector UI.8081## 4. Action System (Animation Without Code)8283- `Action`s: `MoveTo`, `Sequence`, `Spawn`, `RepeatForever`, `EaseIn`.84- `node->runAction(...)`; actions run inside `Node::i` update loop on the main thread.85- Hierarchy: `Sequence`/`Spawn` composite actions; `ActionInterval` for timed.86- `Director::getScheduler()` controls update priorities of actions.8788### 4.1 Scheduler8990- `scheduler->schedule(...)` with time intervals; `update(dt)` for every frame.91- `scheduleUpdate()` / `unscheduleUpdate()` on nodes.92- Pause/Resume: scheduler respects `Director::pause()`.9394## 5. Physics in Cocos2d-x9596- 2D: Box2D is the common physics backend (via `PhysicsBody` / `PhysicsWorld` or direct Box2D).97- 3D: Cocos2d-x has a lightweight 3D physics module (mostly unmaintained → prefer external).98- `PhysicsBody::createBox`, `PhysicsWorld` integrated to scene.99- Fixed timestep via scheduler; collisions: `EventListenerPhysicsContact`.100101### 5.1 Sensor pattern102103Create a body with `PhysicsMaterial()`, set `setSensor(true)` for triggers, listen `onContactBegin` for overlap detection.104105## 6. Memory & Resource Management106107- `Ref`/`RefCounted`-style retention: `retain()/release()` (Cocos uses its own `Ref`).108- `TextureCache::sharedTextureCache()->addImage()` caches textures (avoid duplicate loads).109- `SpriteFrameCache` for atlases.110- `ResourcesManager` for transparent asset handling.111- **Rule**: keep references to big assets; `removeUnusedTextures()` after scene transitions.112113### 6.1 Pooling Pattern114115```cpp116// recycle simple objects to avoid alloc/free churn117auto pool = NodePool::getInstance("bullet");118auto bullet = pool->getFromPoolOrCreate(...);119bullet->setPosition(pos);120this->addChild(bullet);121// on death: pool->returnToPool(bullet)122```123124## 7. Cross-Platform Build Pattern125126- Engine wraps platform code (`platform/`): iOS/Win32/Android/Mac/Linux; define `__APPLE__`, `CC_PLATFORM_*` macros.127- Resource paths: use `FileUtils::getInstance()->fullPathForFilename()`; Assets folder mapped per-platform.128- Audio: `AudioEngine::play2d`; OGG/MP3/WAV platform-specific loading via `AudioDecoder`.129- Bundle assets: pack into `.res` or Atlas; on Android use `assets/`.130131### 7.1 Cocos Creator 3.x vs Cocos2d-x132133| | Cocos2d-x (C++) | Cocos Creator (TS/editor) |134|--|------------------|---------------------------|135| Language | C++ | TypeScript |136| Rendering | OpenGL ES/Metal | Vulkan/GL/Metal (multibackend) |137| Editor | none (code-first) | full editor + scene system |138| Use case | perf-critical, engine-level | team-based game dev |139140## 8. Common Anti-Patterns141142| Anti-pattern | Consequence | Fix |143|--------------|-------------|-----|144| One texture per sprite | Draw call explosion | atlas + batch node |145| per-node `retain()` leaks | memory growth | pooled/refcache |146| Actions recreated each frame | alloc churn | reuse cached actions |147| Global `Director` misuse in logic | scene-restart bugs | keep in scene node |148| blocking file loads | UI stalls | async load + cache |149150## 9. Decision Tree151152```mermaid153flowchart TD154 A{2D game?} -->|Yes| B{Same texture heavy?}155 A -->|No| C[Use full 3D engine instead]156 B -->|Yes| D[SpriteBatchNode + Atlas]157 B -->|No| E[Standard Sprite renderer]158 D --> F[pool + async load]159 E --> F160```161162## 10. References163164- `skills/game/cocos2d/SKILL.md` — full Cocos2d game dev guide165- Cocos2d-x docs on Renderer, Director, Node, Actions, Physics