iPhone Game Development - Chris Craft [39]
- (void)updateArrowPoint {
// if this tile in not an arrow never show it
if (tileType != arrow) return;
[self updateArrowPointToIndex:self.index fromIndex:self.location];
}
- (void)updateArrowPointToIndex:(int)toIndex fromIndex:(int)fromIndex {
// if the tile is in its home location then hide the arrow
if (toIndex == fromIndex){
[self.arrowView setHidden:true];
return;
}
[self.arrowView setHidden:false];
// calculate the angle
float angle = [self getArrowDirectionToIndex:toIndex fromIndex:fromIndex];
CATransform3D rotationTransform = CATransform3DIdentity;
rotationTransform = CATransform3DRotate(rotationTransform, angle, 0.0, 0.0,
1.0);
self.arrowView.layer.transform = rotationTransform;
}
The angle for the arrow is calculated in getArrowDirectionToIndex. We need to know what angle to point the arrow in. The “to” and “from” positions are calculations in grid coordinates. From there we have the information to calculate the rise and run. Finally, we use the atan2() function to derive the angle:
- (float)getArrowDirectionToIndex:(int)toIndex fromIndex:(int)fromIndex {
CGFloat toX = toIndex % dimension;
CGFloat toY = toIndex / dimension;
CGFloat fromX = fromIndex % dimension;
CGFloat fromY = fromIndex / dimension;
double rise = toY - fromY;
double run = toX - fromX;
float angle = atan2(rise, run);
return angle;
}
One last thing to take notice of: TileView defines three helper methods that calculate where to place a tile based on an index or location. This is needed because we frequently reference tiles based on their index in the tile array:
+ (CGRect)getRectForLocation:(int)aLocation withDimension:(int)aDimension
withSize:(int)aSize{
int x = [TileView getXForLocation:aLocation withDimension:aDimension];
int y = [TileView getYForLocation:aLocation withDimension:aDimension];
return CGRectMake(x*aSize+x, y*aSize+y, aSize, aSize);
}
+ (int)getXForLocation:(int)aLocation withDimension:(int)aDimension {
return aLocation % aDimension;
}
+ (int)getYForLocation:(int)aLocation withDimension:(int)aDimension {
return aLocation / aDimension;
}
Understanding the magic behind the MainViewController
The MainViewController or Game View is where the rest of the game logic resides. Here you will find the code that initializes the collection of tiles and positions them in the grid. The MainViewController receives touch events and translates these gestures into the expected behavior of the tiles.
In MainViewController.h you will find a concise definition for the MainViewController class. Here is a listing of the MainViewController interface:
@interface MainViewController : UIViewController int currentLevelIndex; Level currentLevel; int emptyTile; TileView *tiles[100]; MenuViewController *menuViewController; } -(void)loadLevel:(int)levelIndex; @end In the previous code segment, pay attention to the following items of interest: currentLevelIndex keeps track of the integer value of the current level the player is on. currentLevel is assigned to the active level structure. emptyTile contains the location index of where the empty tile currently resides. tiles[25] is the collection of pointers to the MainViewControllers tiles. Not all the tile pointers are used depending on the difficulty of the currently active level. menuViewController provides a reference for the active instance of our menu that we discussed earlier. Initializing the display In the initialization method initWithNibName we fill all the tile pointers with nil. Shortly you will see iterations that perform a nil check on this array. This step gives us