Skip to content

Instantly share code, notes, and snippets.

@nathanclark
Created October 13, 2011 15:55
Show Gist options
  • Save nathanclark/1284613 to your computer and use it in GitHub Desktop.
Save nathanclark/1284613 to your computer and use it in GitHub Desktop.
Box2D touch wheel rotation
//
// HelloWorldLayer.mm
//
// Created by Nathan Clark on 10/13/11.
// Copyright self 2011. All rights reserved.
//
// Import the interfaces
#import "HelloWorldLayer.h"
//Pixel to metres ratio. Box2D uses metres as the unit for measurement.
//This ratio defines how many pixels correspond to 1 Box2D "metre"
//Box2D is optimized for objects of 1x1 metre therefore it makes sense
//to define the ratio so that your most common object type is 1x1 metre.
#define PTM_RATIO 32
// enums that will be used as tags
enum {
kTagTileMap = 1,
kTagBatchNode = 1,
kTagAnimation1 = 1,
};
b2Body* _spinnerBody;
b2Body* _groundBody;
b2RevoluteJoint *_m_joint2;
b2Fixture *_spinnerFixture;
b2MouseJoint *_mouseJoint;
CCSprite *spinner;
// HelloWorldLayer implementation
@implementation HelloWorldLayer
-(void) registerWithTouchDispatcher
{
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0
swallowsTouches:YES];
}
+(CCScene *) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
HelloWorldLayer *layer = [HelloWorldLayer node];
// add layer as a child to scene
[scene addChild: layer];
// return the scene
return scene;
}
// on "init" you need to initialize your instance
-(id) init
{
// always call "super" init
// Apple recommends to re-assign "self" with the "super" return value
if( (self=[super init])) {
// enable touches
self.isTouchEnabled = YES;
// enable accelerometer
self.isAccelerometerEnabled = YES;
CGSize screenSize = [CCDirector sharedDirector].winSize;
CCLOG(@"Screen width %0.2f screen height %0.2f",screenSize.width,screenSize.height);
// Define the gravity vector.
b2Vec2 gravity;
gravity.Set(0.0f, -10.0f);
// Do we want to let bodies sleep?
// This will speed up the physics simulation
bool doSleep = true;
// Construct a world object, which will hold and simulate the rigid bodies.
world = new b2World(gravity, doSleep);
world->SetContinuousPhysics(true);
// Debug Draw functions
m_debugDraw = new GLESDebugDraw( PTM_RATIO );
world->SetDebugDraw(m_debugDraw);
uint32 flags = 0;
flags += b2DebugDraw::e_shapeBit;
m_debugDraw->SetFlags(flags);
// Define the ground body.
b2BodyDef groundBodyDef;
groundBodyDef.position.Set(0, 0); // bottom-left corner
// Call the body factory which allocates memory for the ground body
// from a pool and creates the ground box shape (also from a pool).
// The body is also added to the world.
_groundBody = world->CreateBody(&groundBodyDef);
// Define the ground box shape.
b2PolygonShape groundBox;
// bottom
groundBox.SetAsEdge(b2Vec2(0,0), b2Vec2(screenSize.width/PTM_RATIO,0));
_groundBody->CreateFixture(&groundBox,0);
// top
groundBox.SetAsEdge(b2Vec2(0,screenSize.height/PTM_RATIO), b2Vec2(screenSize.width/PTM_RATIO,screenSize.height/PTM_RATIO));
_groundBody->CreateFixture(&groundBox,0);
// left
groundBox.SetAsEdge(b2Vec2(0,screenSize.height/PTM_RATIO), b2Vec2(0,0));
_groundBody->CreateFixture(&groundBox,0);
// right
groundBox.SetAsEdge(b2Vec2(screenSize.width/PTM_RATIO,screenSize.height/PTM_RATIO), b2Vec2(screenSize.width/PTM_RATIO,0));
_groundBody->CreateFixture(&groundBox,0);
[self schedule: @selector(tick:)];
b2CircleShape spinnerCircle;
spinnerCircle.m_radius = 4.9f;
b2BodyDef bd2;
bd2.type = b2_dynamicBody;
bd2.position.Set(15, 15);
// Adds the sprite to the body
// bd2.userData = spinner;
//Slows the rotation down
bd2.linearDamping = 1;
bd2.angularDamping = 1;
// Now the body will you these damping settings
b2FixtureDef circleFixtureDef;
circleFixtureDef.shape = &spinnerCircle;
circleFixtureDef.density = 100.0f;
circleFixtureDef.friction = 100.0f;
circleFixtureDef.filter.groupIndex =-8;
circleFixtureDef.filter.maskBits =0x0004;
_spinnerBody = world->CreateBody(&bd2);
_spinnerFixture = _spinnerBody->CreateFixture(&circleFixtureDef);
b2RevoluteJointDef jd2;
jd2.Initialize(_groundBody, _spinnerBody, bd2.position);
_m_joint2 = (b2RevoluteJoint*)world->CreateJoint(&jd2);
}
return self;
}
-(void) draw
{
// Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
// Needed states: GL_VERTEX_ARRAY,
// Unneeded states: GL_TEXTURE_2D, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
world->DrawDebugData();
// restore default GL states
glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
}
-(void) addNewSpriteWithCoords:(CGPoint)p
{
CCLOG(@"Add sprite %0.2f x %02.f",p.x,p.y);
CCSpriteBatchNode *batch = (CCSpriteBatchNode*) [self getChildByTag:kTagBatchNode];
//We have a 64x64 sprite sheet with 4 different 32x32 images. The following code is
//just randomly picking one of the images
int idx = (CCRANDOM_0_1() > .5 ? 0:1);
int idy = (CCRANDOM_0_1() > .5 ? 0:1);
CCSprite *sprite = [CCSprite spriteWithBatchNode:batch rect:CGRectMake(32 * idx,32 * idy,32,32)];
[batch addChild:sprite];
sprite.position = ccp( p.x, p.y);
// Define the dynamic body.
//Set up a 1m squared box in the physics world
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(p.x/PTM_RATIO, p.y/PTM_RATIO);
bodyDef.userData = sprite;
b2Body *body = world->CreateBody(&bodyDef);
// Define another box shape for our dynamic body.
b2PolygonShape dynamicBox;
dynamicBox.SetAsBox(.5f, .5f);//These are mid points for our 1m box
// Define the dynamic body fixture.
b2FixtureDef fixtureDef;
fixtureDef.shape = &dynamicBox;
fixtureDef.density = 1.0f;
fixtureDef.friction = 0.3f;
body->CreateFixture(&fixtureDef);
}
-(void) tick: (ccTime) dt
{
//It is recommended that a fixed time step is used with Box2D for stability
//of the simulation, however, we are using a variable time step here.
//You need to make an informed choice, the following URL is useful
//http://gafferongames.com/game-physics/fix-your-timestep/
int32 velocityIterations = 8;
int32 positionIterations = 1;
// Instruct the world to perform a single step of simulation. It is
// generally best to keep the time step and iterations fixed.
world->Step(dt, velocityIterations, positionIterations);
//Iterate over the bodies in the physics world
for (b2Body* b = world->GetBodyList(); b; b = b->GetNext())
{
if (b->GetUserData() != NULL) {
//Synchronize the AtlasSprites position and rotation with the corresponding body
CCSprite *myActor = (CCSprite*)b->GetUserData();
myActor.position = CGPointMake( b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO);
myActor.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
}
}
}
- (BOOL) ccTouchBegan:(UITouch*)touch withEvent:(UIEvent*)event
{
if (_mouseJoint != NULL) return YES;
CGPoint location = [touch locationInView:[touch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
b2Vec2 locationWorld = b2Vec2(location.x/PTM_RATIO, location.y/PTM_RATIO);
if (_spinnerFixture->TestPoint(locationWorld)) {
b2MouseJointDef md;
md.bodyA = _groundBody;
md.bodyB = _spinnerBody;
md.target = locationWorld;
md.collideConnected = true;
md.maxForce = 1000.0f * _spinnerBody->GetMass();
_mouseJoint = (b2MouseJoint *)world->CreateJoint(&md);
_spinnerBody->SetAwake(true);
}
return YES;
}
-(void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event{
if (_mouseJoint == NULL) return;
CGPoint location = [touch locationInView:[touch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
b2Vec2 locationWorld = b2Vec2(location.x/PTM_RATIO, location.y/PTM_RATIO);
_mouseJoint->SetTarget(locationWorld);
}
-(void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event{
if (_mouseJoint) {
world->DestroyJoint(_mouseJoint);
_mouseJoint = NULL;
}
}
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
//Add a new body/atlas sprite at the touched location
for( UITouch *touch in touches ) {
CGPoint location = [touch locationInView: [touch view]];
location = [[CCDirector sharedDirector] convertToGL: location];
}
}
// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
// in case you have something to dealloc, do it in this method
delete world;
world = NULL;
delete m_debugDraw;
// don't forget to call "super dealloc"
[super dealloc];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment