27th December 2008

Gravity Tutorial for iPhone Part 3

posted in Objective C, iPhone |

See this note.

Here in part three, we are going to do a few small improvements, and add in some gravity. Mid way through part two I realized that I had not set up a way for the ball's color to get passed through for drawing. I could add another parameter to refresh to pass in a color, but it dawned on me, we might as well just pass in the ball instance itself, which has everything that's needed.

Also, why not have the ball itself keep track of its rectangle area? It knows where it is and it knows its own radius, so it should calculate the rect based on these. Let's tackle that first. Add a new method to Ball. First the declaration in Ball.h:

C:
  1. #import <Foundation/Foundation.h>
  2.  
  3.  
  4. @interface Ball : NSObject {
  5.     CGPoint position;
  6.     CGPoint velocity;
  7.     CGFloat radius;
  8.     CGColorRef color;
  9. }
  10.  
  11. @property CGPoint position;
  12. @property CGPoint velocity;
  13. @property CGFloat radius;
  14. @property CGColorRef color;
  15.  
  16. - (void)update;
  17. - (CGRect)getRect;
  18.  
  19. @end

There's a getRect method which recturns a CGRect. And the implementation in Ball.m:

C:
  1. - (CGRect)getRect {
  2.     return CGRectMake(position.x - radius, position.y - radius, radius * 2.0, radius * 2.0);
  3. }

Simple enough.

Now let's change BallView's refresh method to accept a Ball. And get rid of ballRect in there and just store a Ball. Here's BallView.h:

C:
  1. #import <UIKit/UIKit.h>
  2. #import "Ball.h"
  3.  
  4.  
  5. @interface BallView : UIView {
  6.     Ball *ball;
  7. }
  8.  
  9. - (void)refresh:(Ball *)aBall;
  10.  
  11. @end

Note that because BallView is now using the Ball class, we need to import that.

And now BallView.m:

[Note - I fixed an earlier error in here in line 30. Should be fine now.]

C:
  1. #import "BallView.h"
  2.  
  3.  
  4. @implementation BallView
  5.  
  6.  
  7. - (id)initWithFrame:(CGRect)frame {
  8.     if (self = [super initWithFrame:frame]) {
  9.         // Initialization code
  10.     }
  11.     return self;
  12. }
  13.  
  14.  
  15. - (void)drawRect:(CGRect)rect {
  16.     // Drawing code
  17.     CGContextRef context = UIGraphicsGetCurrentContext();
  18.     CGContextSetStrokeColorWithColor(context, ball.color);
  19.     CGContextSetLineWidth(context, 1.0);
  20.     CGContextAddEllipseInRect(context, [ball getRect]);
  21.     CGContextStrokePath(context);
  22. }
  23.  
  24.  
  25. - (void)dealloc {
  26.     [super dealloc];
  27. }
  28.  
  29. - (void)refresh:(Ball *)aBall {
  30.         ball = aBall;
  31.     [self setNeedsDisplay];
  32. }
  33.  
  34. @end

A few things going on here. Notice that refresh now takes a pointer to Ball and stores it, then calls setNeedsDisplay. Then in the drawRect method, we use the ball's color in the CGContextSetSTrokeColorWithColor call, and [ball getRect] in CGContextAddEllipseInRect. Ball has everything we need here.

The last change we need is in the view controller's onTimer method. Instead of creating a rect and passing that to refresh, we just pass the ball.

C:
  1. - (void)onTimer {
  2.     [ball update];
  3.     [(BallView *)self.view refresh:ball];
  4. }

Test that and you should still have a bouncing ball, but now you can change the color of the ball when you create it and this will be reflected in what is drawn in the view.

Now let's add gravity and bounce. In Ball.h, declare them as CGFloats and properties:

C:
  1. @interface Ball : NSObject {
  2.     CGPoint position;
  3.     CGPoint velocity;
  4.     CGFloat radius;
  5.     CGColorRef color;
  6.     CGFloat bounce;
  7.     CGFloat gravity;
  8. }
  9.  
  10. @property CGPoint position;
  11. @property CGPoint velocity;
  12. @property CGFloat radius;
  13. @property CGColorRef color;
  14. @property CGFloat bounce;
  15. @property CGFloat gravity;
  16.  
  17. - (void)update;
  18. - (CGRect)getRect;
  19.  
  20. @end

And synthesize these in the implementation .m file:

