iPhone Tutorial: Using the iPhone's accelerometer with Cocos2D

In this part of the tutorial I'll explain how to use the iPhone's built in gyroscope to control the tilt of the labyrinth board that we created in the earlier iPhone tutorial. In Cocos2D this is very easy to do but before we start it's worth explaining what kind of information you're going to get from the accelerometer. The accelerometer measures force - direction and strength. The phone will experience forces for two reasons. Firstly, gravity is always applying a downwards force on the phone towards the centre of the earth. The phone will also experience forces if you apply them to it with your hands. By waving the phone around or shaking it. In Cocos2D we access these forces by overriding a method in our HelloWorldLayer. When we do this we gain access to three variables: x-force, y-force and z-force. From the diagram you can see the directions of these components. Using these forces we can gain some idea about what's happening to the phone. If the phone is being held quite still, then the only force acting will be gravity. Knowing this we can find the exact orientation of the phone.

For our labyrinth game we're only going to be using the x and y force components and we're going to wire up these componentes directly to the worlds gravity.

Setting up the project:

Open up the labyrinth project we've been working on. Firstly we need to make a few tweaks. In the AppDelegate file change the shouldAutorotateToInterfaceOrientation to look like this:

  1. // Supported orientations: Landscape. Customize it for your own needs
  2. - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
  3. {
  4. return interfaceOrientation == UIInterfaceOrientationLandscapeLeft;
  5. }

This means that the screen will only support one landscape mode. If you didn't do this when you tilted the phone away from you the screen would rotate to that direction.

Next we're going to disable retina support. ShapeWorkshop can support retina displays but you would need to create separate hd images. For this tutorial we're not going to do that so it's best for retina to be disabled. In the app delegate in the application method find this line and make sure it's set to "NO":

  1. // Enables High Res mode (Retina Display) on iPhone 4 and maintains low res on all other devices
  2. if( ! [director_ enableRetinaDisplay:NO] )
  3. CCLOG(@"Retina Display Not supported");

Finally, we need to delete the code which simulates tilting by clicking on the screen. In the HelloWorldLayer remove the following code:

  1. - (void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
  2. UITouch* touch = [touches anyObject];
  3. [self updateBallForce:touch];
  4.  
  5. }
  6.  
  7. - (void) ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
  8. UITouch* touch = [touches anyObject];
  9. [self updateBallForce:touch];
  10. }
  11.  
  12. -(void) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
  13. b2Vec2 force (0,0);
  14. _ballForce = force;
  15. NSLog(@"Force: %f, %f", _ballForce.x, _ballForce.y);
  16. }
  17.  
  18. - (void) updateBallForce: (UITouch *) touch {
  19.  
  20. // Get the location of the touch
  21. CGPoint location = [touch locationInView:touch.view];
  22.  
  23. // Find the position relative to the centre of the screen
  24. // remember the screen is 480x320 with the origin at the
  25. // top left hand corner
  26. float xRel = location.x - 240;
  27. // Make it so y-up is positive negative
  28. float yRel = -location.y + 160;
  29.  
  30. // Scale xRel and yRel so they vary between 0 and 1
  31. xRel = xRel / 240;
  32. yRel = yRel / 160;
  33.  
  34.  
  35. // Now apply a force to the ball
  36. float maxForce = 15 ;
  37.  
  38. // Check that there is a ball
  39. if(_ball != Nil) {
  40. b2Body * ballBody;
  41.  
  42. // The body is stored as a pointer wrapped in an NSValue
  43. // get a reference to the NSValue
  44. NSValue * bodyValue = _ball.physicsLink;
  45.  
  46. // Populate ballBody with the reference
  47. [bodyValue getValue:&ballBody];
  48.  
  49. // Set the linear damping. This means that if the ball
  50. // will gradually come to rest if we don't tilt the
  51. // phone.
  52. ballBody->SetLinearDamping(0.5);
  53.  
  54. // Make sure the body is awake
  55. ballBody->SetAwake(YES);
  56.  
  57. // Create a new force depending on where we've touched on the screen
  58. b2Vec2 force (xRel * maxForce * ballBody->GetMass(), yRel * maxForce* ballBody->GetMass());
  59. _ballForce = force;
  60.  
  61.  
  62.  
  63.  
  64. }
  65. }
  66.  
  67. // -(void) update: (ccTime) dt {
  68. // . . . . .
  69. // Delete this bit:
  70. if(_ball != Nil) {
  71. // Apply the force to the ball
  72.  
  73. bodyValue = _ball.physicsLink;
  74. [bodyValue getValue:&ballBody];
  75.  
  76. if(_ballForce.x!=0 && _ballForce.y != 0) {
  77. ballBody->ApplyForce(_ballForce, ballBody->GetWorldCenter());
  78. }
  79. }
  80. // . . . . . .
  81. //}

Adding the gyroscope:

Now we need to add code for the gyroscope. First add the following to the init method in HelloWorldLayer to activate the accelerometer in Cocos2D:

  1. self.isAccelerometerEnabled = YES;

Next add the following function:

  1. // Override the accelerometer method
  2. -(void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
  3.  
  4. if(_ball != Nil) {
  5. // Get a pointer to the ball's physics body
  6. b2Body * ballBody;
  7. NSValue * bodyValue = _ball.physicsLink;
  8. [bodyValue getValue:&ballBody];
  9.  
  10. // Make sure the body is awake (if it's not awake it won't be affected by gravity)
  11. ballBody->SetAwake(YES);
  12. }
  13.  
  14. // Set the gravity by the tilt angle
  15. b2Vec2 gravity ( 20 * acceleration.y, - 20 * acceleration.x);
  16. NSLog(@"Gravity: %f, %f", gravity.x, gravity.y);
  17. _world->SetGravity(gravity);
  18. NSLog(@"Acceleration: %f, %f, %f", acceleration.x, acceleration.y, acceleration.z);
  19. }

Run the project on an iPhone or iPod Touch and the ball should now be controlled by the accelerometer.

I hope you've enjoyed this tutorial. If you have any feedback or comments about future tutorials you'd like to see please post them below or on the forum.

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.