Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I change an animation for an object while it is already animating?

So, right now I have a rocket which bounces side to side across the bottom of the iphone 5 screen. I want the rocket however to stop moving side to side but to go upwards once the user touches the screen (so touching the screen makes the rocket take off).

First, in viewDidAppear I told the compiler to run the spawnRocket method after 2 seconds.

In the spawnRocket method I established the rockets image and frame, and then I added it to the view and performed a uiview animation sending the rocket to the right side of the screen. In the finished parameter in the uiview animation method I told the compiler to run the moveRocketLeft method.

In the moveRocketLeft method I did an animation which would send the rocket to the left of the screen, and in the finished parameter I ran the moveRocketRight method.

The moveRocketMethod is basically the spawnRocket method except I don't establish the rockets image and frame and add it to the view.

So after all this, I tried to implemented the -touchesBegan:withEvent: method. I tried simply running a uiview animation which changed the rockets y to off the screen upwards, and the x to whatever the x was currently at when the user touched the screen.

However, I realize that the calling the rockets frame does not return the location that the rocket looks like while animating. It really just returns what the rockets frame will be when its done animating. So, to get the frame I want should I call layer? I remember reading somewhere that layer will return the actual location of a uiimageview during an animation. But, layer only has the property bounds and not frame, so I'm a little confused.

I also tried calling [self.view.layer removeAllAnimations]; and then running a new animation which would shoot the awkward up, but the removeAllAnimations method never worked (and anyway i don't really like the idea of using that because i heard it lags).

So anyone have any idea how i can implement touchesBegan:withEvent: method so that the rocket can take off correctly? (or if you think I have to change my whole program please feel free to help)

    #import "ViewController.h"
    #import <QuartzCore/QuartzCore.h>
    @interface ViewController ()
    @property UIImageView *rocket;
    @end

    @implementation ViewController


    @synthesize rocket=_rocket;

    - (void)viewDidLoad
    {
        [super viewDidLoad];

    }

    -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[self.view.layer removeAllAnimations];
     //   [UIView animateWithDuration:3 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^(){self.rocket.frame=CGRectMake(self.rocket.frame.origin.x, -40, 25, 40);} completion:^(BOOL finished){}];

    // this didn't work :(
    }



    -(void)viewDidAppear:(BOOL)animated{
        [self performSelector:@selector(spawnRocket) withObject:self afterDelay:2];
    }
    -(void)spawnRocket{
        self.rocket=[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"default.png"]]; //places imageview right off screen
        self.rocket.frame=CGRectMake(-25, 420, 25, 40);

        [self.view addSubview:self.rocket];
        [UIView animateWithDuration:1.5 delay:0 options:UIViewAnimationOptionCurveLinear animations:^(){self.rocket.frame=CGRectMake(295, 420, 25, 40);}  completion:^(BOOL finished){if (finished)[self moveRocketLeft]; }];


    }

    -(void) moveRocketLeft{
        [UIView animateWithDuration:1.5 delay:0 options:UIViewAnimationOptionCurveLinear animations:^(){self.rocket.frame=CGRectMake(0, 420, 25, 40);} completion:^(BOOL finished){if (finished)[self moveRocketRight];}];
    }

        -(void)moveRocketRight{
          [UIView animateWithDuration:1.5 delay:0 options:UIViewAnimationOptionCurveLinear animations:^(){self.rocket.frame=CGRectMake(295, 420, 25, 40);} completion:^(BOOL finished){if (finished)[self moveRocketLeft];}];
        }
    - (void)didReceiveMemoryWarning
    {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }

    @end
like image 801
Mindi Hansen Mende Avatar asked Dec 04 '25 16:12

Mindi Hansen Mende


1 Answers

This should do the trick

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    CALayer *rocketPresentationLayer = [self.rocket.layer presentationLayer];
    self.rocket.layer.position = rocketPresentationLayer.position;
    [UIView animateWithDuration:3 delay:0 options:UIViewAnimationOptionCurveEaseIn|UIViewAnimationOptionBeginFromCurrentState animations:^(){self.rocket.frame=CGRectMake(self.rocket.frame.origin.x, -40, 25, 40);} completion:^(BOOL finished){}];
}

Note 1: I didn't put logic in here to check whether the user tapped the rocket again, when it is taking off vertically. You might want to add a BOOL or something to see if the user successfully hit the rocket or not, and if so, don't perform the vertical animation again.

Note 2: If in future you only want this to occur when the rocket is hit, you can use hitTest checking to call the animation conditionally.

// Get the touch
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self.view];

// See if we hit the rocket
CALayer *rocketPresentationLayer = [self.rocket.layer presentationLayer];
CALayer* hitTest = [rocketPresentationLayer hitTest:touchPoint];

// If we did, then stop animation and move upwards
if (hitTest) {
    ....
}

P.S: Also as a slight mention, @property UIImageView *rocket; should be changed to @property (nonatomic) UIImageView *rocket;. This is primarily for performance reasons, as I don't expect your rocket to be accessed by multiple threads (it shouldn't, it's the UI!).

like image 60
WDUK Avatar answered Dec 07 '25 07:12

WDUK