推箱子小游戏

以前做的小游戏,很多地方不足也不做修改了,比较有趣,用到了一点算法,所以摘过来放在这儿

  • GitHub地址:https://github.com/rayonCheng/PushTheBox_-.git
    推箱子.png
  • 和炸弹人游戏原理差不多,这个是在它之前写的,图上有游戏规则
  • 重点分析:根据深度优先搜索算法,得出人能否移动到指定的目标点(可以找出最优的路线,但无法有序的显示出来故删掉了)

下面展示全部代码和部分注解

ViewController.m文件中

#define rowCount 10 
// 每一行个数@interface ViewController ()

@property(nonatomic,strong)UICollectionView *collectView;
@property(nonatomic,strong)NSMutableArray *dataArray;
@property(nonatomic)CGPoint point;// 箱子所在的坐标位置    
@property(nonatomic)CGPoint personPoint;// 人所在的坐标位置
@property(nonatomic)CGPoint endPoint; // 出口
@property(nonatomic)CGPoint startPoint; // 入口
@property(nonatomic,strong)NSMutableArray *allArray;// 记录人经过的路线所有信息@property(nonatomic)NSInteger success; // 判断人是否走到了正确的路线上@end

ViewController.m文件中

@implementation ViewController

static NSString *const cellId = @"cellId";// collectView注册时的标识符

- (void)viewDidLoad {    
    [super viewDidLoad]
     // Do any additional setup after loading the view, typically from a nib.        

    [self layoutCollectionView];        // 游戏规则注释
UILabel *explainLabel = [[UILabel alloc]initWithFrame:CGRectMake(20, [UIScreen mainScreen].bounds.size.height - 150, [UIScreen mainScreen].bounds.size.width - 40, 100)];
  
    explainLabel.text = @"箱子推动的规则:\n点击非墙非箱子的地方,如果人可以移动过去则移动;点击箱子,如果人在箱子四周的一位距离则把箱子向人的相反方向推去(那个方向非墙),人跟着移动一步,人和箱子距离在1位以上则没法进行";
    explainLabel.numberOfLines = 0;    [explainLabel setFont:[UIFont systemFontOfSize:12]];
    [self.view addSubview:explainLabel];
    [self.view bringSubviewToFront:explainLabel];        // 箱子起始坐标 {1,2},人的起始坐标{0,2},出口是{9,7}    // 墙占位符为2,空地为0,箱子为3,人为1   
    self.point = CGPointMake(1, 2);
    self.personPoint = CGPointMake(0, 2);
    self.startPoint = CGPointMake(0, 2);
    self.endPoint = CGPointMake(9, 7);} // 重新开始

- (IBAction)refreshBtn:(id)sender {// 拉控件
//    if (_personPoint.x != _startPoint.x || _personPoint.y != _startPoint.y ) {
//        // 避免连续点击两次刷新按钮
//        [_dataArray replaceObjectAtIndex: _personPoint.y * 10 + _personPoint.x  withObject:@0];// 人曾经的位置变为空地//    }
//    if (_point.x != _startPoint.x + 1 || _point.y != _startPoint.y){
//        // 箱子有移动
//        [_dataArray replaceObjectAtIndex: _point.y * 10 + _point.x  withObject:@0];// 箱子曾经的位置//    }//    
//    [_dataArray replaceObjectAtIndex: _startPoint.y * 10 + _startPoint.x  withObject:@1];// 人现在的位置
//    [_dataArray replaceObjectAtIndex: _startPoint.y * 10 + _startPoint.x + 1  withObject:@3];// 箱子现在的位置

//PS:开始想的太复杂导致思路错了走歪了,但逻辑还是经得起推敲的    
self.dataArray = nil;// so easy   
 _point = CGPointMake(_startPoint.x + 1, _startPoint.y);    
_personPoint = _startPoint;// 任何箱子的点重新赋值

[self.collectView reloadData];
}

