For the final installment in this series, we’ll add accelerometer support to the ball, allowing you to tilt the device to change the direction of “down”. Note, although you can rotate the device in the iPhone simulator, this does not simulate acceleration. The only way you’ll be able to see this in action is on a physical device. This means that you’ll have to pay $99 sign up for and be accepted to the iPhone Developer program, and figure out how to provision apps to your device. I’m not going to cover that here, so I’ll assume that you’ve figured that out on your own. OK, let’s jump in.
So far, we have gravity in the ball, affecting its y velocity. If we know which way the device is tilted, we can change that to affect the velocity on the x axis as well, proportional to the degree of tilt. For example, if you tilted the device 90 degrees to the left, gravity should only affect the x velocity. If you turn it upside down, it will affect only the y velocity again, but in the opposite direction. In most cases, it will not be exactly straight, so there will be some x velocity and some y, proportional to the angle of tilt.
To respond to acceleration, we need to do three things:
1. Have a class specify the UIAccelerometerDelegate protocol. This is similar to implementing an interface in ActionScript. But less strict. It’s telling the application that you expect this class to respond to acceleration, and it may have some of the methods associated with this protocol. But unlike an interface, you are not required to implement all or even any of the methods.
2. Set the class as a delegate for accelerometer events. Think of this as adding an event listener.
3. Create a method to respond to the events. Here is where you will change gravity.
OK, step 1, specifying the protocol. We’ll have the Ball class do this directly, as that’s where gravity is. You just put the protocol name in angle brackets after the class name and and super classes, like so:
[c]@interface Ball : NSObject
…[/c]
I’m not really sure what this does to be honest, as it seems you can be a delegate without specifying the protocol (although you will get a warning), and you can specify the protocol without being a delegate. But you’re supposed to do it, so do it.
Step 2. Set self as a delegate. We’ll do that in the init method in Ball.m:
[c]- (id) init
{
self = [super init];
if (self != nil) {
position = CGPointMake(100.0, 100.0);
velocity = CGPointMake(5.0, 5.0);
radius = 20.0;
color = [UIColor greenColor].CGColor;
bounce = -0.9f;
gravity = 0.5f;
dragging = NO;
[[UIAccelerometer sharedAccelerometer] setDelegate:self];
}
return self;
}[/c]
sharedAccelerometer is a class (static) property of the UIAccelerometer class, I assume it’s like getInstance of a Singleton. You are calling setDelegate on that object, passing self (this). Simple enough.
Step 3. Create a method which will be called on acceleration. Again, right in Ball.m:
[c]- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
NSLog(@”x: %f, y: %f”, acceleration.x, acceleration.y);
}[/c]
You don’t need to declare this, as you specified the protocol, which, come to think of it, is probably why you set the protocol.
The method is called accelerometer and passes a pointer to a UIAccelerometer object, and a pointer to a UIAcceleration object. It’s this last one we’re interested in, as that will tell us the amount of tilt.
Here I’ve just put in a log statement so you can see that it’s working. The acceleration parameter passed in will contain x, y, and z properties, which will range from -1.0 to +1.0. We’re only interested in x and y. x will be -1.0 when the device is tilted 90 degrees to the left, 0.0 when it’s upright and +1.0 when tilted to the right. Likewise, y will be -1.0 when upright, and vary towards 0.0 on either side, and then to +1.0 when the device is upside down.
So, rather than a single value for gravity, we’ll need x and y values for gravity. We can store these in a point object. Declare it in Ball.h:
[c]CGPoint acceleratedGravity;[/c]
Leave gravity there, as that will affect the overall strength of gravity and generally stays the same. This new variable will change constantly according to tilt.
You can also initialize this in the init method:
[c]acceleratedGravity = CGPointMake(0.0, gravity);[/c]
Note that the x value is initialized to 0.0 and y to gravity, indicating no rotation.
Now we can change the acceleration method to alter this variable:
[c]- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
acceleratedGravity.x = acceleration.x * gravity;
acceleratedGravity.y = -acceleration.y * gravity;
}[/c]
Note that the y value is reversed, otherwise the ball would fall “up”.
Finally, we just need to alter the update method in Ball.m to utilize acceleratedGravity instead of just gravity:
[c]- (void)update {
if(dragging) return;
velocity.x += acceleratedGravity.x;
velocity.y += acceleratedGravity.y;
position.x += velocity.x;
position.y += velocity.y;
…
[/c]
And that’s it! Pretty simple actually. Now you tilt the device and the ball will always fall “down”. It will settle in a corner, or on the “top” of the device, or whatever direction is down. Amazing just how easy that was. Less than 10 lines of code in all.
And that brings us to the end of this series. Bear in mind that I’m a beginner at this stuff, and was writing this for my own selfish reasons – to learn the language and drill it into my head. I’ve already seen several places where the code in this project is not up to snuff at all. I may go back and correct it at some point, but I’ll just say for now to take what I’ve written here as a jump start. It will get you up and running, but you really need to learn more about the right way to do things, like I am already doing. And if you find something that indicates I did something incorrectly, it’s probably right.
Dude, i really wanna thank you!
all posts of this tutorial, are simple and clear for me, who never develop in iPhone SDK!
Plz keep this good posts!
And u recommend the book of first tutorial, for who never develop in sdk before? Or another?
Great tutorial really!!
But this just spoiled my day: “This means that you’ll have to pay $99 sign up for and be accepted to the iPhone Developer program”!
Great tutorial!
First one that I’ve read that does something interesting while still explaining every bit of code. Could you post those references that show that your code is “not up to snuff.” ?
any chance of getting the source code. .i tried following and i must of missed something and i cant seem to find where the error is.
Amazing! Wrote an iPhone app, that I understand, with graphics, accelerometer, touch sensitivity, all within 45 minutes! Your tutorial is great!
Only catch is that the simulator does not seems to have accelerometer built in, strange, so I can’t test if the tilt really works. Must download it into a friend’s iPhone next to try this.
Thank you man!
Great Tutorial!
Example runs nicely in iPhone too!
Thanks very much for taking the time to write these tutorials.
Explaining things in actionscript terms has really helped me get up to speed. Although there are still quite a few syntactical oddities in Objective-C that leave me slightly confused.
Fun fun
Cheers
Is possible to download the tutorial ?
Thanks a lot for your work.
Thierry
Thanks,
I am a Visual Studio guy and have been for years. Your tutorials have been very helpful in crossing the gap.
I tried to follow along and made a few mistakes. Where can I find the source code?
It is a wonderful tutorial. I tried following the steps. However getting some errors. Do you have tutorial source code? Thanks in advance.
Can you please add the complete sample code so i can actually see a demo of what would be the end product?
Thx for great tutorial.
Im having some errors when trying to compile…. can’t find a way to fix them.
Can u please post complete code of the working project, so i can compare with mine and see whats wrong?
thx!
Awesome tutorial! Thanks for relating this all to ActionScript.
Well, we all know you can’t do pinball in Flash.
Ian, yes, this has been proven.
Great set of tutorials. I have created a more generic version of this code so that it can easily be re-used. I am also providing all source code. Feel free to check it out at http://blog.rawjam.co.uk/index.php/development/iphone-gravity-tutorial-code/
Great Tutorial! But I wanted to know, if it’s possible to add more than just one ball and use them all like you do in this tutorial? I was experimenting a little bit, but I didn’t get any positive result :(. I tried to use the Ball-Class as an array of objects. Does somebody have any ideas? Please let me know.
hey chaoz I also have the same question that is it possible for more than one ball if you have found anything then please let me know I am new to iphone so help me out budy.
Great Tutorial. I was learning iphone app development for past 2 months. Because my root knowledge of programming is from Action Script, even after learning the basics of development i always got some confusion. This tutorial gave more clear idea about how to transfer the flash knowledge to iphone. It will be great if you write a book on actionscript to iphone. Thanks
some purists would criticize your comment, “I’m not really sure what this does to be honest, as it seems you can be a delegate without specifying the protocol”
imho, you’re a hacker opposed to an theorists/purist/etc and thats great! hackers often make the nicest code, realizing that coding for other humans–to read, to learn, to contribute, to grow–is more important than coding for the machine.
thanks for your time.
Hi, thanks for the great tutorials! Shame I can’t test the last one properly until I fork out the $99… but I think I’ll do that when (if!!) I get close to completing a publishable App.
Just one small bug I spotted – should be
Here’s a copy of the source I put together:
http://www.iheals.net/upload/Gravity.zip
If you like World of Warcraft check out my iPhone game out http://www.iheals.net
It’s people like Keith that enabled me to make apps in the first place, you rule.
Tim
This is awesome tutorial, Thank you so much to post them here.
UPDATE: http://www.iheals.net/upload/Gravity-Universal.zip
I’ve converted the Gravity app to universal so you can see how it goes on the iPad too. Apart from running the ‘Upgrade to Universal’ I had to slightly modify the code in Ball.m to the following. Note how the resolution specific code is now device independent.
– (void)update {
if(dragging) return;
velocity.x += acceleratedGravity.x;
velocity.y += acceleratedGravity.y;
position.x += velocity.x;
position.y += velocity.y;
CGFloat width = [UIScreen mainScreen].bounds.size.width;
CGFloat height = [UIScreen mainScreen].bounds.size.height;
if(position.x + radius > width) {
position.x = width – radius;
velocity.x *= bounce;
}
else if(position.x – radius height) {
position.y = height – radius;
velocity.y *= bounce;
}
else if(position.y – radius < 0.0) {
position.y = radius;
velocity.y *= bounce;
}
}
Hey friends I found this tutorial interesting but I really wanted to know that is it possible to do this for more than one ball? I am really looking forward to it so please help me out with it
Hi,
Great tutorial but how would i use a image instead of drawing the ball ?
Thanks in advance.
great tutorial series, as an as3 dev moving to iOS I found it all very interesting.
your humility in admitting when you don’t know something is refreshing!