Created
October 13, 2011 15:55
-
-
Save nathanclark/1284613 to your computer and use it in GitHub Desktop.
Box2D touch wheel rotation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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