views:

286

answers:

3

Hi,

Here is my code for making a bat flap its wings and respond to touches.

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSArray * imageArray = [[NSArray alloc] initWithObjects:
          [UIImage imageNamed:@"Bat1.png"],
          [UIImage imageNamed:@"Bat2.png"],
          [UIImage imageNamed:@"Bat3.png"],
          [UIImage imageNamed:@"Bat2.png"],
          [UIImage imageNamed:@"Bat1.png"],
          [UIImage imageNamed:@"Bat4.png"], 
          [UIImage imageNamed:@"Bat5.png"],
          [UIImage imageNamed:@"Bat6.png"],
          [UIImage imageNamed:@"Bat5.png"],
          [UIImage imageNamed:@"Bat4.png"],
          nil];

    UIImageView * batView = [[UIImageView alloc] initWithFrame:
           CGRectMake(0, 0, 80, 56)];
    batView.animationImages = imageArray;
    batView.animationDuration = 0.70;
    [follower1 addSubview:batView];
    [batView startAnimating];
    [UIImageView beginAnimations:@"follow" context:nil];
    [UIImageView setAnimationDuration:1];
    [UIImageView setAnimationBeginsFromCurrentState:YES];
    UITouch *touch = [touches anyObject];
    follower1.center = [touch locationInView:self];
    [UIImageView commitAnimations];
    [batView release]; 
}

The problem is that after the second touch the animations overlap on top of each other so after every touch it looks like there are lots of bats underneath!

Any help will be much appreciated!

Thank You!

+1  A: 

This is happening because you're adding a new batView each time a touch begins.

One way to fix this is to add the batView once, such as in a superview's or a view controller's init method. If you only want the batView to appear when a touch occurs, you can start it hidden via:

// during initialization
batView.hidden = YES;

Since you're always doing the same animation each time, you might as well set up your animation parameters at the same time, instead of repeating that same set up with each touch:

// still during initialization
NSArray* imageArray = /* set up your image array */;
batView.animationImages = imageArray;
batView.animationDuration = 0.7;

Now, when a touch occurs, you can handle it by starting the animation:

// Within touchesBegan:
    ...
    // Start the batView animation.
    batView.hidden = NO;
    if (![batView isAnimating]) [batView startAnimating];
    // Hide the animation when it's done.
    [self performSelector:@selector(hideBat) withObject:nil afterDelay:0.71];
}

// Later:

- (void) hideBat { batView.hidden = YES; }

You might want to do something different in hideBat if you don't always want it to disappear right after a single animation. For example, if you want to always repeat an animation until the user stops clicking, you could set up an NSTimer object to go off as soon as there has been no user touches for at least 0.7 seconds. Each time the user touches the screen again, you can reset this timer.

Reference: UIImageView docs, which includes brief descriptions of the animation methods.

Tyler
A: 

Hi, Here is my attempt at adding your code:

  • (void)viewDidLoad {

    NSArray * imageArray = [[NSArray alloc] initWithObjects:

         [UIImage imageNamed:@"Bat1.png"],
         [UIImage imageNamed:@"Bat2.png"],
         [UIImage imageNamed:@"Bat3.png"],
         [UIImage imageNamed:@"Bat2.png"],
         [UIImage imageNamed:@"Bat1.png"],
         [UIImage imageNamed:@"Bat4.png"], 
         [UIImage imageNamed:@"Bat5.png"],
         [UIImage imageNamed:@"Bat6.png"],
         [UIImage imageNamed:@"Bat5.png"],
         [UIImage imageNamed:@"Bat4.png"],
         nil];
    

    UIImageView * batView = [[UIImageView alloc] initWithFrame: CGRectMake(0, 0, 80, 56)];

    batView.animationImages = imageArray;

    batView.animationDuration = 0.70;

    batView.hidden = YES;

    [batView startAnimating];

    [follower1 addSubview:batView];

    [batView release];

}

  • (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    [UIImageView beginAnimations:@"follow" context:nil];

    [UIImageView setAnimationDuration:1];

    [UIImageView setAnimationBeginsFromCurrentState:YES];

    UITouch *touch = [touches anyObject];

    follower1.center = [touch locationInView:self];

    [UIImageView commitAnimations];

    UIImageView * batView;

    if (![batView isAnimating]) [batView startAnimating];

    batView.hidden = NO;

    // Hide the animation when it's done.

    [self performSelector:@selector(hideBat) withObject:nil afterDelay:0.71];

}

  • (void)hideBat {

    UIImageView * batView;

    batView.hidden = YES; }

  • (void)dealloc {

    [super dealloc]; }

@end

Thanks for your help so far Tyler!

My attempt at adding your code has produced an objc_msgSend crash. I have been stuck on this for 2 months, its really annoying me now. I have very limited free time and usually find something else to do but this is now the last piece of the jigsaw!

All i am trying to do is make a bat look like it flapping its wings while following your finger touches. Someone must have done this before?

If i cant figure this out myself i will be giving credit to the person who does! Its the least i could do!

Picoman Games
Do you know which function of yours the code is executing when it crashes? One idea is to comment out the performSelector line to check if that is the culprit (that would be my first guess).
Tyler
A: 

Is there a way to release the previous set of .pngs before loading the next? This would eliminate the overlapping?

Anyone got any ideas?

Alex