C:
  1. #import "Ball.h"
  2.  
  3.  
  4. @implementation Ball
  5. @synthesize position;
  6. @synthesize velocity;
  7. @synthesize radius;
  8. @synthesize color;
  9. @synthesize bounce;
  10. @synthesize gravity;
  11.  
  12. ...

Then we change the update method of Ball to add gravity to the y velocity and use bounce instead of the hard coded -1.0.

C:
  1. - (void)update {
  2.    
  3.     velocity.y += gravity;
  4.     position.x += velocity.x;
  5.     position.y += velocity.y;
  6.    
  7.     if(position.x + radius> 320.0) {
  8.         position.x = 320.0 - radius;
  9.         velocity.x *= bounce;
  10.     }
  11.     else if(position.x - radius <0.0) {
  12.         position.x = radius;
  13.         velocity.x *= bounce;
  14.     }
  15.    
  16.     if(position.y + radius> 460.0) {
  17.         position.y = 460.0 - radius;
  18.         velocity.y *= bounce;
  19.     }
  20.     else if(position.y - radius <0.0) {
  21.         position.y = radius;
  22.         velocity.y *= bounce;
  23.     }
  24. }

If you test this as is, you'll see some problems. One, no gravity. Two, no bouncing. That's because we haven't initialized the bounce or gravity properties. We could require that the user assigns every property when they make a ball, but you might want some default values in there. You can't assign values when they are created like CGFloat bounce = -1.0f; unfortunately. So we do this in an init method, which is close to a constructor.

[Edit - actually, I just found this reference, which indicates that we should have provided the init method from the start, and should have been calling it right from the start. Oh well, better late than never. :) http://developer.apple.com/DOCUMENTATION/Cocoa/Conceptual/ObjectiveC/Articles/chapter_4_section_2.html#//apple_ref/doc/uid/TP30001163-CH22-SW2]

If you just type init in the Ball.m file, you should get a code completion for init Definition. Choose that and it will create an init method for you, with a place to add your initialization code. This is where you set up all your default values, like so:

C:
  1. - (id) init
  2. {
  3.     self = [super init];
  4.     if (self != nil) {
  5.         position = CGPointMake(100.0, 100.0);
  6.         velocity = CGPointMake(5.0, 5.0);
  7.         radius = 20.0;
  8.         color = [UIColor greenColor].CGColor;
  9.         bounce = -0.9f;
  10.         gravity = 0.5f;
  11.     }
  12.     return self;
  13. }

Unfortunately, the init method does not get called by default, so when you allocate the ball, you call it then. This is in the view controller's viewDidLoad method:

C:
  1. - (void)viewDidLoad {
  2.     [super viewDidLoad];
  3.     ball = [[Ball alloc] init];
  4.     ball.position = CGPointMake(100.0, 100.0);
  5.     ball.velocity = CGPointMake(4.0, 3.0);
  6.     ball.radius = 20.0;
  7.     ball.color = [UIColor blueColor].CGColor;
  8.    
  9.     [NSTimer scheduledTimerWithTimeInterval:1.0 / 30.0 target:self selector:@selector(onTimer) userInfo:nil repeats:YES];
  10. }

Line 3 shows the change.

Run this and you have a ball that bounces and finally settles to the "floor". Pretty neat. Note that you can still customize the properties like we are doing for position, velocity, radius and color. You could also leave all those off as long as you call init, and you'll get a default ball.

In part 4 we will add touch support!

Post to Twitter

This entry was posted on Saturday, December 27th, 2008 at 5:24 pm and is filed under Objective C, iPhone. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

