views:

56

answers:

2

I'm trying to make a slot machine animation where the reels spin. to do this, I'm using drawRect to draw images in a custom class that inherits from UIView. I'm using an nstimer to update the position of the images and calling [self setNeedsDisplay] to update the drawing. In the simulator, it looks very good, however, on the device, it is very laggy. I was wondering if i'm doing something wrong with my method of drawing or is there any better solutions.

- (void)drawRect:(CGRect)rect
{   
    [image1 drawInRect:CGRectMake(0, image1Position, 98, 80)];
    [image2 drawInRect:CGRectMake(0, image2Position, 98, 80)];
    [image3 drawInRect:CGRectMake(0, image3Position, 98, 80)];
}


- (void)spin
{
    // move each position down by 10 px
    image1Position -= MOVEMENT;
    image2Position -= MOVEMENT;
    image3Position -= MOVEMENT;
    // if any of the position <= -60 reset to 180
    if(image1Position < -50)
    {
        image1Position = 180;
    }
    if(image2Position < -50)
    {
        image2Position = 180;
    }
    if(image3Position < -50)
    {
        image3Position = 180;
    }
    [self setNeedsDisplay];
}

-(void)beginSpinAnimation
{       
    timer = [NSTimer scheduledTimerWithTimeInterval:SCROLL_TIME target:self selector:@selector(spin) userInfo:self repeats:YES];
}

My CoreAnimation Attempt with UIScrollView:

- (void) spinToNextReel
{   
    int y = self.contentOffset.y + 80;

    // if the current >= last element reset to first position (-30)
    if(y >= (80 *(elementCount+1) - 30))
    {
        y = -30;
    }

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDuration:SCROLL_TIME];
    [UIView setAnimationCurve:UIViewAnimationCurveLinear];

    self.contentOffset = CGPointMake(0, y);

    [UIView commitAnimations];

    if (!isSpinning && targetY == y)
    {
        NSLog(@"target is %d, y is %d", targetY, y);

        if(timer)
        {
            [timer invalidate];
            timer = nil;
        }
        [self playSound];
    }
}
+4  A: 

I would say research into CoreAnimation. It is made to do what you want to do here. It'll be much faster than what you are doing here.

As for it being slow, calling drawInRect isn't the fastest thing in the world. What is SCROLL_TIME?

Joshua Weinberg
Faster and less troublesome.
Steven Fisher
Seconded. Especially on a mobile device. CoreAnimation is a lot better (as in "fast" and "battery-friendly") than the best you'll be able to do in Cocoa on your own.
Joshua Nozzi
SCROLL_TIME is at .05 its just a float i defined.I think from all the responses, the answer is CoreAnimation. Is there a good simple example of CoreAnimation from apple? On a side note, on a previous attempt, I used a CoreAnimation along with UIScrollView (check the edited post above) However, it causing a slight hickup when it tries to stop on the last reel, and that is why I tried to draw it myself.
tul697
+1  A: 

You want to use CoreAnimation, it will be a lot easier, and more efficient. Having said that, if you insist on trying to manually animate this way you are doing a couple of thing wrong:

  1. Do not attempt move a constant amount on fixed intervals, timer events can be delayed, and if they are that will result in your animation being uneven, since you are moving a constant amount per event, not per time interval. You should record the actual timestamp every time you animate, compare it to the previous timestamp, and move an appropriate number of pixels. This will result in even amounts of movement even if the events are delayed (effectively you will being dropping frames).

  2. Do not use an NSTimer, use a CADisplayLink. That will tie your drawing to the native refresh rate of the system, and synchronize it with any other drawing that is going on.

  3. I know I said it already, but learn and use CoreAnimation, you will be much happier.

Louis Gerbarg