【300行小游戏】二、扫雷
废话不多说了。
二,推箱子
首先,仍然需要明确自己要做什么?做到什么程度?
1、扫雷的重要元素:有雷的格子,没雷的格子,小红旗(用于确认雷,但是手机没有右键一说,懒得整得很复杂,抛弃小红旗)
2、成功条件:除有雷的格子外,其他格子全部被翻开
3、失败条件:翻开有雷的格子
4、其他细节:地图的大小(同上个游戏),点击无雷格子的事件(若周围有雷,显示周围雷数;若周围没累,自动翻开周围格子,直至有雷),点击有雷格子事件(亮出所有雷的位置,报告失败,如果是第一次就点击到了有雷的格子,则重新埋雷后自动翻开格子,直至第一次非雷)等
开始。(笔者再次声明:本人没做过游戏,这个只是写来自己玩的,如有误导,纯属坑爹)
惯例先贴出笔者自定义的常量和枚举类型,看面看不懂的可以回过头看看
#define kCount_Grid 9 //地图大小-小于10 #define kColor_Mine [UIColor clearColor] #define kColor_Safe [UIColor grayColor] #define kColor_Normal [UIColor brownColor]
笔者的习惯是首先把地图绘制出來:
-(void)initMap
{
if (vMap) {
[vMap removeFromSuperview];
}
CGRect frame = self.view.frame;
CGFloat width_Grid = frame.size.width/kCount_Grid;
vMap = [[UIView alloc]initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.width)];
[vMap setCenter:CGPointMake(frame.size.width/2, frame.size.height/2)];
[self.view addSubview:vMap];
for (int i=1; i<kCount_Grid+1; i++) {
for (int j=1; j<kCount_Grid+1; j++) {
UIButton *btn = [[UIButton alloc]initWithFrame:CGRectMake((i-1)*width_Grid, (j-1)*width_Grid, width_Grid, width_Grid)];
btn.layer.borderWidth = 1;
btn.layer.borderColor = [[UIColor lightGrayColor]CGColor];
[btn setBackgroundColor:kColor_Normal];
[btn setTag:i+j*10];
[btn addTarget:self action:@selector(findSafe:) forControlEvents:UIControlEventTouchUpInside];
[vMap addSubview:btn];
}
}
}
由于都是方格游戏,所以笔者采用了上一个游戏的绘制方法,不多说。
然后我们来是埋雷
-(void)initMine
{
for (int i=0; i<countMine; i++) {
UIButton *btn = [self randomPoint];
btn = [self checkRepeat:btn];
[btn removeTarget:self action:@selector(findSafe:) forControlEvents:UIControlEventTouchUpInside];
[btn addTarget:self action:@selector(findMine:) forControlEvents:UIControlEventTouchUpInside];
[arrMine addObject:btn];
}
}
由于雷的位置是随机的,所以必须的一件事仍然是查重
-(UIButton *)checkRepeat:(UIButton*)btn
{
if ([arrMine containsObject:btn]) {
btn = [self randomPoint];
return [self checkRepeat:btn];
}else{
return btn;
}
}
-(UIButton *)randomPoint
{
int x = arc4random()%kCount_Grid;
int y = arc4random()%kCount_Grid;
x++;
y++;
return (UIButton *)[vMap viewWithTag:(x+y*10)];
}
埋完雷游戏就算初始化完了,接下来是游戏过程。
当我们点击一个格子的时候,如果是安全的,那么
-(void)isSafe:(UIButton *)btn
{
if ([btn isKindOfClass:[UIButton class]] == NO || [btn isSelected] == YES) {
return;
}
[btn setSelected:YES];
countSafe++;
if (countMine+countSafe == kCount_Grid*kCount_Grid) {
NSLog(@"Success");
[self alertSetSucceed];
}
[btn setBackgroundColor:kColor_Safe];
int tag = btn.tag;
int x = tag%10;
int y = tag/10;
NSMutableArray *nearGrid = [NSMutableArray new];
UIButton *btn1 = (UIButton *)[vMap viewWithTag:(x-1)+(y-1)*10];
UIButton *btn2 = (UIButton *)[vMap viewWithTag:x+(y-1)*10];
UIButton *btn3 = (UIButton *)[vMap viewWithTag:(x+1)+(y-1)*10];
UIButton *btn4 = (UIButton *)[vMap viewWithTag:(x-1)+y*10];
UIButton *btn5 = (UIButton *)[vMap viewWithTag:(x+1)+y*10];
UIButton *btn6 = (UIButton *)[vMap viewWithTag:(x-1)+(y+1)*10];
UIButton *btn7 = (UIButton *)[vMap viewWithTag:x+(y+1)*10];
UIButton *btn8 = (UIButton *)[vMap viewWithTag:(x+1)+(y+1)*10];
(btn1) ? ([nearGrid addObject:btn1]):(nil);
(btn2) ? ([nearGrid addObject:btn2]):(nil);
(btn3) ? ([nearGrid addObject:btn3]):(nil);
(btn4) ? ([nearGrid addObject:btn4]):(nil);
(btn5) ? ([nearGrid addObject:btn5]):(nil);
(btn6) ? ([nearGrid addObject:btn6]):(nil);
(btn7) ? ([nearGrid addObject:btn7]):(nil);
(btn8) ? ([nearGrid addObject:btn8]):(nil);
int i = [self getNearMineCount:nearGrid];
if (i != 0) {
NSString *count = [NSString stringWithFormat:@"%d",i];
[btn setTitle:count forState:UIControlStateNormal];
}else{
[self isSafe:btn1];
[self isSafe:btn2];
[self isSafe:btn3];
[self isSafe:btn4];
[self isSafe:btn5];
[self isSafe:btn6];
[self isSafe:btn7];
[self isSafe:btn8];
}
}
Selected是一个标识,表明这个格子被检查过了没。如果安全,再检查周围8个格子,如果有雷,则注明雷数。如果无雷,就依次检查周围的8个按钮是否有雷。注意边界检查。
检查雷数的方法:
-(int)getNearMineCount:(NSMutableArray *)nearGrid
{
int count = 0;
for (int i=0; i<[nearGrid count]; i++) {
UIButton *btn = nearGrid[i];
if (!btn) {
break;
}
if ([arrMine containsObject:btn]) {
count++;
}
}
return count;
}
如果点击的格子是雷,那直接把所有的雷区都标明出来,再提示一个失败就好了。
理论上是,但是:
有例外,按照和谐的、友好的、通常的玩法,点击的第一个格子无论如何不能是雷的。如果第一次就踩shit点到雷了呢?笔者的做法是把雷重埋一次,再自动去翻点击的格子,还是雷就再埋,直至不是雷为止。
-(void)findMine:(UIButton *)btn
{
if (countSafe == 0) {
[self reStart];
btn = (UIButton *)[vMap viewWithTag:btn.tag];
if ([arrMine containsObject:btn]) {
[self findMine:btn];
}else{
[self findSafe:btn];
}
return;
}
for (int i=0; i<[arrMine count]; i++) {
UIButton *mine = arrMine[i];
[self isMine:mine];
}
[self alertSetFailed];
}
-(void)isMine:(UIButton *)btn
{
[btn setBackgroundColor:kColor_Mine];
[btn setTitle:@"💢" forState:UIControlStateNormal];
}
再然后呢、扫雷基本上也没啥可做的了。当然还有一些细节我没说,比如成功或者失败后格子就不能再翻啦,比如雷设置时的数量啦等等,虽没说,但都做了。有兴趣的可以自己下载来看看。
ok,扫雷,竣工。
完整代码下载:Demo
啊
浙公网安备 33010602011771号