After the great feedback on my previous thread, I thought I'd ask for input on my implementation of an infinite, randomly generated tilemap which scrolls horizontally. My player entity moves at a constant velocity while the level essentially move around him.
Here's how I'm approaching the problem. You'll find my questions below!
1) I have a Map class, which is essentially a subclass of SPSprite. It acts as a container for the tiles I load later, and is 'scrolled' like so:
- (void)onEnterFrame:(SPEnterFrameEvent *)event
{
self.x -= event.passedTime * scrollVelocity;
}
2) I have a Tile class which subclasses SPMovieClip to allow for animated tiles, where applicable. Rather than truly randomly generate terrain, my Map class chooses from a selection of NSMutableArrays which contain level 'chunks'. These chunks act like puzzle pieces and are added to the end of the existing tilemap (essentially allowing the map to scroll infinitely, with a random string of 'chunks' forming the terrain).
To give you an idea of how these chunks are loaded into the Map container:
NSInteger width = [[chunk valueForKey:@"width"] intValue];
NSInteger height = [[chunk valueForKey:@"height"] intValue];
for(int x = 0; x < width; x++)
{
for(int y = 0; y < height; y++)
{
NSString *tileId = nil;
if(tileId = [[chunk valueForKey:@"terrain"] objectAtIndex:(x + (y * width))])
{
if([tileId intValue])
{
NSString *tileTexturePrefix = [NSString stringWithFormat:@"tile%d", [tileId intValue]];
Tile *tile = [[Tile alloc] initWithFrames:[[mapManager mTextureAtlas] texturesStartingWith:tileTexturePrefix] fps:12];
tile.x = chunkOffsetX + (x * kMapTileWidth);
tile.y = chunkOffsetY + (y * kMapTileHeight);
[self addChild:tile];
[tile release];
}
}
}
}
chunkOffsetX += width * kMapTileWidth;
3) Here's where I run into difficulty. Ideally, as there is no way for my player to travel backwards, I wish to remove Tile objects from my Map container when they scroll off of the left of the screen. To do this, I register an event for each Tile object:
- (void)onEnterFrame:(SPEnterFrameEvent *)event
{
if((self.x + self.width) < 0)
{
NSLog(@"Removing Tile entity from container");
[self removeFromParent];
[self release];
}
}
Unfortunately, removing the Tile class in this manner results in a crash: Collection <Map: 0x56842a0> was mutated while being enumerated.
My questions are as follows:
1) What's the best way to efficiently handle removing Tile (SPSprite) instances after they have left the screen?
2) Will my Tile class coordinate values (x, y) report their position in screen space, or relative to their parent container? As you've seen, I'm currently scrolling the container. So Tile objects placed at (50,0) could actually be off screen if the container has a position of (-500,0).
3) Is this the best way to go about this? I'm conscious of performance issues, so any suggestions would be greatly appreciated.