Thanks to some really hard work from Gustavo Ambrozio from raywenderlich.com we now have a new tutorial to explore the intriguing world of Box2D and Cocos2D.
In the first part of his How To Make a Catapult Shooting Game with Cocos2D and Box2D tutorial, Gustavo takes us through the very first steps of setting up the Box2D world, creating the catapult using revolute joints, arming it and launching the projectile. Although this may seem like quite a lot of work, it is actually quite simple to grasp.
As always, I have ported the tutorial code to Cocos2D-x. I tried to keep in line with Gustavo’s naming convention, however, I could not bear to use member variables without marking them in some way. By the way, I went with Cocos2D-x‘s convention of naming the members with
m_ as a prefix.
I can also say I learned a couple of new tricks with git, namely creating and managing tags. Gone are the days when I created a new project for each tutorial part. With the help of tags I can now manage the chapters in a way that does not spam GitHub‘s project list.
To create a tag you can do the following:
git tag -a BulletCreation
To view the list of existing tags, just do:
To push the list of tags to the remote server, you can do:
git push --tags
Gustavo’s tutorial stored references to the bullet in an
NSMutableArray. Since bullet is a
b2Body object you cannot directly store it into an
NSArray, so we employ a trick and store only a reference to it using
[NSValue valueWithPointer:bullet]. Trouble is, you don’t have
NSValue in Cocos2D-x and
CCMutableArray can only store objects derived from
So what do we do?
Make use of C++’s standard
When you declare a
std::vector, similarly to when you declare a
CCMutableArray, you need to decide what kind of objects will be stored inside it. For example, in our case, we want to store
b2Body objects, therefore we need to declare our vector as
std::vector<b2Body *> m_bullets;
Take note that
m_bullets is not a pointer, but a statically allocated vector that stores pointers to b2Body objects.
To add a new object to the vector we do:
bullet, of course, is declared as
push_back will store a copy of your object and not your actual object. See also
To count the number of items in a vector we use the
size() function as follows:
To access an item at a given index we use
m_bulletBody = (b2Body*)m_bullets.at(index);
And finally, to
delete remove objects from the vector we can use the
Edit: after Bob’s comment below, I updated the text above to clarify that erasing an element from the vector will not deallocate it, it will merely remove the reference to that object from the vector. Freeing the memory occupied by the object you just removed from the vector is still your responsibility. So, after calling
erase() make sure you always deallocate the object if that’s the case (for example, using
Edit edit: After careful re-reading of the documentation,
push_back actually stores a COPY of the object you send as a parameter. When you call
erase that object is removed from the vector, its destructor called and the memory freed.
You can learn more about
std::vector from the C++ Reference.
Project source code
Here are the tags that we have so far, in order:
You can launch one acorn and the camera will follow it all the way to the right when it hits a wall an bounce back to the squirrels. Cute, ain’t it?