How to Implement Grabbing a Sprite with Cocos2d and Box2d
With Box2d, it’s not difficult to implement an app in which we can grab a sprite with touches. The core function we should use is called mouse joint. In this article, I want to show the basic ideas and steps of implementation. Note: this example is based on one of my previous articles – Cocos2d Example – Box2d. The only difference is I moved the codes regarding to the sprite ball from MyScene to BallLayer.
Step 1: Enable the touch. Add the following line of code into the init function of BallLayer.
isTouchEnabled = YES;
Step 2: Response the touch begin event by implementing ccTouchesBegan method. In this method, we first need to use the touch position (Note: a coordinate and unit conversion is required) to construct a very small area (the touch position is within this small area). Then we find all the shapes that intersect with this small area using AABB queries (b2World::Query). If such shapes exist, we should get their associated bodies and test whether the body is not static and the touch position is inside the body. The body which is not static and contain the touch position will be selected to create a mouse joint. The codes are as follows:
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { UITouch* myTouch = [touches anyObject]; CGPoint location = [myTouch locationInView: [myTouch view]]; location = [[Director sharedDirector]convertCoordinate:location]; m_mouseWorld.Set(location.x/PTM_RATIO, location.y/PTM_RATIO); if (m_mouseJoint != NULL) { return; } b2AABB aabb; b2Vec2 d; d.Set(0.001f, 0.001f); aabb.lowerBound = m_mouseWorld - d; aabb.upperBound = m_mouseWorld + d; const int32 k_maxCount = 10; b2Shape* shapes[k_maxCount]; int32 count = world->Query(aabb, shapes, k_maxCount); b2Body* nbody = NULL; for (int32 i = 0; i < count; ++i) { b2Body* shapeBody = shapes[i]->GetBody(); if (shapeBody->IsStatic() == false && shapeBody->GetMass() > 0.0f) { bool inside = shapes[i]->TestPoint(shapeBody->GetXForm(), m_mouseWorld); if (inside) { nbody = shapes[i]->GetBody(); break; } } } if (nbody) { b2MouseJointDef md; md.body1 = world->GetGroundBody(); md.body2 = nbody; md.target = m_mouseWorld; #ifdef TARGET_FLOAT32_IS_FIXED md.maxForce = (nbody->GetMass() < 16.0)? (1000.0f * nbody->GetMass()) : float32(16000.0); #else md.maxForce = 1000.0f * nbody->GetMass(); #endif m_mouseJoint = (b2MouseJoint*)world->CreateJoint(&md); nbody->WakeUp(); } }
Step 3: Response the touch cancelled event by implementing ccTouchesCancelled method. In this method, the created mouse joint is destroyed.
- (void)ccTouchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { if (m_mouseJoint) { world->DestroyJoint(m_mouseJoint); m_mouseJoint = NULL; } }
Step 4: Response the touch move event by implementing ccTouchesMoved method. Get the new touch position, then update the position of the joint bodies (b2MouseJoint::SetTarget).
- (void)ccTouchesMoved:(NSSet*)touches withEvent:(UIEvent*)event{ UITouch* myTouch = [touches anyObject]; CGPoint location = [myTouch locationInView: [myTouch view]]; location = [[Director sharedDirector]convertCoordinate:location]; m_mouseWorld.Set(location.x/PTM_RATIO, location.y/PTM_RATIO); if (m_mouseJoint) { m_mouseJoint->SetTarget(m_mouseWorld); } }
All done!
—————————————
Download: You can download the source codes from here.

AWESOME!
I just finished a demo game all using chipmunk, but the features you are getting so easily out of box2d put chipmunk to shame…
I wonder what kind of project you will use all this knowledge on?
@christopher truman
It’s also not that complex if using Chipmunk, but I often met some annoying problems with it. Box2d is more reliable and has more comprehensive resources (e.g., documentation) I think.
Do we have to use cocos2d and box2d together ?
I am trying to find a tutorial or some source code where we only have box2d without cocos2d….Can you please provide a project with just that ?
Thanks.
@Sandbird
hi, you don’t have to. cocos2d just provides you a pretty good 2d
framework to save you lots of time. you don’t need to develop
from scratch. i have no idea where to find such an example that
uses box2d without cocos2d, but i think if you’re
familiar with graphics development in iPhone, it won’t be difficult
to integrate box2d into your project because the core of using
box2d is just defining an updating scheduler to update the world,
but you don’t need to know how box2d updates the world. The rest
things you need to know are reading the documentation to find
the details of setting parameters and define the bodies, shapes, etc.
I am running this and i get just a black screen.
No errors in my console and the programs seems to run because i can press the Home button and go back to the menu. Its not crashing or anything.
I’ve imported the cocos2d and the box2d libraries…Everything seems fine oO
Oh, i am using 2.2.1 sim
hi again, thanks for your answer. I was asking to just have box2d cause i dont wanna learn a new engine to work on another engine and then we have opengl also and core animation and quartz and its all a big programmatic “soup”.
I am still in the learning process i know but i dont want to have to learn 10 things to do 1.
Besides….can we make a box2d object or a cocos2d obj and then use Opengl to manipulate them ? For example make a box with box2d and use quartz to map a texture on it ?
Thanks again.
of course you can:) after you update the world in your updating scheduler, you
just need to simply use quartz to update the texture’s position. that’s it.
to be honest, using box2d is not that difficult.
Your example is the only thing i found on the net that its a bit standalone…(no demos and tables stuff)
But when i am running your project i get a weird error
Argument list too long: recursive header expansion failed at /Developer/Documentation/DocSets/com.apple.ADC_Reference_Library.CoreReference.docset/Contents/Resources/Documents/documentation/Carbon/Reference/QuickDraw_Ref.
so i tried to make it in a new project putting together the same project again. Thats why i said its running but i see a black screen. Now i am 99.9f%
sure that i did it correctly.
Can you please give it a go yourself and tell me why its not working ? I know i am asking too much but if you want in the end cause i bet alot of people just started with this and dont know how to add Target executables in a project, you can also give mine in your examples. I have included the cocos2d and box2d (all latest) in the project as files and not their project files.
Here is the project file (zipped): http://tinyurl.com/MyBox2D
And again thanks for your responses. Its a rare thing to see in our days
stike that….its working now
I did the whole project again from the beginning and now its working….Dont know what went wrong. You can delete the last post if you want…and sorry for the spam.I’ve been trying to make this work 2 days now
Thanks for these great tutorials. I’ve just discovered your site after spending the last 2 days trying to decide between box2d and chipmunk, and had pretty much given up on box2d because of the lack of working demos and tutorials I could find for the iphone vs chipmunk ones. You’ve given me new hope : )
Is it possible to add any bounce/spring to the grabbed object, whilst you drag it, so it feels slightly elasticated?
I’d also be very interested if you’ve had any experience with non flat surfaces with box2d, I’m liking the sound of the edge shapes feature, but not 100% where to start.
Thanks for the posts, keep it up!
Can anyone tell me how to modify this example to work with cocos2d-iphone 0.8.1 which has a newer version of box2d which no longer has a “Query” method but rather a “QueryAABB” method? I’m having trouble with QueryAABB’s b2QueryCallback parameter.
I’d love to see how this changes with the new build of Box2D in Cocos2d 0.8.1 also.
hi friends..!!
i’m currently working on iphone app developing..!
but i want to start game developing using cocos2d …!!
from where can i start to boost up easily and fast…?!!!!
i’m a new bee to iphone game development.
Thank you for sharing this great tutorial, it was invaluable to help me start with Box2D.
Might you think it possible to subclass mousejoint into player/enemy type classes?
how to skin a body using cocos+box2d
here is my body and i have a image called wood.png
[B]b2BodyDef groundBodyDef2;
groundBodyDef2.position.Set(8, 9);
groundBodyDef2.angle=28;
//groundBox2.restitution=1;
b2Body* groundBody2 = world->CreateBody(&groundBodyDef2);
b2PolygonShape groundBox2;
groundBox2.SetAsBox(1.5f, .1f);//SetAsEdge(b2Vec2(3,3), b2Vec2(3,0));
groundBody2->CreateFixture(&groundBox2);
[/B]
any idea thanks
For anyone wondering how to do this in a more recent version of Box2D (QueryAABB and friends), check out this forum post: http://www.cocos2d-iphone.org/forum/topic/2298
- Johannes
For even more recent cocos2d-iphone and Box2D, see here: http://www.cocos2d-iphone.org/forum/topic/7219#post-42388
@matt
Hi matt,
Thanks for your link.
@admin my pleasure. share the knowledge!