iPhone Game Development - Chris Craft [40]
Listing 3.3
Code Used to Initialize the Display and Load Current Level
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]){
for (int i=0; i<25; i++) tiles[i]=nil;
currentLevelIndex =[Game getCurrentLevelIndex];
}
return self;
}
-(void)loadLevel:(int)levelIndex {
currentLevelIndex = levelIndex;
[Game setCurrentLevelIndex:levelIndex];
[menuViewController.view removeFromSuperview];
[self clearTiles];
currentLevel = [Game getLevelAtLevelIndex:levelIndex];
for (int i=0 ; i<(currentLevel.gridSize*currentLevel.gridSize)-1; i++) {
Tile tile = currentLevel.tiles[i]; //[currentLevel getTileAtIndex:i];
TileView *tileView = [[TileView alloc] initWithIndex:i
atLocation:tile.location withSize:currentLevel.tileSize
withDimension:currentLevel.gridSize withType:tile.tileType];
tiles[i] = tileView;
[self.view addSubview:tiles[i]];
}
emptyTile = currentLevel.gridSize*currentLevel.gridSize-1;
}
- (void)viewDidLoad {
[super viewDidLoad];
menuViewController = [[MenuViewController alloc] initWithNibName:
@”MenuView” bundle:nil];
menuViewController.delegate = self;
[self.view addSubview:menuViewController.view];
}
Responding to touches
touchesMoved is a key method of the MainViewController. As discussed earlier in the example we reviewed, this event is fired whenever one or more touch gestures have moved. When this happens we locate the tile (if any) that the touch is inside of. If the tile can be moved, we allow it to move as the location of the touch moves. We determine if the tile can be moved by checking to see if it is adjacent to the empty tile. Finally, we restrict the movement of the tile in order to keep it inside an allowed region. This region is calculated by union of the original location rectangle of the tile in motion with the rectangle of the empty tile (Listing 3.4).
Listing 3.4
Code Used to Move a Tile from Its Current Tile to an Empty Cell
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
for (int i=0 ; i<(currentLevel.gridSize*currentLevel.gridSize)-1; i++) {
if ([touch view] ==tiles[i]) {
if ([self tileCanMoveToIndexFromIndex:tiles[i].location]) {
CGPoint location = [touch locationInView:self.view];
CGFloat maxX, minX, minY, maxY;
CGRect movingTileRect = [TileView
getRectForLocation:tiles[i].location
withDimension:currentLevel.gridSize
withSize:currentLevel.tileSize];
CGRect emptyTileRect = [TileView getRectForLocation:emptyTile
withDimension:currentLevel.gridSize
withSize:currentLevel.tileSize];
CGRect slideRect = CGRectUnion(movingTileRect, emptyTileRect);
CGFloat centerPadding = (currentLevel.tileSize) / 2;
minX = slideRect.origin.x + centerPadding;
minY = slideRect.origin.y + centerPadding;
maxX = slideRect.origin.x + slideRect.size.width - centerPadding;
maxY = slideRect.origin.y + slideRect.size.height - centerPadding;
if (location.x > maxX)
location.x = maxX;
if (location.y > maxY)
location.y = maxY;
if (location.y < minY)
location.y = minY;
if (location.x < minX)
location.x = minX;
tiles[i].center = location;
return;
}
}
}
}
Once again, as discussed in the earlier example, the touchesEnded event fires whenever a player lifts his finger off the glass at the conclusion of a touch gesture. When this happens we check to see if the touch is inside of any of our tiles that can move as we did in the previous listing. If the touch is in a legal tile, we check to see if the center of the tile that the touch is inside of is contained in the original tile location or in the empty tile location. We then animate the tile to the appropriate location and update the location property of the tile and the emptyTile field of the MainViewController. This ensures that the tile is always in a legal location and gives the player the feeling that it snaps