你的浏览器禁用了JavaScript, 请开启后刷新浏览器获得更好的体验!
首页
热门
推荐
精选
登录
|
注册
iOS 扫雷游戏
立即下载
用AI写一个
金额:
1
元
支付方式:
友情提醒:源码购买后不支持退换货
立即支付
我要免费下载
发布时间:2017-08-18
45人
|
浏览:6770次
|
收藏
|
分享
技术:C + OC
运行环境:macOS + Xcode
概述
本文主要讲解了用Obj-C 实现简单扫雷小游戏的思路和详细过程。看了会后悔,不看更后悔!
详细
###1、项目结构图 ![mineframe] > `Viewcontroller`:扫雷逻辑代码 > `LevelModel`:扫雷难度选择代码 ###2、定义 相信很多人小时候都玩过Windows XP系统的扫雷游戏。记得刚开始玩时不知道游戏规则,以为全靠运气,点到白色区域就是没有地雷,高兴地又蒙对了。后来发现了其中的奥秘,原来白色块代表周围都没有地雷,数字块代表其周围有几块地雷。根据这个规则我们开始扫雷游戏的实现: *以下以10×10地图为例进行分析* 1)用数组`mineMapArray`(0 - 9)存储每个单元的状态,初始化全为0 > 0,表示单元周围没有地雷 > 1 - 8,表示单元周围有1 - 8个地雷 > 9,表示该单元是地雷 >单元的周围是指,当前单元的左上方、上方、右上方、右方、右下方、下方、左下方、左方的单元。一个单元周围最多有8个单元。 2)用数组`minesArray`(0 - 99)存储所有地雷的位置 3)用数组`turnoverArray`(0 - 99)存储点击空白单元时可翻转所有单元的位置 ###3、随机地雷的位置 1)先创建临时地图位置数组`tmpMapArray`(0 - 99),方便下一步随机`_mineNums`个地雷位置用 ``` //1.创建临时地图位置数组,用于随机出地雷位置 NSMutableArray *tmpMapArray = [NSMutableArray array];//临时地图位置数组 for (int i = 0; i < _row * _column; i++) { [tmpMapArray addObject:@(i)]; } ``` 2)随机产生`_mineNums`个地雷并记录地雷位置到地图相应`mineMapArray`上 > `delIndex`,临时地图数组`tmpMapArray`的删除的位置 > `addIndex `,地雷地图数组`minesArray`上添加地雷的位置 ``` //2.更新地图地雷位置和记录地雷位置 int delIndex;//随机地雷的位置 int addIndex;//地雷添加到地图的位置 for (int i = 0; i < _mineNums; i++) { delIndex = arc4random() % tmpMapArray.count; addIndex = [tmpMapArray[delIndex] intValue]; [self.mineMapArray replaceObjectAtIndex:addIndex withObject:@(9)];//更地图上地雷位置 [self.minesArray addObject:tmpMapArray[delIndex]];//添加地雷位置到存储所有地雷位置的数组 [tmpMapArray removeObjectAtIndex:delIndex];//删除临时随机的地雷位置 } ``` 3)计算每个不是地雷的单元的周围地雷数量 一般情况下地雷的数量比较少,所以,首先我们可以遍历找到地雷单元,然后再遍历地雷周围的单元,再在`mineMapArray`数组相应位置上加1。 ![10×10][location] > 地雷的位置是`location`,`_row`是行数, `_column`是列数,即一行单元的个数 > 所以, > 左上 = `location - _column - 1` > 上 = `location - _column` > 右上 = `location - _column + 1` > 右 = `location + 1` > 右下 = `location + _column + 1` > 下 = `location + _column` > 左下 = ` location + _column - 1` > 左 = `location - 1` > > **注意**:在遍历周围单元是要注意是否在边界位置 > `location / _column != 0` 判断当前单元是否在第一行 > `location % _column != 0` 判断当前单元是否在第一列 > `location / _column != _row - 1` 判断当前单元是否在最后一行 > `location % _column != _column - 1` 判断当前单元是否在最后一列 > > 左上单元,需要判断当前单元是否在第一行&&是否在第一列 > 上单元,需要判断当前单元是否在第一行 > 右上单元,需要判断当前单元是否在第一行&&是否在最后一列 > 右单元,需要判断当前单元是否在最后一列 > 右下单元,需要判断当前单元是否在最后一行&&最后一列 > 下单元,需要判断当前单元是否在最后一行 > 左下单元,需要判断当前单元是否在最后一行&&第一列 > 左单元,需要判断当前单元是否在第一列 ``` //3.标记地雷周围数字 for (NSNumber *obj in self.minesArray) {//找到地雷周围位置,标记数值加1 NSInteger location = [obj integerValue]; NSInteger aroundLocation;//遍历地雷周围8个位置 //location / _column != 0 判断是否在第一行 //location % _column != 0 判断是否在第一列 //location / _column != _row - 1 判断是否在最后一行 //location % _column != _column - 1 判断是否在最后一列 // aroundLocation = location - _column;//上 if (location / _column != 0) { [self locationPlus:aroundLocation]; } aroundLocation = location - _column + 1;//右上 if (location / _column && location % _column != _column - 1) { [self locationPlus:aroundLocation]; } aroundLocation = location + 1;//右 if (location % _column != _column - 1) { [self locationPlus:aroundLocation]; } aroundLocation = location + _column + 1;//右下 if (location % _column != _column - 1 && location / _column != _row - 1) { [self locationPlus:aroundLocation]; } aroundLocation = location + _column;//下 if (location / _column != _row - 1) { [self locationPlus:aroundLocation]; } aroundLocation = location + _column - 1;//左下 if (location / _column != _row - 1 && location % _column != 0) { [self locationPlus:aroundLocation]; } aroundLocation = location - 1;//左 if (location % _column != 0) { [self locationPlus:aroundLocation]; } aroundLocation = location - _column - 1;//左上 if (location / _column != 0 && location % _column != 0) { [self locationPlus:aroundLocation]; } } ``` ``` - (void)locationPlus:(NSInteger)location { NSInteger cellMineNums = [[self.mineMapArray objectAtIndex:location] integerValue]; if (cellMineNums != 9) { cellMineNums++; } [self.mineMapArray replaceObjectAtIndex:location withObject:@(cellMineNums)]; } ``` ###4、初始化地图 代码: ``` /** * 初始化地图 */ - (void)setupMapView { for (int i = 0; i < _row * _column; i++) { UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; button.tag = kTag + i; //设置frame CGRect screenBounds = [UIScreen mainScreen].bounds; CGFloat buttonW = (screenBounds.size.width - kBorderX * 2 - (_column - 1) * kGap) / _column; CGFloat buttonH = buttonW; CGFloat buttonX = (i % _column) * (buttonW + kGap) + kBorderX; CGFloat buttonY = (i / _column) * (buttonH + kGap) + kBorderX; button.frame = CGRectMake(buttonX, buttonY, buttonW, buttonH); button.backgroundColor = [UIColor grayColor]; [button setBackgroundImage:[UIImage imageNamed:[NSString stringWithFormat:@"selected_%@", self.mineMapArray[i]]] forState:UIControlStateSelected]; [button setBackgroundImage:[UIImage imageNamed:@"selected_bg"] forState:UIControlStateNormal]; [button addTarget:self action:@selector(cellButtonSelect:) forControlEvents:UIControlEventTouchUpInside]; UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(markMine:)]; [button addGestureRecognizer:longPress]; [self.bgView addSubview:button]; } } ``` 随机地雷位置数组: ``` [0, 0, 0, 1, 9, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 2, 9, 0, 0, 0, 0, 0, 0, 1, 9, 4, 3, 0, 0, 0, 1, 2, 3, 3, 3, 9, 9, 0, 1, 1, 2, 9, 9, 9, 2, 2, 2, 0, 2, 9, 4, 4, 4, 3, 1, 0, 0, 0, 2, 9, 9, 2, 9, 2, 1, 1, 0, 0, 1, 2, 2, 2, 1, 2, 9, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 9, 1, 1, 9, 1, 0, 0, 0, 0, 0] ``` 地雷位置效果图: ![效果图][随机效果] ###5、扫雷逻辑 - 点击数字单元,数字单元翻过来 - 点击地雷单元,所有单元翻过来,游戏结束 - 点击空白单元,找出其周围“可翻转的单元”,并翻转过来 > “可翻转的单元”是指,如下图,当点击绿色区域内任意空白单元时绿色区域全部翻转过来 ![分析图][递归算法分析] ######下面是当点击黄点位置空白单元时,找到其周围可翻转的单元的思路和算法 ![递归遍历过程图][递归遍历过程图] **PS:偷偷地告诉你,例子包里有遍历流程。** 思路: ① 如果当前单元是空白单元,先把这个单元存到`turnoverArray`; ② 再依次判断这个单元的上、右上、右、右下、下、左下、左、左上单元 ③如果判断的单元是空白单元,则把判断的单元作为当前空白单元回到①;如果判断的单元是数字单元,则回到②依次进行判断; 核心算法: ``` - (void)findAllTurnover:(NSInteger)location { if (![self.turnoverArray containsObject:@(location)]) {//如果turnoverArray不包含这个单元,存进去 [self.turnoverArray addObject:@(location)]; } if ([self.mineMapArray[location] integerValue] != 0) {//如果当前单元不是空白单元则,回到上一层继续寻找下一个位置 return; } NSInteger aroundLocation; aroundLocation = location - _column - 1;//左上 if (location / _column != 0 && location % _column != 0) { [self addTurnover:aroundLocation]; } aroundLocation = location - _column;//上 if (location / _column != 0) { [self addTurnover:aroundLocation]; } aroundLocation = location - _column + 1;//右上 if (location / _column && location % _column != _column - 1) { [self addTurnover:aroundLocation]; } aroundLocation = location + 1;//右 if (location % _column != _column - 1) { [self addTurnover:aroundLocation]; } aroundLocation = location + _column + 1;//右下 if (location % _column != _column - 1 && location / _column != _column - 1) { [self addTurnover:aroundLocation]; } aroundLocation = location + _column;//下 if (location / _column != _column - 1) { [self addTurnover:aroundLocation]; } aroundLocation = location + _column - 1;//左下 if (location / _column != _column - 1 && location % _column != 0) { [self addTurnover:aroundLocation]; } aroundLocation = location - 1;//左 if (location % _column != 0) { [self addTurnover:aroundLocation]; } } - (void)addTurnover:(NSInteger)location { if ([self.turnoverArray containsObject:@(location)]) {//如果已经包含这个单元return return; } [self.turnoverArray addObject:@(location)]; [self findAllTurnover:location]; } ``` ###6、实现效果 ![demogif] ###7、颇多不足,望各位不吝赐教 - 有些细节没有说明白,欢迎留言讨论。 - 用递归遍历寻找空白单元周围可翻转单元时,时间复杂度太大。 - - - 最后,推荐一个画图标神器 [Sketch],还有一个图标素材搜索网站[easyicon]。我一般都是在[easyicon]上找素材,能用的直接用,需要改动的再在[Sketch]上修改。 另外,Mac自带的软件Keynote也很好用。本文中的图10×10,分析图和递归遍历过程图都是用Keynote制作的。 ###什么!玩得不过瘾?[来这儿!] [mineframe]:/contentImages/image/20170818/TUvd5XH1QVZxwE43dkm.png [demogif]:/contentImages/image/20170818/FIZhHq52QbopkuedvaL.gif [location]:http://upload-images.jianshu.io/upload_images/610137-dff00f795b057d03.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240 [随机效果]:http://upload-images.jianshu.io/upload_images/610137-042cef08fc08d785.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240 [递归算法分析]:http://upload-images.jianshu.io/upload_images/610137-3dcdcd94bd36da87.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240 [递归遍历过程图]:http://upload-images.jianshu.io/upload_images/610137-959a2ce64f9a817e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240 [Sketch]:https://www.sketchapp.com [easyicon]:http://www.easyicon.net [来这儿!]:https://mienfield.com
本实例支付的费用只是购买源码的费用,如有疑问欢迎在文末留言交流,如需作者在线代码指导、定制等,在作者开启付费服务后,可以点击“购买服务”进行实时联系,请知悉,谢谢
感谢
0
手机上随时阅读、收藏该文章 ?请扫下方二维码
相似例子推荐
评论
作者
mr.wendao
5
例子数量
171
帮助
0
感谢
评分详细
可运行:
4.5
分
代码质量:
4.5
分
文章描述详细:
4.5
分
代码注释:
4.5
分
综合:
4.5
分
作者例子
iOS 购物车动画
iOS 扫雷游戏
iOS 滑块拼图游戏(Puzzle8)
iOS 转盘动画效果实现
iOS 吸附悬浮按钮实现