Exploring iPhone Graphics Part 3
May 5th, 2008 Posted in Software Development, iPhone![]()
Last time we created a simple iPhone application that made a ball bounce around the screen. This time we are going to extend the last example to use the accelerometer to create a gravity influence on the ball. So as you tilt the device the ball will roll in the direction of the tilt.
The first thing we need to do is add a way to influence the ball’s motion. I’ve added an influence method to the Vector2D class. Also the GravityView class gets a gravity variable that is a Vector2D class instance.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | - (void)influence:(Vector2D*)influenceVector Max:(CGFloat)max; { [endPoint addVector:influenceVector]; length = sqrt(endPoint.X * endPoint.X + endPoint.Y * endPoint.Y); CGFloat newAngle = atan2(-endPoint.Y, endPoint.X) * ONEEIGHTYOVERPI; if(newAngle < 0) { newAngle += 360; } if(abs(newAngle - influenceVector.angle) >= 90) { length *= 0.96; } else { length *= 1.03; } if(length > max) { length = max; } else if(length < 0.0) { length = 0.0; } [self setAngle:newAngle]; } |
This method is passed another vector and a max value. The passed in influenceVector is added to the ball’s endPoint. If the ball is currently moving away from the influence vector then it is slowed down slightly by multiplying the vector length by 0.96. If the ball is currently moving toward the influence vector then it is sped up slightly by multiplying the vector length by 1.03. The maximum length of the vector is capped at the max value passed into the method. The vector is not allowed to have a negative length.
I’ve also added a method to the Vector2D class to scale the length of the vector.
1 2 3 4 5 6 7 8 9 10 11 12 | - (void)scaleLength:(CGFloat)factor; { length *= factor; if(length < 0.05) { length = 0.0; } double radians = angle * PIOVERONEEIGHTY; endPoint.X = length * cos(radians); // could speed these up with a lookup table endPoint.Y = -(length * sin(radians)); } |
This method simply multiplies the vector length by the scale factor. When the length of the vector becomes very small it is set to zero.
In order to receive accelerometer events we make the GraphicsView class implement the UIAccelerometerDelegate prototype.
1 | @interface GraphicsView : UIView <UIAccelerometerDelegate> |
In the GraphicsView initWithFrame method we need to set up the accelerometer.
1 2 3 4 5 | accelX = 0.0; accelY = 0.0; [[UIAccelerometer sharedAccelerometer] setUpdateInterval:(1.0 / 60)]; [[UIAccelerometer sharedAccelerometer] setDelegate:self]; |
We are initializing the accelerometer x and y values to zero, setting the update interval so that we receive updates 60 times per second and setting self as the delegate.
With the accelerometer set up the accelerometer method of our GraphicsView object instance will be called 60 times per second.
1 2 3 4 5 6 7 | - (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration { accelX = (acceleration.x * kAccelFilt) + (accelX * (1.0 - kAccelFilt)); accelY = (-acceleration.y * kAccelFilt) + (accelY * (1.0 - kAccelFilt)); [gravity setEndPointX:accelX*2 Y:accelY*2]; } |
We are using a filter to isolate the current device position. Each time the method is called we set the gravity vector’s end point to two times the accelerometer X and Y values. We don’t need the Z axis accelerometer for this example. Note that we are using negative Y to account for coordinate system differences.
The final piece of the puzzle is to call the influence method of our ball’s vector in the timer tick method.
1 2 3 4 5 6 7 8 9 10 11 | - (void)tick { // Apply gravity influence [ball.vector influence:gravity Max:8.0]; // Update the balls position [ball move:self.bounds]; // Tell the view that it needs to re-draw itself [self setNeedsDisplay]; } |
That’s all there is to it. Prett simple eh?
Here are the new source files:
Exploring iPhone Graphics Part 3 Source












Related Articles:

That’s great. Thank you!
Great tutorials, thanks! I have a question though. No matter how I play with the values here the motion of the ball doesn’t feel exactly right. I want it to be nice and smooth the way apps like “Labyrinth” on the app store are. Do you have any recommendations on how to adapt this code to make it like that, or are they using an entirely different algorithm do you think? Thanks!
My algorithm is home grown and just for demonstration purposes.
List of physics engines: http://www.digitalrune.com/KnowledgeBase/RigidBodyDynamics/PhysicsEnginesList/tabid/476/language/en-US/Default.aspx
[...] I have found a good tutorial on the subject of making a ball move based on the accelerometer: Exploring iPhone Graphics Part 3 | Trails in the Sand but the motion of the ball does not look nearly as smooth as other apps I have seen (Labyrinth is [...]
Hi, great tutorial, very nice job. However, I can’t deal with a transposition for my own needs. And NOBODY (yes, i said NOBODY) on the web seems to understand something and explains about vectors, except you ^^
I’m sure that my study case should be easy for you, so if you would help me a little on this, it would be very nice
If so, send me a PM or email me at ivico92@free.fr (I’d like to talk about my project in privacy ^^)
Thank you, bye bye
iVico
awsome!