Design Patterns in Cocos2d-x

Introduction

The article will be interesting for Cocos2d-x developers and those who study patterns. It is a short review, in which you can quickly see where a particular pattern is applied in Cocos2d-x. The full description of each pattern is not the purpose of this article.

Creational Patterns

Prototype

Prototype defines the interface for copying an object. A new object is created by copying the state of the object. For example, if we call clone() on an Animation object, we'll create an Animation object with the same parameters.

Image title

Singleton

Come on.

Structural Patterns

Flyweight

Flyweight should be used for the separate use of the same resources without creating a large number of instances of the same resource. This makes it possible to effectively use memory. This pattern is well suited for displaying text.

To display text, use the Label class. To display the text we need a font. To get a TTF font, use the getFontAtlasTTF method of the FontAtlasCache class. FontAtlasCache is a pool of all fonts used in the application. The font is stored as long as at least one object uses it. If we have 10 Label objects with the same font, they all use the same instance of the FontAtlas class.

Image title

FontAtlas contains the data to display the symbol - the texture and coordinates. The texture size is typically 512x512 and some textures may be more than that if all the symbols do not fit into one. The character is created if the same object used it. Label receives the FontLetterDefinition structure for each character from FontAtlas. Based on the data from this structure, Label creates a sprite and puts it in its BatchNode. In general, we can see how thoroughly the Label is optimized.

Image title

Another good example of the separate use of resources is the use of textures by sprites. The texture for each downloaded file is stored in a single copy. Several sprites created from the same file will refer to a single instance of the texture.

Image title

We can find some regularity - if the class name ends with Cache, then it produces objects for separate use.

Bridge

Bridge decouples an abstraction from its implementation. This pattern is most often used to implement cross-platform objects. A Classic Bridge can be found in EditBox and Downloader.

Image title

Image title

Also, this pattern is well suited for GLView, AudioEngine, Controller, and WebView. However, these objects have different ways of implementing the same task - decoupling an abstraction from its implementation.

Composite

The task of Composite is to build trees and unify access to tree components. Usually, the Composite scheme looks like this:

Image title

Compositeis a compound object consisting of several objects inherited from the Component. Thus, we can perceive several objects as one. In Cocos2d-x, Node is both a Composite and a Component.

Image title

The graph-scene is created using Node in which each of its nodes is a Node.

Behavioral Patterns

Command

Commandencapsulates the request as an object, thereby letting request to be queued. Other use cases will not be considered. In Cocos2d-x, this pattern is used to create a queue for the Renderer. Thanks to this pattern, the use of the OpenGL API inside the objects was removed. The same code for OpenGL is placed in the same command and is not copied several times. It can also facilitate the transition to other graphical APIs, but it will not make it easy.

Image title

Observer

This pattern defines a one-to-many dependency between objects. In Cocos2d-x, the subject is the EventDispatcher, and the observer is the EventListenerEventDispatcher is not a singleton, we can inherit from it our EventDispatcher. A director via EventDispatcher notifies observers about changes in the state of the accelerometer, mouse, keyboard, etc. You can also create custom events (EventCustom). These events have a name and data to be sent to the observer. This is an alternative to NotificationCenter which is already marked as deprecated. Director also defines several useful EventCustoms, for example, EVENT_BEFORE_UPDATE, EVENT_AFTER_UPDATE, and others. EVENT_BEFORE_UPDATE is useful for working with Box2D. For example, before updating the physical world, change the linearVelocity to any object.

Image title

Decoupling Patterns

Component

I think every game developer knows about the Component-Based Architecture. Unity3d programmers should definitely know. This system reduces the coupling of components and allows you to add components to the entity so that the entity does not even know about it. Cocos2d-x has its system. Each Node has a container for components. You must inherit your components from the Component class. Each component has a reference to the Node that it owns (owner), the update method, and the serialize method for processing messages between components and other objects.

Image title

Optimization Patterns

Data Locality

The task of this pattern is to speed up memory access by using more convenient data placement for caching by the processor. This pattern is often used to create particles. And in Cocos2d-x it is also used to create particles. In ParticleSystem, all particle data is stored in ParticleDataParticleData contains data for all particles. Every member of ParticleData is an array. For example, the particle coordinates along the X-axis are stored in the posx array.

class ParticleData
{
public:
    float* posx;
    float* posy;
//...
};

This is placing the data in memory sequentially, in the order of their processing, allowing them to be processed quickly and avoid cache misses as much as possible.

Dirty Flag

It is quite often found in Cocos2d-x. This pattern defers some slow work until the result is actually needed. It can be found in the classes Scene, Camera, Node, Label, ParticleSystem, Sprite, and many others.

 

 

 

 

Top