views:

53

answers:

1

It seems that none of these solutions eliminate the lag associated with rendering images onto the screen (whether from .png's or using CG).

There is a 28x16 grid of blocks that are each 16x16 pixels, and at some points in the game, about half of them need to change their image because of a state change. Having each block as a subview of the main view causes a lag when half of them need to individually change their image (either from .png's or using CG).

I tried having one "map" view with whose drawRect: method is:

CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClearRect(context, rect);

// width and height are defined as the width and height of the grid (28x16 for iPhone)
for (int x = 0; x < width; x++) {
    for (int y = 0; y < height; y++) {
        // states[] is an enum instance variable that holds the states of each block in the map (state determines image)
        if (states[(x * height) + y] == PXBlockStateEmpty) {
            CGContextSetFillColorWithColor(context, [UIColor colorWithRed:153.0/255.0 green:153.0/255.0 blue:153.0/255.0 alpha:0.5].CGColor);
            CGContextSetStrokeColorWithColor(context, [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.5].CGColor);
            CGContextAddRect(context, CGRectMake(x * 16, y * 16, 16, 16));
            CGContextDrawPath(context, kCGPathFillStroke);
        } else if (states[(x * height) + y] == PXBlockStateSolid || states[(x * height) + y] == PXBlockStateSolidEdge) {
            CGContextSetFillColorWithColor(context, [UIColor colorWithRed:0.0 green:0.0 blue:102.0/255.0 alpha:0.9].CGColor);
            CGContextSetStrokeColorWithColor(context, [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.5].CGColor);
            CGContextAddRect(context, CGRectMake(x * 16, y * 16, 16, 16));
            CGContextDrawPath(context, kCGPathFillStroke);
        } else if (states[(x * height) + y] == PXBlockStateBuilding) {
            CGContextSetFillColorWithColor(context, [UIColor colorWithRed:51.0/255.0 green:51.0/255.0 blue:51.0/255.0 alpha:0.5].CGColor);
            CGContextFillRect(context, CGRectMake(x * 16, y * 16, 16, 16));
        }
    }
}

So my solution was to call setNeedsDisplayInRect: on the map, passing the frame (a 16x16 rect) of the block whose state changed. Am I using setNeedsDisplayInRect: incorrectly, or is this just an inefficient way to do it?

Both options (one subview vs hundreds of subviews) lag the game for a bit when a lot of the board is filled with a different image, and the second solution in particular lags whenever ANY block's image needs to be updated.

Any ideas? Thank you for your help!

+1  A: 

Calling setNeedsDisplayInRect: affects the argument to drawRect: but is otherwise the same as setneedsDisplay. The rectangle drawRect: receives is the union of all dirty rectangles. If you only draw content that intersects that rectangle, leaving other content untouched, you may see a speed improvement. Judging from the code snippet above you draw every tile every time. Since it is a union, you might also track dirty tiles separately and only draw dirty tiles. In that case, call CGContextClearRect for individual tiles instead of clearing the whole context, unless they are all dirty.

CGContextAddRect adds a rectangle to a path that will be drawn. Since you draw the path at every loop without beginning a new path, you redraw areas as the loop progresses. It would probably be faster to use CGContextFillRect and CGContextStrokeRect instead of a path.

Making each tile a separate UIView incurs more overhead than drawing as a whole. You should be able to get better speed from this method once the kinks are worked out.

drawnonward
What is a "dirty rectangle"? I don't understand the first paragraph of your answer :(
Arseniy Banayev
http://developer.apple.com/mac/library/documentation/cocoa/conceptual/CocoaViewsGuide/Optimizing/Optimizing.htmlfigured it out! thanks for pointing me in the right direction, drawonward!
Arseniy Banayev