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.
Lessons learned
git tags
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:
git tag
To push the list of tags to the remote server, you can do:
git push --tags
Using std::vector
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 CCObject
.
So what do we do?
Make use of C++’s standard std::vector
!
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:
m_bullets.push_back(bullet);
bullet
, of course, is declared as b2Body *bullet
.
Update: push_back
will store a copy of your object and not your actual object. See also erase()
.
To count the number of items in a vector we use the size()
function as follows:
m_bullets.size()
To access an item at a given index we use at()
:
m_bulletBody = (b2Body*)m_bullets.at(index);
And finally, to delete remove objects from the vector we can use the erase()
function:
m_bullets.erase(index);
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 delete
);
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:
Part 1
- https://github.com/clawoo/CuteAPultCocos2D-x/tree/CleanUpProject
- https://github.com/clawoo/CuteAPultCocos2D-x/tree/BeforePhysics
- https://github.com/clawoo/CuteAPultCocos2D-x/tree/CatapultJoint
- https://github.com/clawoo/CuteAPultCocos2D-x/tree/MouseJoint
- https://github.com/clawoo/CuteAPultCocos2D-x/tree/BulletCreation
And this is what the project looks like so far after Part 1 was completed:
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?