- (void)layoutCollectionView{    
if (!_collectView) {       
     
CustomViewFlowLayout *layout = [[CustomViewFlowLayout alloc]init];
        UICollectionView *collevtView = [[UICollectionView alloc]initWithFrame:self.view.bounds collectionViewLayout:layout];
        collevtView.backgroundColor = [UIColor whiteColor];
        collevtView.delegate = self;
        collevtView.dataSource = self;
        [self.view addSubview:collevtView];
        _collectView = collevtView;
                [_collectView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:cellId];// collectView注册    }
}
// delegate和datasource方法
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{    
if (self.dataArray.count % rowCount == 0) {       
 return self.dataArray.count / rowCount;    
}else   
     return self.dataArray.count / rowCount + 1;
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{    
return rowCount;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{    
UICollectionViewCell *collectCell = [collectionView dequeueReusableCellWithReuseIdentifier:cellId forIndexPath:indexPath];// 重用机制,上面别忘了注册
    NSInteger inter = (indexPath.section) * rowCount + indexPath.row;
        if ([self.dataArray[inter] isEqualToNumber:@2]) {      
  collectCell.backgroundColor = [UIColor blackColor];
    }   
 if ([self.dataArray[inter] isEqualToNumber:@0]) {        
collectCell.backgroundColor = [UIColor groupTableViewBackgroundColor];
    }   
 if (indexPath.row == self.point.x && indexPath.section == self.point.y) {        
collectCell.backgroundColor = [UIColor redColor];    
}// 代表箱子
    if ([self.dataArray[inter] isEqualToNumber:@1]) { 
       collectCell.backgroundColor = [UIColor greenColor];    
}// 代表人 
   return collectCell;
}
/* 箱子推动的规则:    点击非墙非箱子的地方,如果人可以移动过去则移动;     点击箱子,如果人在箱子四周的一位距离则把箱子向人的相反方向推去(那个方向非墙),人跟着移动一步,人和箱子距离在1位以上则没法进行 */

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{    
NSIndexPath *path = [NSIndexPath indexPathForRow:_personPoint.x inSection:_personPoint.y];
        if (indexPath.row == self.point.x && indexPath.section == self.point.y) {        // 点击了箱子
                if (indexPath.row - 1 == self.personPoint.x && indexPath.section == self.personPoint.y && [_dataArray[indexPath.section * rowCount + indexPath.row + 1] isEqualToNumber:@0]) {
            // 人在箱子左边一位,人和箱子向右移动一位
            _personPoint = CGPointMake(indexPath.row, indexPath.section);
            _point = CGPointMake(indexPath.row + 1, indexPath.section);
                        NSInteger inter = indexPath.section * 10 + indexPath.row;
            [_dataArray replaceObjectAtIndex: (NSUInteger)inter  withObject:@1];// 人现在的位置
            [_dataArray replaceObjectAtIndex: (NSUInteger)inter - 1  withObject:@0];// 人曾经的位置变为空地
            [_dataArray replaceObjectAtIndex: (NSUInteger)inter + 1  withObject:@3];// 箱子现在的位置
            [self.collectView reloadItemsAtIndexPaths:@[indexPath,path,
[NSIndexPath indexPathForRow:_point.x inSection:_point.y] ]]; 
           }       
 if (indexPath.row + 1 == self.personPoint.x && indexPath.section == self.personPoint.y &&  [_dataArray[indexPath.section * rowCount + indexPath.row - 1] isEqualToNumber:@0]) {    // 人在箱子右边一位,人和箱子向左移动一位
            _personPoint = CGPointMake(indexPath.row, indexPath.section);
            _point = CGPointMake(indexPath.row - 1, indexPath.section);
     NSInteger inter = indexPath.section * 10 + indexPath.row;
            [_dataArray replaceObjectAtIndex: (NSUInteger)inter  withObject:@1];// 人现在的位置
            [_dataArray replaceObjectAtIndex: (NSUInteger)inter + 1  withObject:@0];// 人曾经的位置变为空地
            [_dataArray replaceObjectAtIndex: (NSUInteger)inter - 1  withObject:@3];// 箱子现在的位置
            [self.collectView reloadItemsAtIndexPaths:@[indexPath,path,
[NSIndexPath indexPathForRow:_point.x inSection:_point.y] ]]; 
                   }        
if (indexPath.row  == self.personPoint.x && indexPath.section - 1 == self.personPoint.y &&  [_dataArray[(indexPath.section + 1) * rowCount + indexPath.row] isEqualToNumber:@0]) {    // 人在箱子上边一位,人和箱子向下移动一位
            _personPoint = CGPointMake(indexPath.row, indexPath.section);
            _point = CGPointMake(indexPath.row , indexPath.section + 1);
           NSInteger inter = indexPath.section * 10 + indexPath.row;
            [_dataArray replaceObjectAtIndex: (NSUInteger)inter withObject:@1];// 人现在的位置
            [_dataArray replaceObjectAtIndex: (NSUInteger)inter - 10  withObject:@0];// 人曾经的位置变为空地
            [_dataArray replaceObjectAtIndex: (NSUInteger)inter + 10  withObject:@3];// 箱子现在的位置
            [self.collectView reloadItemsAtIndexPaths:@[indexPath,path,
[NSIndexPath indexPathForRow:_point.x inSection:_point.y] ]];                    }   
     if (indexPath.row == self.personPoint.x && indexPath.section + 1 == self.personPoint.y && [_dataArray[(indexPath.section - 1) * rowCount + indexPath.row] isEqualToNumber:@0]) {            // 人在箱子下边一位,人和箱子向上移动一位
            _personPoint = CGPointMake(indexPath.row, indexPath.section);
            _point = CGPointMake(indexPath.row, indexPath.section - 1);
                        NSInteger inter = indexPath.section * 10 + indexPath.row;
            [_dataArray replaceObjectAtIndex: (NSUInteger)inter  withObject:@1];// 人现在的位置
            [_dataArray replaceObjectAtIndex: (NSUInteger)inter + 10  withObject:@0];// 人曾经的位置变为空地
            [_dataArray replaceObjectAtIndex: (NSUInteger)inter - 10  withObject:@3];// 箱子现在的位置
            [self.collectView reloadItemsAtIndexPaths:@[indexPath,path,
[NSIndexPath indexPathForRow:_point.x inSection:_point.y] ]]; 
                   }           
 }else if (_personPoint.x == indexPath.row && _personPoint.y == indexPath.section){        // 点了人自身,不做任何变化
            }else  if (
![_dataArray[(indexPath.section) * rowCount + indexPath.row] isEqualToNumber:@2]) {        // 点击的地方不是墙且能够有路线达到那儿(不一定是最优方案--暂时先这样)       
 [self.allArray removeAllObjects];        
self.success = 0;
        NSInteger success = [self judgeTwoPointRouteWithStartPiontX:(NSInteger)_personPoint.x y:(NSInteger)_personPoint.y endPointX:(indexPath.row) y:(indexPath.section)];
                if (success == 1) {         
   [self.dataArray enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {   
             if ([obj isEqualToNumber:@1]) {                 
   //                    [self.allArray addObject:obj];
//                    NSIndexPath *path1 = [NSIndexPath indexPathForRow:( idx / rowCount) inSection:(idx % rowCount) ];
                    //                    NSLog(@"= %@",obj);
//                    [self.collectView reloadItemsAtIndexPaths:@[path1]];
                    [_dataArray replaceObjectAtIndex: (NSUInteger)idx  withObject:@0];// 人曾经的位置变为空地                
}
            }];     
                   NSInteger inter = indexPath.section * 10 + indexPath.row;
            [_dataArray replaceObjectAtIndex: (NSUInteger)inter  withObject:@1];// 人现在的位置
            self.personPoint = CGPointMake(indexPath.row, indexPath.section);
            [self.collectView reloadItemsAtIndexPaths:@[indexPath,path]];
        }    
}    
if (_point.x == _endPoint.x && _point.y == _endPoint.y) {        NSLog(@"过关啦");
        UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"恭喜" message:@"过关了" preferredStyle:(UIAlertControllerStyleAlert)];// 比alertView好用且齐全
        UIAlertAction *action = [UIAlertAction actionWithTitle:@"确定" style:(UIAlertActionStyleCancel) handler:^(UIAlertAction * _Nonnull action) {
//            [_dataArray replaceObjectAtIndex: _startPoint.y * 10 + _startPoint.x  withObject:@1];// 人现在的位置
//            [_dataArray replaceObjectAtIndex: _personPoint.y * 10 + _personPoint.x  withObject:@0];// 人曾经的位置变为空地
//            [_dataArray replaceObjectAtIndex: _startPoint.y * 10 + _startPoint.x + 1  withObject:@3];// 箱子现在的位置
//            [_dataArray replaceObjectAtIndex: _point.y * 10 + _point.x  withObject:@0];// 箱子曾经的位置// 和重新按钮 那一块同理
            self.dataArray = nil;            
_point = CGPointMake(1, 2);
            _personPoint = CGPointMake(0, 2);
            [self.collectView reloadData];        
}];
        [alertController addAction:action];
        [self presentViewController:alertController animated:YES completion:nil];   
 }
    }// 输入起始点和结束点,判断这两点在地图内有没有连通的路线?有几条?

// 详解可看上一篇文章(炸弹人游戏),只是将BOOL值替换成了nsinteger- (NSInteger )judgeTwoPointRouteWithStartPiontX:(NSInteger)startX y:(NSInteger)startY endPointX:(NSInteger)endX y:(NSInteger)endY{    NSInteger inter = startY * rowCount + startX;
    [_dataArray replaceObjectAtIndex: (NSUInteger)inter  withObject:@1];// 人走过的路线
        if (startX == endX && startY == endY) {    
    self.success = 1;        
//        for (int i = 0; i < _dataArray.count; i ++) {
//            if ([_dataArray[i] isEqualToNumber:@1]) {
//                // 记录走过的每一个点
//                [self.allArray addObject:
[NSNumber numberWithInt:i]];//                //       
     }//      
  }    
}        // 上下左右四个方向是否能移动
    if (_success != 1 && [_dataArray[startX + (startY - 1) * rowCount] isEqualToNumber:@0]) {        
[self judgeTwoPointRouteWithStartPiontX:startX y:(startY - 1) endPointX:endX y:endY];
    }    
