Today I present a rough prototype of our Minesweeper project. It incorporates the rendering techniques we’ve been experimenting with over the past few posts, and includes some (partial) game logic. At this point, you can only move around the playfield and uncover cells, but the demo illustrates the basic mechanics of the program.
Demo
You can download the latest demo here. The interface to reach a puzzle is a little strange: Tap the “+” button on the main screen to add a row to the table, then tap that row to bring up a puzzle. (Hopefully, this design will make more sense in a day or two.)
Touches
I took a shortcut to make the game respond to touches: I copied the approach (and, indeed, the code) from one of AAPL’s “ScrollViewSuite” demos. I set the content
view inside our UIScrollView
to be a TapDetectingView
.
You can view the declaration and definition of TapDetectingView
on AAPL’s site, or in the complete project.
Game Logic
Most of the “game logic” implemented so far is found in a single Playfield
method:
- (void)tapDetectingView:(TapDetectingView*)tdView gotSingleTapAtPoint:(CGPoint)tapPoint
{
if (![self cellForPoint:&tapPoint]) return;
NSLog(@"Tap at (%.1f, %.1f)", tapPoint.x, tapPoint.y);
[puzzle revealCell:tapPoint];
UIView* tv = [content viewWithTag:(TAG_BASE + puzzle.w*tapPoint.y + tapPoint.x)];
tv.layer.contents = (id) [[self imageForCell:tapPoint] CGImage];
}
(Note that I take advantage of the 1-to-1 correspondence between cells and tiles to cheaply figure out which parts of the UI need to be redrawn.)
Here are two of the more interesting helper functions:
- (BOOL)cellForPoint:(CGPoint*)point
{
if (!point) return FALSE;
CGPoint cell = CGPointMake(floorf(point->x/(cellSize.width*scale)),
floorf(point->y/(cellSize.height*scale)));
if ([puzzle isLegalCell:cell])
{
*point = cell;
return TRUE;
}
else
{
return FALSE;
}
}
- (UIImage*)imageForCell:(CGPoint)pos
{
if (![puzzle isRevealedCell:pos])
{
return [self.contents objectAtIndex:10];
}
else if ([puzzle isMinedCell:pos])
{
return [self.contents objectAtIndex:9];
}
else
{
return [self.contents objectAtIndex:[puzzle neighborsOfCell:pos]];
}
}
I do use some “magic numbers” when referencing the contents
array, but, well, “meh”.