【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
啊