There are currently 21 responses to “Gravity Tutorial for iPhone Part 3”

  1. 1 On December 27th, 2008, John said:

    Great reading here, thanks so much. I bought the beginning iphone dev book that you recommended and have been working through it non-stop for the last two days.

    It’ll take a long, long time before I’m even half as comfortable with this stuff as I am with AS3 but it’s definitely been a lot of fun so far and I can’t wait to see the next part of this article :)

    Thanks again!

  2. 2 On December 28th, 2008, BFourneau said:

    Hi,

    great tutorial! But right now, I’m kinda stuck in the refresh method in the BallView-class (right before you would add the gravity-code). I get an error on this line:

    self.ball = aBall;

    the error says:
    error: request for member ‘ball’ in something not a structure or union.

    I was first typing along but when i got this error i copied your code so it’s kinda strange that it still doesn’t work :s

    Thanx!

  3. 3 On December 28th, 2008, kp said:

    Yes, I changed that line to remove the self. just say

    ball = aBall;

    and you should be fine.

  4. 4 On December 29th, 2008, 4 part iPhone Development Tutorial on Gravity from Keith Peters at The iPhone Developer Chronicles said:

    [...] Gravity Tutorial for iPhone – Part 3 [...]

  5. 5 On December 30th, 2008, Scott Janousek said:

    success! ball with gravity. :)

  6. 6 On December 31st, 2008, IPhone SDK - tutoriaux par Keith Peters | tweenpix said:

    [...] la liste complète des tutoriaux: – Part 1 – Part 2 – Part 3 – Part 4 – Part [...]

  7. 7 On December 31st, 2008, Steve-o said:

    I noticed that I can fill the ball with

    CGContextSetFillColorWithColor(context, ball.color);
    CGContextFillPath(context);

    but i can’t fill AND stroke the path. it just does whatever is called first.

  8. 8 On January 8th, 2009, Matthi’s kleine Welt » iPhone SDK & OpenGL ES - Erste Versuche said:

    [...] Tutorial Part 1, Part 2, Part 3, Part 4, Part [...]

  9. 9 On January 10th, 2009, MacDaddy said:

    Steve-o, you can get stroke and fill like this…

    - (void)drawRect:(CGRect)rect {
    // Drawing code
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetFillColorWithColor(context, ball.color);
    CGContextAddEllipseInRect(context, [ball getRect]);
    CGContextFillPath(context);

    CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
    CGContextSetLineWidth(context, 3.0);
    CGContextAddEllipseInRect(context, [ball getRect]);
    CGContextStrokePath(context);
    }

  10. 10 On January 14th, 2009, Rachel said:

    Hi Keith,

    I noticed you’re writing a list to synthesize properties…
    ie.) @synthesize position;
    @synthesize velocity;
    etc…

    I just wanted to let you know that it is possible to synthesize multiple properties by separating them with a comma like this: @synthesize position, velocity, radius, color, bounce, gravity;

    These tutorials are great! Thanks so much for posting them!

  11. 11 On January 25th, 2009, Boon said:

    Hi Keith, as a convention ObjC coders tend to not prefix their accessor with get (but do prefix mutators with set). So a minor code enhancement here would be to turn the getRect method into a property (say rect) and instead of using property/synthesize, you would roll your own accessor to do the calculation there.

    Thanks much for the tutorial.

  12. 12 On January 29th, 2009, Ravi said:

    I got struck with following error
    *** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘*** -[UIView refresh:]: unrecognized selector sent to instance 0×526190′

    From Controller code:

    - (void)onTimer {
    [ball update];
    [(BallView *)self.view refresh:ball];
    }
    ————————-
    self.view is UIView and casted to BallView; But refresh method not picked up from BallView.
    I am missing code where we are initializing BallView? Is it from App Delegate? and how we are doing it?

    Thanks in Advance

  13. 13 On February 2nd, 2009, seb said:

    I have the same problem as Ravi. I get the following message Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘*** -[UIView refresh:]: unrecognized selector sent to instance.
    I am sure what I am missing…

    looking forward to the fix
    S

  14. 14 On February 22nd, 2009, イナヅマtvログ » iPhone SDK + Objective-C, 参考サイト メモ said:

    [...] Gravity Tutorial for iPhone – Part 3 [...]

  15. 15 On March 19th, 2009, GNull said:

    I get the same problem! What the hell! How do I fix this so it compiles?

    I have the same problem as Ravi. I get the following message Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘*** -[UIView refresh:]: unrecognized selector sent to instance.
    I am sure what I am missing…

  16. 16 On April 19th, 2009, Matthew Wallace said:

    pretty sure I got the code correct but I am getting a crash soon as the app tries to load the view. if I remove the ball = [[Ball alloc] init]; in the GravityTotorialViewController then the app will launch without crashing.

    I am using the latest iPhone SKD 3.0. I am wondering if something changes with the way you use “init” in the latest build of the SKD but not sure.

    Any thoughts on how I could trouble shoot this guys ?

    Thanks again for all you do Keith.

  17. 17 On April 19th, 2009, Matthew Wallace said:

    ok so there most be something with usint “init” in 3.0 Here is what I did to get it not to crash.

    In Ball.h I added -(id)runit;

    in Ball.m I replaced the “init” function that is in the tutorial above and called in -(id)runit

    then in my GravityTutorialViewController.m I changed the line that says “ball = [[Ball alloc] init]; …. where “init” put “runit”. Hope that helps anyone that tries this on 3.0 and gets a crash.

  18. 18 On May 4th, 2009, Aman Rai said:

    I tried Matthew’s solution but that doesn’t seem to work. I’m still getting the same error. Anyone got a better solution to this?

    Aman

  19. 19 On May 4th, 2009, Aman Rai said:

    p.s: thanks kieth, for the awesome tutorials.

  20. 20 On August 12th, 2009, Learning Iphone » Gravity Tutorial for iphone said:

    [...] the link, let’s see how much I can do tonight before I gotta get to bed. – Part 1 – Part 2 – Part 3 – Part 4 – Part [...]

  21. 21 On January 21st, 2010, rich said:

    Hi. Finding this tutorial very useful although I am stumped with an error that I’m sure I can’t solve due to a lack of understanding.

    I get “Incompatible type for argument 1 of ‘refresh’” when calling the refresh method in the ViewControllers OnTimer method: [(BallView *)self.view refresh:ball];

    My interpretation is that refresh is expecting a pointer to ball rather than the ball itself although my code seems to be as he tutorial suggests. Any help would be appreciated.

    Thanks

