Programmers Guide
Programmers Guide
3
The Cocos2d-x Team
v2014.12.16
PDF Version
eBook Version
You can download the samples for this guide on GitHub
class names, methods names and other API components are renderer using
fixed fonts. eg: Sprite
italics are used to notate concepts and keywords
Revision history
2014-10-28 - initial release
Main Components
It might seem overwhelming at first, but getting started with Cocos2d-x is
simple. Before we dive into depth we must understand some of the concepts
cocos2d-x utilizes. At the heart of Cocos2d-x are Scene, Node, Sprite, Menu
and Action objects. Look at any of your favorite games and you will see all of
these components!
Lets have a look. This looks like a very popular game you might have played:
Maybe you have a few sketches of your game? Take a look at them and see what
components you have compared the example above.
Director
Cocos2d-x uses the concept of a Director. Yes, just like in a movie! The
Director controls the flow of operations and tells the necessary recipient what
to do. Think of yourself as the Executive Producer and you tell the Director
what to do! One common Director task is to control Scene replacements and
transitions. The Director is a shared singleton object that you can call from
anywhere in your code.
Here is an example of a typical game flow. The Director takes care of transitioning through this as your game criteria decides:
You are the director of your game. You decide what happens, when and how.
Take charge!
Scene
In your game you probably want a main menu, a few levels and an ending
scene. How do you organize all of these into the separate pieces they are? You
guessed it, Scene. When you think about your favorite movie you can see that
its distinctly broken down into scenes, or separate parts of the story line. If we
apply this same thought process to games, we should come up with at least a
few scenes no matter how simple the game is.
Taking another look at the image from above:
This is a main menu and it is a single Scene. Yes, this scene is made up of
several pieces that all fit together to give us the end result. Scenes are drawn by
the Renderer. The Renderer is responsible for rendering the sprites and other
objects into the screen. To better understand this we need to talk a bit about
the Scene Graph.
Scene Graph
A scene graph is a data structure that arranges a graphical scene. A scene graph
contains Node objects in a tree (yes, it is called screne graph, but it is actually
represented by a tree) structure.
It sounds and looks complicated. Im sure you are asking why should you care
about this technical detail if Cocos2d-x does the heavy lifting for you? It really
is important to understand how Scenes are drawn by the renderer. Once you
start adding nodes, sprites and animations to your game, you want to make sure
you are getting the visual result you are looking for. What if you are not? What
if your sprites are in the background and you want them the foremost objects?
Take a step back and run through the scene graph on a piece of paper and I bet
you find your mistake easily.
Since the Scene Graph is a tree; you can walk the tree. Cocos2d-x uses the
in-order walk algorithm. An in-order walk is the left side of the tree being
walked, then the root node, then the right side of the tree. Since the right side
of the tree is rendered last, it is displayed first on the scene graph.
The scene graph is easily demonstrated, lets take a look at one of the figures
above broken down:
Another point to think about is elements with a negative z-order are on the left
side of the tree while elements with a positive z-order are on the right side of
the tree. Keep this in consideration when ordering your elements! Also, you can
add elements in any order and they are automatically sorted based upon z-order.
Building on this concept, we can think of a Scene as a collection of Node objects.
8
Lets break the scene above down to see the the scene graph uses the z-order to
layout out the Scene:
10
The Scene on the left is actually made up of multiple Node objects that are
given a different z-order to make them stack on top of each other.
In Cocos2d-x, you build the Scene Graph using the addChild() API:
// Adds a child with the z-order of -2, that means
// it goes to the "left" side of the tree (because it is negative)
scene->addChild(title_node, -2);
// When you don't specify the z-order, it will use 0
scene->addChild(label_node);
// Adds a child with the z-order of 1, that means
// it goes to the "right" side of the tree (because it is positive)
scene->addChild(sprite_node, 1);
Sprites
All games have Sprites, and you may or may not realize what they are. Sprites
are the objects that you move around the screen. You can manipulate them.
The main character in your game is probably a Sprite. I know what you might
be thinking - isnt every graphical object a Sprite? No! Why? Well a Sprite is
only a Sprite if you move it around. If you dont move it around it is just a Node.
Taking another look at the image from above, lets point out what are Sprites
and what are Nodes:
11
Sprites are key in every game. Writing a platformer, you probably have a main
character that is made by using an image of some sort. This is a Sprite.
Sprites are easy to create and they have manipulatable properties like: position,
rotation, scale, opacity, color and more.
// This is how to create an sprite
auto mySprite = Sprite::create("mysprite.png");
// this is how to change the properties of the sprite
mySprite->setPosition(Vec2(500, 0));
mySprite->setRotation(40);
mySprite->setScale(2.0); // sets scale X and Y uniformly
mySprite->setAnchorPoint(Vec2(0, 0));
Lets illustrate each property, consider the following screenshot from the example
code for this chapter:
12
13
Take a look at what happened. The Sprite position has changed from its
original position to the new position that we specified.
If we now set a new rotation using mySprite->setRotation(40);:
14
Take a look at what happened. The Sprite has been rotated to the new amount
that we specified.
If we now specify a new scale using mySprite->setScale(2.0);:
15
Again, we can see that the Sprite now has changed according to our code
changes.
Lastly, all Node objects (remember that a Sprite is a subclass of Node) have a
value for anchor point. We havent talked about this yet, so now is a good time.
You can think of anchor point as a way of specifying what part of the sprite will
be used when setting the position of it.
Using the character from our example game and setting the anchor point to 0, 0
using mySprite->setAnchorPoint(Vec2(0, 0)); would result in the lower left
corner of our sprite being used as the basis for any setPosition() call. Lets
see a few of these in action:
16
Take a look at the red dot in each picture. This red dot illustrates there the
anchor point is!
As you can see anchor point is very useful when positioning Nodes. You can
even adjust the anchor point dynamically to simulate effects in your game.
We can truly work with our sprites. What if we wanted to have these same
types of changes occur in an automated, time determined manner? Well, keep
reading. . .
Actions
Creating a Scene and adding Sprite objects on the screen is only part of what
we need to do. For a game to be a game we need to make things move around!
Action are an integral part of every game. Actions allow the transformation of
Node objects in time space. Want to move a Sprite from one Point to another
17
and use a callback when complete? No problem! You can even create a Sequence
of Action items to be performed on a Node. You can change Node properties
like position, rotation and scale. Example Actions: MoveBy, Rotate, Scale. All
games use Actions.
Taking a look at the sample code for this chapter, here are Actions in work:
18
With children, changing the rotation of the parent will also change the rotation
to all children:
21
22
Conclusion
We have gone through a lot of Cocos2d-x concepts. Take a deep breath. Dont
worry. Just dive in with your ideas and take it one step at a time. Cocos2d-x
and programming in general are not a skill that is learned overnight. These take
practice and understanding. Remember that the forums are also there to help
you with questions.
Chapter 3: Sprites
What are Sprites
A Sprite is a 2D image that can be animated or transformed by changing its
properties, including rotation, position, scale, color, etc.
23
Creating Sprites
There are different ways to create Sprites depending upon what you need to
accomplish. You can create a Sprite from an image with various graphic formats
including: PNG, JPEG, TIFF, and others. Lets go through some create methods
and talk about each one.
Creating a Sprite
A Sprite can be created by specifying an image file to use.
auto mySprite = Sprite::create("mysprite.png");
The statement above creates a Sprite using the mysprite.png image. The
result is that the created Sprite uses the whole image. Sprite has the same
dimensions of mysprite.png. If the image file is 200 x 200 the resulting Sprite
is 200 x 200.
Creating a Sprite with a Rect
In the previous example, the created Sprite has the same size as the original
image file. If you want to create a Sprite with only a certain portion of the
image file, you can do it by specifying a Rect.
Rect has 4 values: origin x, origin y, width and height.
auto mySprite = Sprite::create("mysprite.png", Rect(0,0,40,40));
24
Rect starts at the top left corner. This is the opposite of what you might be
used to when laying out screen position as it starts from the lower left corner.
Thus the resulting Sprite is only a portion of the image file. In this case the
Spritedimension is 40 x 40 starting at the top left corner.
If you dont specify a Rect, cocos2d-x will automatically using the full width
and height of the image file you specify. Take a look at example below, if we use
an image with dimension 200 x 200 the following 2 statements would have the
same result.
auto mySprite = Sprite::create("mysprite.png");
auto mySprite = Sprite::create("mysprite.png", Rect(0,0,200,200));
It doesnt look like much but lets take a closer look at what is happening:
25
As you can see the sprite sheet, at a minimum reduces unneeded space, consolidates all sprites into a single file.
Lets tie this all together!
Loading a Sprite Sheet
Load your sprite sheet into the SpriteFrameCache, probably in AppDelegate:
// load the Sprite Sheet
auto spritecache = SpriteFrameCache::getInstance();
// the .plist file can be generated with any of the tools mentioned below
spritecache->addSpriteFramesWithFile("sprites.plist");
Now that we have a sprite sheet loaded into SpriteFrameCache we can create
Sprite objects by utilizing it.
Creating a Sprite from SpriteFrameCache
This creates a Sprite by pulling it from the SpriteFrameCache.
auto mysprite = Sprite::createWithSpriteFrameName("mysprite.png");
26
Sprite Manipulation
After creating a Sprite, there are a variety of properties it has that can be
manipulated.
Given:
auto mySprite = Sprite::create("mysprite.png");
27
28
There are more ways to set position than just anchor point. Sprite objects can
also be set using specific setPosition() statement.
// position a sprite to a specific position of x = 100, y = 200.
mySprite->setPosition(Vec2(100, 200);
Rotation Changes the sprites rotation, by positive or negative degrees. A
positive value rotates the sprite clockwise while a negative value rotates the
sprite counter clockwise. The default value is 0.
// rotates sprite by +20
mySprite->setRotation(20.0f);
// rotates sprite by -20
29
mySprite->setRotation(-20.0f);
// rotates sprite by +60
mySprite->setRotation(60.0f);
// rotates sprite by -60
mySprite->setRotation(-60.0f);
Scale Changes the sprites scale, either by x, y or uniformly for both x and y.
The default value is 1.0 for both x and y.
// increases X and Y size by 2.0 uniformly
mySprite->setScale(2.0);
// increases just X scale by 2.0
mySprite->setScaleX(2.0);
// increases just Y scale by 2.0
mySprite->setScaleY(2.0);
Skew Changes the sprites skew, either by x, y or uniformly for both x and y.
The default value is 0,0 for both x and y.
// adjusts the X skew by 20.0
mySprite->setSkewX(20.0f);
// adjusts the Y skew by 20.0
mySprite->setSkewY(20.0f);
30
Opacity Changes the sprites opacity by the specified value. It expects a value
from (2-255). The default value is 255 (non-opague).
// set the opacity by passing in a value
mySprite->serOpacity(30);
31
Chapter 4: Actions
Action objects are just like they sound, make a Node perform a change to its
properties. Action objects allow the transform of Node properties in time. Any
object with a base class of Node can have Action objects performed on it. As
an example, you can move a Sprite from one position to another and do it over
a time span.
Example of MoveTo and MoveBy action:
// Move sprite to position 50,10 in 2 seconds.
auto moveTo = MoveTo::create(2, Vec2(50, 10));
mySprite1->runAction(moveTo);
// Move sprite 20 points to right in 2 seconds
auto moveBy = MoveBy::create(2, Vec2(20,0));
mySprite2->runAction(moveTo);
By and To, what is the difference?
You will notice that each Action has a By and To version. Why? They are
different in what they accomplish. A By is relative to the current state of the
Node. A To action is absolute, meaning it doesnt take into account the current
state of the Node. Lets take a look at a specific example:
auto mySprite = Sprite::create("mysprite.png");
mySprite->setPosition(Vec2(200, 256));
// MoveBy - lets move the sprite by 500 on the x axis over 2 seconds
// MoveBy is relative - since x = 200 + 200 move = x is now 400 after the move
auto moveBy = MoveBy::create(2, Vec2(500, mySprite->getPositionY()));
// MoveTo - lets move the new sprite to 300 x 256 over 2 seconds
// MoveTo is absolute - The sprite gets moved to 300 x 256 regardless of
32
33
Rotate
Rotates a Node clockwise over 2 seconds.
auto mySprite = Sprite::create("mysprite.png");
// Rotates a Node to the specific angle over 2 seconds
auto rotateTo = RotateTo::create(2.0f, 40.0f);
mySprite->runAction(rotateTo);
// Rotates a Node clockwise by 40 degree over 2 seconds
auto rotateBy = RotateBy::create(2.0f, 40.0f);
mySprite->runAction(rotateBy);
Scale
Scales a Node by 10 over 2 seconds.
auto mySprite = Sprite::create("mysprite.png");
// Scale uniformly by 3x over 2 seconds
auto scaleBy = ScaleBy::create(2.0f, 3.0f);
mySprite->runAction(scaleBy);
// Scale X by 5 and Y by 3x over 2 seconds
auto scaleBy = ScaleBy::create(2.0f, 3.0f, 3.0f);
mySprite->runAction(scaleBy);
// Scale to uniformly to 3x over 2 seconds
auto scaleTo = ScaleTo::create(2.0f, 3.0f);
mySprite->runAction(scaleTo);
// Scale X to 5 and Y to 3x over 2 seconds
auto scaleTo = ScaleTo::create(2.0f, 3.0f, 3.0f);
mySprite->runAction(scaleTo);
34
Fade In/Out
Fades In a Node.
It modifies the opacity from 0 to 255. The reverse of this action is FadeOut
auto mySprite = Sprite::create("mysprite.png");
// fades in the sprite in 1 seconds
auto fadeIn = FadeIn::create(1.0f);
mySprite->runAction(fadeIn);
// fades out the sprite in 2 seconds
auto fadeOut = FadeOut::create(2.0f);
mySprite->runAction(fadeOut);
Tint
Tints a Node that implements the NodeRGB protocol from current tint to a
custom one.
auto mySprite = Sprite::create("mysprite.png");
// Tints a node to the specified RGB values
35
Animate
With Animate it is possible to do simple flipbook animation with your Sprite
objects. This is simply replacing the display frame at set intervals for the
duration of the animation. Lets consider this example:
auto mySprite = Sprite::create("mysprite.png");
// now lets animate the sprite we moved
Vector<SpriteFrame*> animFrames;
animFrames.reserve(12);
animFrames.pushBack(SpriteFrame::create("Blue_Front1.png", Rect(0,0,65,81)));
animFrames.pushBack(SpriteFrame::create("Blue_Front2.png", Rect(0,0,65,81)));
animFrames.pushBack(SpriteFrame::create("Blue_Front3.png", Rect(0,0,65,81)));
animFrames.pushBack(SpriteFrame::create("Blue_Left1.png", Rect(0,0,65,81)));
animFrames.pushBack(SpriteFrame::create("Blue_Left2.png", Rect(0,0,65,81)));
animFrames.pushBack(SpriteFrame::create("Blue_Left3.png", Rect(0,0,65,81)));
animFrames.pushBack(SpriteFrame::create("Blue_Back1.png", Rect(0,0,65,81)));
animFrames.pushBack(SpriteFrame::create("Blue_Back2.png", Rect(0,0,65,81)));
animFrames.pushBack(SpriteFrame::create("Blue_Back3.png", Rect(0,0,65,81)));
animFrames.pushBack(SpriteFrame::create("Blue_Right1.png", Rect(0,0,65,81)));
animFrames.pushBack(SpriteFrame::create("Blue_Right2.png", Rect(0,0,65,81)));
animFrames.pushBack(SpriteFrame::create("Blue_Right3.png", Rect(0,0,65,81)));
// create the animation out of the frames
Animation* animation = Animation::createWithSpriteFrames(animFrames, 0.1f);
Animate* animate = Animate::create(animation);
36
37
Cocos2d-x supports most of the easing function in the above graph. They are
also simple to implement. Lets look at a specific use case. Lets drop a Sprite
object from the top of the screen and make it bounce.
// create a sprite
auto mySprite = Sprite::create("mysprite.png");
An example sequence
auto mySprite = Sprite::create("mysprite.png");
// create a few actions.
auto jump = JumpBy::create(0.5, Vec2(0, 0), 100, 1);
auto rotate = RotateTo::create(2.0f, 10);
// create a few callbacks
auto callbackJump = CallFunc::create([](){
log("Jumped!");
});
auto callbackRotate = CallFunc::create([](){
log("Rotated!");
});
39
to help achieve specific effects that you cannot otherwise. Combining Spawn and
Sequence is a very powerful feature
Example, given:
// create 2 actions and run a Spawn on a Sprite
auto mySprite = Sprite::create("mysprite.png");
auto moveBy = MoveBy::create(10, Vec2(400,100));
auto fadeTo = FadeTo::create(2.0f, 120.0f);
Using a Spawn:
// running the above Actions with Spawn.
auto mySpawn = Spawn::createWithTwoActions(moveBy, fadeTo);
mySprite->runAction(mySpawn);
and consecutive runAction() statements:
// running the above Actions with consecutive runAction() statements.
mySprite->runAction(moveBy);
mySprite->runAction(fadeTo);
Both would produce the same result. However, one can use Spawn in a Sequence.
This flowchart shows the how this might look:
41
// create a Sprite
auto mySprite = Sprite::create("mysprite.png");
// create a few Actions
auto moveBy = MoveBy::create(10, Vec2(400,100));
auto fadeTo = FadeTo::create(2.0f, 120.0f);
auto scaleBy = ScaleBy::create(2.0f, 3.0f);
// create a Spawn to use
auto mySpawn = Spawn::createWithTwoActions(scaleBy, fadeTo);
// tie everything together in a sequence
auto seq = Sequence::create(moveBy, mySpawn, moveBy, nullptr);
// run it
mySprite->runAction(seq);
Run the example Programmer Guide Sample code to see this in action!
Reverse
Reverse is exactly like it sounds. If you run a series of actions, you can call
reverse() to run it in the opposite order. Backwards. However it is not just
simply running in reverse. It is actually manipulating the properties of the
original Sequence or Spawn in reverse too.
Using the Spawn example above reversing is simple. cpp // reverse a
sequence, spawn or action mySprite->runAction(mySpawn->reverse());
Most Action and Sequence objects are reversible!
Its easy to use, but lets make sure we see what is happening. Given:
// create a Sprite
auto mySprite = Sprite::create("mysprite.png");
mySprite->setPosition(50, 56);
// create a few Actions
auto moveBy = MoveBy::create(2.0f, Vec2(500,0));
auto scaleBy = ScaleBy::create(2.0f, 2.0f);
auto delay = DelayTime::create(2.0f);
// create a sequence
auto delaySequence = Sequence::create(delay, delay->clone(), delay->clone(),
delay->clone(), nullptr);
42
43
Creating a Scene
It is very easy to create a Scene
auto myScene = Scene::create();
A Simple Scene
Letss build a simple Scene. Remember that cocos2d-x uses a right handed
coordinate system. This means that our 0,0 coordinate is at the bottom left
corner of the screen/display. When you start positioning your game elements
this is where you should start your calculations from. Lets create a simple
Scene and add a few elements to it:
auto dirs = Director::getInstance();
Size visibleSize = dirs->getVisibleSize();
auto scene1 = Scene::create();
auto label1 = Label::createWithTTF("My Game", "Marker Felt.ttf", 36);
label1->setPosition(Vec2(visibleSize.width / 2, visibleSize.height / 2));
scene->addChild(label1);
auto sprite1 = Sprite::create("mysprite.png");
sprite1->setPosition(Vec2(100, 100));
scene->addChild(sprite1);
When we run this code we shall see a simple Scene that contains a Label and a
Sprite. It doesnt do much but its a start.
// Transition Fade
Director::getInstance()->replaceScene(TransitionFade::create(0.5, myScene, Color3B(0,255,255
// FlipX
Director::getInstance()->replaceScene(TransitionFlipX::create(2, myScene));
// Transition Slide In
Director::getInstance()->replaceScene(TransitionSlideInT::create(1, myScene) );
45
Chapter 6: UI
Overview
Cocos2d-x provides a easy to use UI api that takes care of your GUI needs. Some
of these include Label, Menu, MenuItems, Buttons and Views.
Label
Cocos2d-x provides a Label object that can create TTF, BMFont and SystemFont
labels.
Label BMFont BMFont is a label type that uses a bitmap font. Bitmap fonts
consist of a matrix of dots or pixels representing the image of each glyph in
each face and size. It is very fast and easy to use, but not scalable, requiring a
separate font for each size.
As the Label class is subclass of SpriteBatchNode each character is a Sprite
and can be rotated, scaled, tinted, changes in anchor point and most any other
property change derived from a Node object.
Creating a BMFont label requires two files: a .fnt file and an image representation
of each character in .png format. If you are using a tool like Glyph Designer
these files are created automatically for you. Creating a BMFont label:
auto myLabel = Label::createWithBMFont("myFont.fnt", "My Label Text");
All of the characters in the string parameter should be found in the provided
MyFont.fnt file, otherwise they wont be rendered. If you render a Label and
it is missing characters, make sure they exist in your MyFont.fnt file. An
example Label created with BMFont:
Label TTF TTF is a label type that uses a True Type Font. To create one you
need to specify a .ttf font file name, text string and a size. Unlike BMFont, TTF
can render size changes without the need for a separate font files. Creating a
TTF label:
auto myLabel = Label::createWithTTF("myFont.ttf", "My Label Text", 16);
Although it is more flexible than BMFont, TTF is slower and changing properties
like the font face and size is an expensive operation. An example Label created
with TTF
46
If you need several TTF labels that all have the same properties you can create a
TTFConfig object to manage them. A TTFConfig allows you to set the properties
that all of your TTF labels would have in common. You can create one like:
// create a TTFConfig files for labels to share
TTFConfig labelConfig;
labelConfig.fontFilePath = "myFont.ttf";
labelConfig.fontSize = 16;
labelConfig.glyphs = GlyphCollection::DYNAMIC;
labelConfig.outlineSize = 0;
labelConfig.customGlyphs = nullptr.
labelConfig.distanceFieldEnabled = false;
// create a TTF Label from the TTFConfig file.
auto myLabel = Label::createWithTTF(labelConfig, "My Label Text");
A TTFConfig can also be used for displaying Chinese, Japanese and Korean
characters.
Label SystemFont SystemFont is a label type that uses the default system
font and font size. This is a font that is meant not to have its properties changed.
You should think of it as system font, system rules. Creating a SystemFont
label:
auto myLabel = Label::createWithSystemFont("My Label Text", "Arial", 16);
47
48
Layout
The Layout class is the root class of all containers. It inherits from Widget. The
Layout class exists mainly for arranging children widgets and clipping.
The LayoutManager, LayoutParameter and Margin classes are used for layout
elements. HBox, VBox and RelativeBox are handy classes for layout children
widgets horizontally, vertically and relatively.
The ScrolView, ListView and PageView are specific containers for certain usage
scenario. We will talk it in another section.
Widgets
Widgets are GUI objets that help make creating a user interface easier. Lets
talk about the common widgets that you might use:
Buttons A button intercepts a touch event and calls a predefined callback
when tapped. It is inherited from ui::Widget. This class provide methods for
setting the title, image and other properties of button. A Button has a normal
and selected state. The appearance of the Button can change based upon this
state. Creating a Button is simple:
auto button = Button::create("animationbuttonnormal.png",
"animationbuttonpressed.png");
button->setTitleText("Text Button");
button->setPosition(Vec2(0,0));
button->addTouchEventListener(CC_CALLBACK_2(UIButtonTest::touchEvent, this));
this->addChild(button);
CheckBox A CheckBox permits the user to make a binary choice. A Checkbox
can have a state of normal, selected and disabled. Creating a CheckBox is simple:
auto checkBox = CheckBox::create("check_box_normal.png",
"check_box_normal_press.png",
"check_box_active.png",
"check_box_normal_disable.png",
"check_box_active_disable.png");
checkBox->setPosition(Vec2(0,0));
checkBox->addEventListener(CC_CALLBACK_2(UICheckBoxTest::selectedEvent, this));
this->addChild(checkBox);
50
TextBMFont
A TextBMFont widget is used for displaying BMFont text. It supports touch event,
focus, percent positioning and percent content size. Creating a TextBMFont is
list like the Text widget:
auto textBMFont = TextBMFont::create("BMFont", "bitmapFontTest2.fnt");
textBMFont->setPosition(Vec2(0,0));
this->addChild(textBMFont);
TextAtlas A TextAtlas widget is used for displaying text as an atlas font. It
supports touch event, focus, percent positioning and percent content size.
auto textAtlas = TextAtlas::create("1234567890", "labelatlas.png", 17, 22, "0");
textAtlas->setPosition(Vec2(0,0));
this->addChild(textAtlas);
RichText A RichText widget is used for displaying text, image and custom
nodes. It supports touch event, focus, percent positioning and percent content
size. When receiving a touch event the whole RichText widget receives the
event. To create a RichText widget:
auto richText = RichText::create();
richText->ignoreContentAdaptWithSize(false);
richText->setContentSize(Size(100, 100));
auto re1 = RichElementText::create(1, Color3B::WHITE, 255, str1, "Marker Felt", 10);
richText->pushBackElement(re1);
richText->setPosition(Vec2(0,0));
richText->setLocalZOrder(10);
this->addChild(_richText);
TextField A TextField Widget is used for inputting text. It supports touch
event, focus, percent positioning and percent content size. To create a TextField
widget:
auto textField = TextField::create("input words here","Arial",30);
textField->setPosition(Vec2(0,0));
textField->addEventListener(CC_CALLBACK_2(UITextFieldTest::textFieldEvent, this));
this->addChild(textField);
52
***Ricardo, I removed ScrollView and ListView for now as the coe was very long
and seems very complicated. If we need to include it I should try and create a
smaller, more concise code example. I alro removed HBox and VBox layout as
they were only described for container purposes, as Owen put it.
53
Particle
Parallax
A Parallax Node is a special Node type that simulates a parallax scroller. You
can think of many games that function this way, Super Mario Bros being a
classic example. Parallax Nodes can be moved around by a Sequence and also
manually by mouse, touch, accelerameter or keyboard events.
54
Parallax nodes are a bit more complex than regular nodes. Why? Because they
require the use of multiple nodes to function.
An example of adding multiple Nodes to a Parallax node.
// create a void node, a parent node
auto voidNode = ParallaxNode::create();
// NOW add the 3 nodes to the 'void' node
// background image is moved at a ratio of 0.4x, 0.5y
voidNode->addChild(background, -1, Vec2(0.4f,0.5f), Vec2::ZERO);
// tiles are moved at a ratio of 2.2x, 1.0y
voidNode->addChild(tilemap, 1, Vec2(2.2f,1.0f), Vec2(0,-200) );
// top image is moved at a ratio of 3.0x, 2.5y
voidNode->addChild(cocosImage, 2, Vec2(3.0f,2.5f), Vec2(200,800) );
OK, looks and feels familiar, right? Notice a few items! Each Node is given
a unique z-order so that they stack on top of each other. Also notice the
additional parameters to the addChild() call.
FixedPriority vs SceneGraphPriority
The EventDispatcher uses priorities to decide which listeners get delivered an
event first.
FixedPriority is an integer value. Event listeners with lower Priority values
get to process events before event listeners with higher Priority values.
SceneGraphPriority is a pointer to a Node. Event listeners whose Nodes have
higher z-order values (that is, are drawn on top) receive events before event
listeners whose Nodes have lower Z order values (that is, are drawn below). This
ensures that touch events, for example, get delivered front-to-back, as you would
expect.
Remember Chapter 2? Where we talked about the scene graph and we talked
about this diagram?
Well, when use SceneGraphPriority you are actually walking this above tree
backwards. . . I, H, G, F, E, D, C, B, A. If an event is triggered, H would take a
look and either swallow it (more on this below) or let is pass through to I. Same
thing, I will either consume it or let is pass thought to G.. and so on until the
event either swallowed or it does not get answered.
56
Touch Events
Touch events are the most important event in mobile gaming. They are easy
to create and provide versatile functionality. Lets make sure we know what a
touch event is. When you touch the screen of your mobile device, it accepts the
touch, looks at where you touched and decides what you touched. Your touch is
then answered. It is possible that what you touched might not be the responding
object but perhaps something underneath it. Touch events are usually assigned
a priority and the event with the highest priority is the one that answers. Here
is how you create a basic touch event listener:
// Create a "one by one" touch event listener
// (processes one touch at a time)
auto listener1 = EventListenerTouchOneByOne::create();
// trigger when you push down
listener1->onTouchBegan = [](Touch* touch, Event* event){
// your code
return true; // if you are consuming it
};
// trigger when moving touch
listener1->onTouchMoved = [](Touch* touch, Event* event){
// your code
};
// trigger when you let up
listener1->onTouchEnded = [=](Touch* touch, Event* event){
// your code
};
// Add listener
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, this);
As you can see there are 3 distinct events that you can act upon when using a
touch event listener. They each have a distinct time in which they are called.
onTouchBegan is triggered when you press down.
onTouchMoved is triggered if you move the object around while still pressing
down.
onTouchEnded is triggered when you let up on the touch.
57
Swallowing Events
When you have a listener and you want an object to accept the event it was
given you must swallow it. In other words you comsume it so that it doesnt get
passed to other objects in highest to lowest priority. This is easy to do.
// When "swallow touches" is true, then returning 'true' from the
// onTouchBegan method will "swallow" the touch event, preventing
// other listeners from using it.
listener1->setSwallowTouches(true);
// you should also return true in onTouchBegan()
listener1->onTouchBegan = [](Touch* touch, Event* event){
// your code
return true;
};
58
EventMouse* e = (EventMouse*)event;
string str = "Mouse Up detected, Key: ";
str += tostr(e->getMouseButton());
// ...
}
void MouseTest::onMouseMove(Event *event)
{
EventMouse* e = (EventMouse*)event;
string str = "MousePosition X:";
str = str + tostr(e->getCursorX()) + " Y:" + tostr(e->getCursorY());
// ...
}
void MouseTest::onMouseScroll(Event *event)
{
EventMouse* e = (EventMouse*)event;
string str = "Mouse Scroll detected, X: ";
str = str + tostr(e->getScrollX()) + " Y: " + tostr(e->getScrollY());
// ...
}
Chapter 9: 3D
You probably started with Cocos2d-x and know it as a 2D game engine. Starting
with version 3, 3D features are being added and refined. 3D gaming is a huge
market and Cocos2d-x is adding all the features you need for 3D development.
3D development might be new to you and use some terminology that you are
unfamiliar with. There are also additional softare tools that you need to become
familiar with. Lets jump right in and get our feet wet.
Jumping into 3D
Sprite3D
Just like 2D games, 3D games indeed have Sprite objects. Of course, right!
Sprite objects are a core foundation of any game. 3D Sprites have a z axis
instead of just and x and y axis. Sprite3D works in many ways just like a normal
Sprite. It is easy to load and display a Sprite3D object:
auto sprite = Sprite3D::create("boss.c3b");
sprite->setScale(5.f);
sprite->setPosition(Vec2(200,200));
scene->addChild(sprite);
This creates a Sprite3D object based upon the provided file. Example:
61
Terminology
This isnt a language class but when using 3D there are some commonly used
terms that you should be familiar with.
Mesh - vertexes that construct a shape and texture with which you are
rendering.
Model - an object that can be rendered. It is a collection of meshes. In
our engine, Sprite3D.
Camera - Since a 3D world is not flat, you need set a camera to look at it.
You get different scenes with different camera parameters.
Light - Lightening is applied to make scenes look realistic. To make a
object look real, the color should change according to the light. Face the
light it is bright and the opposite is dark. Lightening an object means
computing the objects color according to the light.
Billboard - an status where an object is always facing the camera.
Ray - a line with a start, but no end point.
62
Swap 3D Model
When doing 3D development you might want to make dynamic changes to
your model. Perhaps due to power-ups, costume changes or visual queues
to notify the user about status changes of your model. If your 3D model is
comprised from meshes you can access the mesh data using getMeshByIndex()
and getMeshByName(). Using these functions it is possible to achieve effects like
swapping a weapon or clothing for a character. Lets take a look at an example
of a girl wearing a coat:
63
We can change the coat that the girl is wearing by changing the visibility of the
mesh objects we are using. The following example demonstrates how to do this:
auto sprite = Sprite3D::create("ReskinGirl.c3b");
// display the first coat
auto girlTop0 = sprite->getMeshByName("Girl_UpperBody01");
if(girlTop0)
{
girlTop0->setVisible(true);
}
auto girlTop1 = sprite->getMeshByName("Girl_UpperBody02");
if(girlTop1)
{
girlTop1->setVisible(false);
}
// swap to the second coat
auto girlTop0 = sprite->getMeshByName("Girl_UpperBody01");
if(girlTop0)
{
girlTop0->setVisible(false);
}
64
Animation
Sprite3D objects are essential to our game! We have learned how manipulate
them. However we might want a more rich experience. Enter animation! To
run a 3d animations, you can use theAnimation3D and Animate3D objects.
Animation3D can be created with .c3b or .c3t files as it is not possible to
animate .obj files. You then create an Animate3D action using the Animation3D
object. Example:
auto animation = Animation3D::create("orc.c3b");
if (animation)
{
auto animate = Animate3D::create(animation);
sprite->runAction(RepeatForever::create(animate));
}
Run the example Programmer Guide Sample code to see this in action!
65
Multiple animations
What do you do when you want to run multiple animations at the same time?
Using the animation start time and animation length parameters you can
create multiple animations. The unit for both parameters is seconds. Example:
auto animation = Animation3D::create(fileName);
if (animation)
{
auto runAnimate = Animate3D::create(animation, 0, 2);
runAnimate->setSpeed(10);
sprite->runAction(runAnimate);
auto attackAnimate = Animate3D::create(animation, 3, 5);
attackAnimate->setSpeed(10);
sprite->runAction(attackAnimate);
}
In the above example there are two animations that get run. The first starts
immediately and lasts for 2 seconds. The second starts after 3 seconds and lasts
for 5 seconds. The speed of the animation is a positive integer for forward while
a negative speed would be reverse. In this case the speed is set to 10. This
means that this animation can be considered to be 10 seconds in length.
Animation Blending
When using multiple animations, blending is automatically applied between each
animation. The purpose of blending is to create a smooth transition between
effects. Given two animations, A and B, the last few frames of animation A and
the first few frames of animation B overlap to make the change in animation
look natural.
The default transition time is 0.1 seconds. You can set the transition time by
using Animate3D::setTransitionTime.
Cocos2d-x only supports linear interpolation between keyframes. This fills in
gaps in the curve to ensure a smooth path. If you use other interpolation methods
in the model production, our built in tool,fbx-conv will generate additional
keyframes to compensate. This compensation is completed in accordance with
the target frame.
Camera
Camera objects are an important aspect of 3D development. Since a 3D world is
not flat you need to use a Camera to look at it and navigate around it. Just like
66
when you are watching a movie and the scene pans to the left or right. This same
concept is applied when using a Camera object. In 2D development a Camera
is not used. You would instead move the layer in your desired direction. The
Camera object inherits from Node and therefore can support most Action objects.
There are two types of Camera objects: perspective camera and orthographic
camera.
The perspective camera is used to see objects having a near to far effect. A
perspective camera view might look like this:
As you can see with a perspective camera objects in the near are larger and
objects in the far are smaller.
The orthogonal camera is used to see objects as large distance. An orthogonal
camera view might look like this:
As you can see with an orthongonal camera objects are the same size regardless
of how far away from the Camera object they are. Mini Maps in games are
67
void unproject (const Size & viewport, Vec3 * src, Vec3 * dst) const;
Here viewport is viewport size, use src as screen coordinates, the z axis of the
src indicates clipping plane distance information, -1 means the near clipping
plane, 1 means far clipping plane. The dst parameter will return world space
coordinates.
Light
Light is really important for building mood and ambiance for a game. There
are currently 4 lighting techniques supported. You would use different lighting
techniques depending upon your needs. Each lighting effect achieves a different
result.
Ambient Light
An AmbientLight object will apply for everything in the scene. Example:
auto light = AmbientLight::create (Color3B::RED);
addChild (light);
This produces:
69
Directional Light
A DirectionalLight object is often used to simulate a light source such as
sunlight. When using DirectionalLight keep in mind that is has the same
density no matter where you are in relationship to it. Example:
auto light = DirectionLight::create(Vec3(-1.0f, -1.0f, 0.0f), Color3B::RED);
addChild (light);
This produces:
Point Light
A PointLight object is often used to simulate the effect of light bulbs, lamps
or torches. The direction of a PointLight is from the lighted position to the
PointLight. Keep in mind that the density is different depending upon the
distance from the PointLight. What does this mean? If you are close to the
start of the PointLight it will be really strong. If you are towards the end of
the PointLight it will be dim. PointLight also becomes weaker the larger the
distance it is projected. Example:
auto light = PointLight::create(Vec3(0.0f, 0.0f, 0.0f), Color3B::RED, 10000.0f);
addChild (light);
70
This produces:
Spot Light
A SpotLight object is often used to simulate a flashlight. This means that it is
emitted in just one direction in the shape of a cone. Example:
auto spotLight = SpotLight::create(Vec3(-1.0f, -1.0f, 0.0f), Vec3(0.0f, 0.0f, 0.0f),
Color3B::RED, 0.0, 0.5, 10000.0f) ;
addChild (spotLight);
This produces:
71
Light Masking
What do you use for lights in your kitchen or living room? Probably a few
lamps? Do you ever notice that perhaps you only use a lamp to light up a certain
portion of the room? You are essentially applying a lighting mask!
A lighting mask is used on a Node to only apply a particular lighting source to it.
For example if you had three lights in a Scene a Node can only be lighted by
one of the lights instead of all three. You can use setLightFlag(LightFlag)
to control which Node objects are effected by the light. It is important to note
that all lighting sources are rendered in a single pass. Due to mobile platform
performance issues the use of multiple light sources is not recommended. The
default maximum is 1. If you want to open multiple light sources you must
define the following keys in info.plist:
<key> cocos2d.x.3d.max_dir_light_in_shader </key>
<integer> 1 </integer>
<key> cocos2d.x.3d.max_point_light_in_shader </key>
<integer> 1 </integer>
<key> cocos2d.x.3d.max_spot_light_in_shader </key>
<integer> 1 </integer>
72
3D Software Packages
3D Editors
3D editors are collections of tools that you use to build your 3D graphics. There
are both commercial and free tools available. These are the most popular editors:
Blender (Free)
3DS Max
Cinema4D
Maya
Most 3D editors usually save files in a common collection of formats for easy use
within other editors as well as a standard way for game engines to import you
files for use.
Cocos2d-x Provided Tools
Cocos2d-x provides tools to help with converting your 3D models to formats
that Cocos2d-x use to provide access to all aspects of your 3D files.
fbx-conv command-line tool fbx-conv allows the conversion of an FBX
file into thecocos2d-x proprietary formats. FBX is the most popular 3D file
format and is being supported by all the major editors. fbx-conv exports to
.c3b by default. It is simple to use with just a few parameters:
fbx-conv [-a|-b|-t] FBXFile
The possible switches are:
Example:
fbx-conv -a boss.FBX
There are a few things to note about fbx-conv: * The model needs to have a
material that contain at least one texture * it only supports skeletal animation. *
it only supports one skeleton object no multiple skeleton support yet. * You can
create a 3d scene by exporting multiple static model * The maximum amount of
vertices or indices a mesh is 32767
73
3D File Formats
Cocos2d-x currently supports two 3d file formats:
Wavefront Object files: .obj files
Cocos2d-x 3d ad-hoc format:c3t, c3b files.
The Wavefront file format is supported because it has been widely adopted by
3D editors and it is extremely easy to parse. It is, however, limited and doesnt
support advanced features like animations.
On the other hand, c3t and c3b are Cocos2d-x proprietary file formats that
were created to allow animations, materials and other advanced 3d features. The
suffix t means text, while the suffix b means binary. Developers must use c3b
for production because it is more efficient. In case you want to debug the file
and track its changes in git or any other VCS you should c3t instead.
Advanced Topics
BillBoard
BillBoard is a very common rendering technique. Under normal circumstances
with a textured plane model (eg: a quadrilateral) to replace the three-dimensional
model and let the plane always facing the observation cameras, so that the
benefits of retaining the three-dimensional model on the basis of three-dimensional
rendering greatly improves efficiency. Common in trees, particle effects rendering.
74
BillBoard use
BillBoard is derived from Sprite, so it supports most of the features as a
Sprite object. We can create for the cameras origin BillBoard through the
following ways:
76