views:

378

answers:

2

I'm working on writing a rather basic app. It uses minimal touch input, and mostly just plays fancy animations. There isn't much animation, but the way it's currently done seems super inefficient and uses far too much memory.

The view is split into two parts, the bottom 1/5th is just one image that doesn't ever change. The rest of it is where the animation plays. It's currently done by loading the 32 images into an array and then playing through them (8fps). It does this a total of 4 times going through each animation. The pictures aren't huge, but they're still rather large. I was also wondering the best file format to store them as, both in terms of overall size and the overhead required.

This is a super simple approach, and it works, but it just doesn't seem to be cutting it memwise, it uses too much.

My suggestion was to split the animation up into some layers, because there's a few things I think could be done differently:

  • Make the background one static image, so it doesn't have to be part of the animations
  • Take out a few of the "doodads", such as moving graphs and a progress bar, and make those their own partially transparent layers, on top of or below the animations. This would also open up the door as far as creative freedom goes in the future for me.
  • Cut out the text at the top and use the iPhone to programmatically display the text instead. Is it better to use the iPhone to draw the text or to load an image with text in it? Being primarily a Web Dev, I find it silly to load any images with text in them.
  • Play what's left after these things are cut out as the animations, which would be considerably smaller.

So overall, we're looking at 1 static background, 3-5 small animations, and one large one. Can I use layers to make these elements all separate, and rely more on the iPhone to draw the final image? That was where I thought I could have this run a little better, it seems silly to merge everything into one big picture that you flip through like a flip book, when you can instead load a few smaller elements that are used app-wide, and do things quite a bit more efficiently.

Or, am I totally overcomplicating this and is there a better way to go about it?

Edit: I've been browsing around and it appears that using layers would be more efficient. I also have another question, though. Is it better to have each frame of the animation as it's own file, and loaded into the array for animation, or to have one giant sprite sheet image with all the frames, and have the iPhone grab each frame from within the sprite sheet using coordinates programmatically?

Edit 2: We've since worked everything out, check it out on the App store.

+1  A: 

Assuming that the total animation sequence is static, you're best bet is to compile it as movie, and use the movie player framework to play it:

MPMoviePlayerController

This will allow the iPhone to use custom hardware for the display, and will keep the battery use low. As to user interaction, you just need to set the movieControlMode property to prevent the user from being able to interact with the movie:

MPMovieControlModeHidden Do not display any controls. This mode prevents the user from controlling playback.

Available in iPhone OS 2.0 and later.

Declared in MPMoviePlayerController.h.

Douglas Mayle
Would that allow the user to control the playback of the video? We do not want that to happen whatsoever.
Sneakyness
Not at all, you have the option of whether or not to display user controls
Douglas Mayle
It appears from the documentation that it only allows for a full screen movie? I need the movie to be playing not fullscreen.
Sneakyness
A: 

Here is an extremely early version of what I used to fix our problem. I'm well aware that it isn't anything close to ideal, but it works. If you feel like you need to write this more awesomely, by all means do so. I'll try and remember to come back and post an update later.

The timer loses it's ability to be on time @ <0.1 seconds, so if you set it for say 28fps, with images rendered out for 28fps, it will drop frames, but pretty unnoticeably so.

    - (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"VDL");
    [animationFrame initWithInteger:1];
    [self animation];
    NSLog(@"VDL Completed");
}

- (void)animation {
    CGRect animationRect = CGRectMake(0, 0, 320, 384);
    //NSLog(@"animationRect defined");
    animationImages = [[UIImageView alloc] initWithFrame:animationRect];
    [self.view addSubview:animationImages];
    //NSLog(@"animationImages allocated, init'd");
    animationTimer = [NSTimer scheduledTimerWithTimeInterval:0.0357 target: self selector:@selector(blah) userInfo:nil repeats:YES];
    [animationImages setImage:[UIImage imageNamed:[NSString stringWithFormat:@"SCAN%d.jpg", animationFrame]]];
    //NSLog(@"animationTimer started");
    animationTimer = nil;
    //NSLog(@"animationTimer set to nil");
}

- (void)blah {
    if (animationFrame <= 336){
     animationFrame += 1;
     [animationImages setImage:[UIImage imageNamed:[NSString stringWithFormat:@"SCAN%d.jpg", animationFrame]]];
     NSLog(@"%d", animationFrame);
    }
    else {
     animationFrame = 1;
     NSLog(@"restart");
    }
}
Sneakyness