if (_success != 1 && [_dataArray[startX + (startY + 1) * rowCount] isEqualToNumber:@0]) {    
    [self judgeTwoPointRouteWithStartPiontX:startX y:(startY + 1) endPointX:endX y:endY];
    }   
 if (_success != 1 && [_dataArray[startX - 1 + (startY ) * rowCount] isEqualToNumber:@0]) {   
     [self judgeTwoPointRouteWithStartPiontX:(startX - 1) y:(startY) endPointX:endX y:endY];
    }   
 if (_success != 1 && [_dataArray[startX + 1 + (startY ) * rowCount] isEqualToNumber:@0]) {   
     [self judgeTwoPointRouteWithStartPiontX:(startX + 1) y:(startY) endPointX:endX y:endY];
    }   
 if (_success != 1) {   
     [_dataArray replaceObjectAtIndex: (NSUInteger)inter  withObject:@0]; 
   }   
 return _success;}

#pragram mark ----getter
- (NSMutableArray *)dataArray{   
 if (!_dataArray) {    
    _dataArray = [NSMutableArray arrayWithArray:@[@2,@2,@2,@2,@2,@2,@2,@2,@2,@2,  @2,@0,@0,@0,@0,@0,@0,@0,@0,@2,  @1,@3,@0,@2,@2,@0,@2,@2,@0,@2,  @2,@0,@0,@2,@0,@0,@2,@0,@0,@2,@2,@0,@0,@2,@0,@2,@0,@2,@0,@2,@2,@0,@0,@0,@0,@0,@0,@2,@0,@2,@2,@0,@0,@2,@2,@2,@0,@2,@2,@2,@2,@0,@0,@0,@0,@0,@0,@0,@0,@0,@2,@2,@2,@2,@2,@2,@2,@2,@2,@2] ];   
 }       
 return _dataArray;
}

- (NSMutableArray *)allArray{ 
   if (!_allArray) {   
     _allArray = [NSMutableArray arrayWithCapacity:20];  
  }
    return _allArray;
}

此工程先于炸弹人编写,逻辑不如其严谨,可两者结合比较,更好的理解

  • PS:文章排版有问题,以前是富文本格式,现在转换为markdown格式,改的头疼

你可能感兴趣的:(推箱子小游戏)