iPhone Tutorial: Simulating a Gyroscope in Cocos2D and Box2D

I was recently working on a tutorial designing a Labyrinth type game for iPhone. This game has a maze which is seen from above. You have to guide a ball through the maze by tilting the phone avoiding obstacles. You can do this using the CoreMotion library if you can test your game on the phone and are a member of the Apple Developer Program. I wanted a simple way to emulate the effect of tilting using the iPhone simulator. The idea I came up to treat the simulator screen like it was piece of board balanced on a pin. When you click the screen it's like you're applying a force to the board and tilting it. If you were to click in the centre that wouldn't cause any tilting the further you click from the centre the more force is applied. In this example I'll show you how to use this to apply a force to an element depending on where the screen is clicked.

To do this I used the following code. First it's necessary to initialise touch in Cocos2D by putting the following in the init method:

  1. self.isTouchEnabled = YES;

Next it's necessary to override the touches moved method:

  1. - (void) ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
  2. UITouch* touch = [touches anyObject];
  3.  
  4. // Get the location of the touch
  5. CGPoint location = [touch locationInView:touch.view];
  6.  
  7. // Find the position relative to the centre of the screen
  8. // remember the screen is 480x320 with the origin at the
  9. // top left hand corner
  10. float xRel = location.x - 240;
  11. // Make it so y-up is positive negative
  12. float yRel = -location.y + 160;
  13.  
  14. // Scale xRel and yRel so they vary between 0 and 1
  15.  
  16. xRel = xRel / 240;
  17.  
  18. yRel = yRel / 160;
  19.  
  20. // Set a max force for the object
  21. float maxForce = 10 ;
  22.  
  23. // Get a reference to the Box2D object (you would need to get the relevant body for you!)
  24.  
  25. // Set linear damping if you want it to come to rest gradually
  26. b2Body * body->SetLinearDamping(0.5);
  27.  
  28. // Make sure it's awake
  29. ballBody->SetAwake(YES);
  30.  
  31. // Setup a force depending on the click position
  32. b2Vec2 force (xRel * maxForce * ballBody->GetMass(), yRel * maxForce* ballBody->GetMass());
  33.  
  34. // Apply the force to the centre of the body
  35. body->ApplyForce(force, ballBody->GetWorldCenter());
  36.  
  37. }
  38.  
  39.  
  40. }

This will cause the body to move around as if the phone were being tilted.

Update: A more complex approach:

The method presented works fine but it has a problem. The user has to move the mouse for the force to be applied. A better approach would be to apply a constant force while the mouse was pressed. To do this we need to register: touches, touch moves and touch ends. When the user touches the screen or moves the mouse we set the force in a b2Vec2 member variable. When the user releases the touch we set this force to zero. Then every step we apply the force.

  1. - (void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
  2. UITouch* touch = [touches anyObject];
  3. [self updateForce:touch];
  4. }
  5.  
  6. - (void) ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
  7. UITouch* touch = [touches anyObject];
  8. [self updateForce: touch];
  9. }
  10.  
  11. -(void) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
  12. b2Vec2 force (0,0);
  13. // Set the force to zero
  14. _force = force;
  15. }
  16.  
  17. - (void) updateForce: (UITouch *) touch {
  18.  
  19. // Get the location of the touch
  20. CGPoint location = [touch locationInView:touch.view];
  21.  
  22. // Find the position relative to the centre of the screen
  23. // remember the screen is 480x320 with the origin at the
  24. // top left hand corner
  25. float xRel = location.x - 240;
  26. // Make it so y-up is positive negative
  27. float yRel = -location.y + 160;
  28.  
  29. // Scale xRel and yRel so they vary between 0 and 1
  30. xRel = xRel / 240;
  31. yRel = yRel / 160;
  32.  
  33. // Now apply a force to the ball
  34. float maxForce = 15 ;
  35.  
  36. // get a pointer to your body
  37. b2Body * body;
  38.  
  39. // Set the linear damping. This means that if the body
  40. // will gradually come to rest if we don't tilt the
  41. // phone.
  42. body->SetLinearDamping(0.5);
  43.  
  44. // Make sure the body is awake
  45. ballBody->SetAwake(YES);
  46.  
  47. // Create a new force depending on where we've touched on the screen
  48. b2Vec2 force (xRel * maxForce * body->GetMass(), yRel * maxForce* body->GetMass());
  49.  
  50. // Set a member variable as the force
  51. _force = force;
  52. }
  53. }

This code just sets the force which is stored in a member variable for this class. Then every step we apply the force to the body:

  1. -(void) update: (ccTime) dt {
  2. b2Body * body;
  3. if(_force.x!=0 && _force.y != 0) {
  4. body->ApplyForce(_force, body->GetWorldCenter());
  5. }
  6. }

This is nice because if the user keeps the mouse clicked it will apply a constant force.

Tweet: 

Add new comment

Filtered HTML

  • Web page addresses and e-mail addresses turn into links automatically.
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>, <c>, <cpp>, <drupal5>, <drupal6>, <java>, <javascript>, <php>, <python>, <ruby>. The supported tag styles are: <foo>, [foo].
  • Allowed HTML tags: <a> <em> <strong> <cite> <blockquote> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.