Leave a Reply

Who is reading BIT-101?

Copyright ©2009 by Keith Peters. All rights reserved. This means that you may not reprint or repost the contents of this site without express written permission of the author.


  • Calendar

  • February 2010
    M T W T F S S
    « Jan    
    1234567
    891011121314
    15161718192021
    22232425262728
hoodia order buy Levitra Plus betablockers weight loss information buy pills without a prescription arthritis menopause ambien doses cat's eye health information on cholesterol cialis online order valtrex cheapest phentermine onlin e increase breast size lower blood sugar immediately terramycin which is better cialis or viagra buy cheap cialis reduce cholesterol naturally new blood pressure treatment products for back pain cheapest cialis index will levitra help piroxicam 20 mg order viagra online in germany buy tadalafil online buy levitra onlines how to naturally lower cholesterol buy generic viagra where to buy soma anti allergic drug levothyroxine dogs new hair loss treatmen buy levitra pain meds buy cheap malaria therapy weight loss after baby asthma medications chronic snoring viagra gel prostate cancer cures order viagra cialis alprazolam men health natural cure arthritis immune system support diet medicine cialis approval lipitor effects where can i buy arthritis drugs overactive bladder in men self help weight loss natural cholesterol control ativan medication cialis approval best cure for snoring breast enhancing pills order prozac celebrex pharmacy buy levitra onlines premature ejaculation cure confidence hypnotherapy free stop smoking bust enhance diet weight loss supplements skin fungal infection valium with no prescription viagra with out prescription breast enhancement products alpha blocker medications azithromycin 250mg skin disease chronic heart failure medicines dog care products buying cialis online gerd in children antibiotics to buy my drug store muscle building diet drugs affecting levitra anti anxiety medications really large breast enhancement help for constipation ulcers stomach drugs for high blood pressure selling pet products buy pain medicine viagra online overnight fucidin ointment generic zyrtec prices soft tab cialis smoking treatment dog products online weight loss solution cialis on line blue pills weight loss diet pill nitroglycerin sublingual floxin prevention of heart attack imuran order gasex vermox treatment of depression Viagra On Line buy generic cialis professional tooth whitening kits to buy valium 2mg treatment for hypertension ultram cheapest online stores hair loss products cheap weight loss diovan prescription malaria preventative taurine treating prostate cancer immune system support natural constipation cure phentermine no prescription fast delivery purchase meds without prescription buy plendil diet drug taking viagra after cialis protonix cheapest generic cialis online viagra levitra cialis yohimbe benefits muscle mass gain diet and health products medical treatment for insomnia buy blood pressure meds buy celexa levaquin interactions blood pressure drug skin disorder where can i buy arthritis drugs natural breast enhancer acute pain control online diazepam natural acne remedy antifungal strategies triphala pravachol online how can i stop smoking breast enhancement natural nautral breast enhancement beta blocker medications wellbutrin dosages order viagra cialis lower high blood pressure mass muscle phentermine from canada how to loss weight osteoporosis bone health lipitor use dog medication drug allergies buy diazepam buyviagra cialis phentermine 37.5 mg zestril medication parkinsons treatment generic revatio free nexium cosmetic dentistry tooth whitening avalide generic buy cheap tadalafil uk simvastatin tablets buy cialis online in usa breast pain cat care ovulating clomid medical skin care lines viagra to canada viagra or cialis cheap cialis tramadole buy azulfidine drugs used for cancer ear pain oral ketoconazole raloxifene evista taurine sex with levitra stop smoking today heart failure natural cholesterol control protonix dose oxybutynin 5mg irritable bowel syndrome treatments new treatment for hepatitis c cheap prescription drugs viagra online prescription depression therapy buy sumycin menopause treatment hair loss treatments medication pletal what is a natural antibiotic viagra purchase synthroid tablets generic prilosec lipitor cat health info discount vitamin cholesterol and health bacterial diarrhea weight loss medicine new treatment for depression removing retention fluids diuretic medicines soma 250mg cat anxiety loss weight online pharmacy viagra buy phentermine without a prescription herbs for breast growth cymbalta dosage fast weight loss supplement arthritis menopause levitra online order cheapest place to buy phentermine cold flu medications for nausea buy ultram where pills for acne free weight loss programs help with anxiety improve skin valium 2mg urinary tract health cat urinary tract disease crestor dosage drug zofran calan zyrtec buy nirdosh dosage digoxin buy pain patch acomplia alendronate cialis best price cheap wellbutrin small dog products depression medicine sildenafil dosage dog health depression and anxiety lamictal withdrawal viagra, levitra and cialis online drug buy bone maker strontium cures for hair loss nitroglycerin tablets natural arthritis treatment arimidex buy buy energy patch how to treat a yeast infection viagra herb alternative viagra cialis levitra order sublingual cialis cialis comparison breast lift augmentation seroquel for depression carisoprodol mg new treatment for depression cialis soft tabs safe sleep aid severe leg muscle pain natural weight loss gabapentin medication what is ambien clozapine medication viagra online ordering cures for hair loss free weight loss help buy viagra levitra pet treats order plan b diabetes type 2 phentermine risk ultram er side effects treatment for hepatitis b constipation cures drugs used in treating depression leg pain buy cheap generic cialis anti anxiety meds hypnotherapy for weight loss motilium body building fitness dog skin relieve upper back pain cures for high blood pressure cardura celecoxib Viagra Online Cheap cheap bactrim ambien online lamisil cost infertility meds progesterone clomid osteoporosis hormon urinary tract infection symptoms hypnotherapy for health how to buy viagra online joint pain cure online allegra buy generic cialis uk generic abilify cures for lung cancer new treatments for lung diseases pain meds buy cheap treatment for dry skin disease of the skin nexium drug free stop smoking buy tooth whitening products viagra tablet naprosyn dosage women's fertility male sexual power carisoprodol purchase asthma attack treatment estradiol pills phentermine from canada pet health care hair loss products online astelin generic cheap estrace free weight loss program buy rimonabant relieve lower back pain lexapro prescription new breast cancer drug buying ambien best online viagra scams home scabies treatment hair loss in woman buy generic cialis uk eye drop gabapentin medication amitriptyline uses ultram no prescription natural pain cures buy cla products back pain lowest price generic viagra pain meds buy cheap mg buy phentermine acne skin care cialis rx weight loss and fitness nitrofurantoin buy phentermine without a prescription high blood pressure medicines stop hair loss viagra china use levitra female health coreg dosage carisoprodol price pain relief product breast enlargement depression pills buy how to treat flu home neck pain relief order imitrex online vitamin b-6 cialis soft tabs pharmacy software description of soma buy isoniazid cheap prevacid help ear infections on dog fat burning stop smoking remedies rhinitis treatment chronic pain relief birth control online meds without prescriptions buy lovastatin drug stores penis enlargement without pill cancer medicine buy deltasone cure for throat infection thyroid dogs dosage cipro viagra from uk cheap alcoholism treatment natural cure for constipation paxil cialis 5mg tablets amitriptyline uses topamax drugs lower heart rate drug discount codes dog medicines body fat loss joint pain recurring urinary tract infections ativan information buy drugs online cheap fast valium body building ambien maximum dosage information on valium how to sperm more chlamydia medication dosage buy cialis online viagra chest pain heart fluconazole interaction calcium channel blocker side effects zolpidem dosage online drug stores zelnorm muscle strength fluconazole buy stress gum free weight loss products information on gout low immune system online viagra cialis 20 buy cefixime phentermine from canada gain muscle mass fast lasix side effects buy singulair penis enlargement free natural muscle and joint health viagra online overnight cialis online aceon allergies and asthma diamox side effects weight loss software generic compazine price for tramadol high blood pressure symtoms osteoporosis help treatment severe constipation drug new smoking stop pain relief product xanax online dog health info clonazepam .5mg buy tribulus pregnancy prevention methods allergy hives