zoukankan      html  css  js  c++  java
  • 【300行小游戏】一、推箱子

    最近略闲。本来学习学习cocos2dx,u3d神马的。但是为人太懒了,于是嚼了嚼老知识。写了点所谓的游戏自娱自乐。纯OC代码,仅仅实现了游戏主要内容。每个游戏限制在300行代码内(主要是为了代码可读性,不然可以再压缩一半)。

    不多说。

    一、搬箱子。

    开始之前,我们要确定到底要做什么?做到什么程度?

    1、搬箱子必须的元素:小人,箱子,目标

    2、成功条件:目标全部被箱子占领

    3、失败条件:不设置

    4、具体细节,地图的大小(正矩形不超过9*9),小人的移动(可以往前进方向推动箱子以及穿越目标),箱子的移动(靠边不能移动),关卡的设置(第一关一个箱子,每关递增一个)等

    开始。(笔者再次声明:本人没做过游戏,这个只是写来自己玩的,如有误导,纯属坑爹)

    先贴出笔者自定义的常量和枚举类型,看面看不懂的可以回过头看看

    #define kCount_Grid 6    //地图大小-小于10
    #define kTotalRound 6    //关卡数
    #define kHero [UIColor yellowColor]
    #define kBox [UIColor blackColor]
    #define kDragon [UIColor redColor]
    #define kNormal [UIColor brownColor]
    
    typedef NS_ENUM(NSInteger, GridType) {
        GridTypeNormal = 0,
        GridTypeBox = 1,
        GridTypeHero = 2,
        GridTypeDragon = 3,
    };
    
    typedef NS_ENUM(NSInteger, MoveDirection) {
        MoveDirectionUp = 0,
        MoveDirectionDown = 1,
        MoveDirectionLeft = 2,
        MoveDirectionRight = 3,
    };

    首先,我们来绘制我们的游戏地图

    -(void)initMap
    {
        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:[UIColor brownColor]];
                [btn setTag:i+j*10];
                [vMap addSubview:btn];
            }
        }
    }
    

    如果是和笔者一样的菜鸟需注意一个细节,int i和int j是从1而非0开始的。

    然后初始化小人,箱子,和目标的位置(笔者YY成Hero,box,和Dragon)

    -(void)initHero
    {
        btnHero = [self randomPoint:GridTypeHero];
        [btnHero setBackgroundColor:kHero];
        [btnHero setSelected:YES];
    }
    
    -(void)initBox
    {
        for (int i=0; i<round; i++) {
            UIButton *btn = [self randomPoint:GridTypeBox];
            btn = [self checkRepeat:btn gridType:GridTypeBox];
            [btn setBackgroundColor:kBox];
            [btn setSelected:YES];
            [array_Box addObject:btn];
        }
    }
    
    -(void)initDragon
    {
        for (int i=0; i<round; i++) {
            UIButton *btn = [self randomPoint:GridTypeDragon];
            btn = [self checkRepeat:btn gridType:GridTypeDragon];
            [btn setBackgroundColor:kDragon];
            [btn setSelected:YES];
            [array_Dragon addObject:btn];
        }
    }
    

    位置的初始化笔者采用的随机位置,因为懒得画地图

    -(UIButton *)randomPoint:(GridType)type
    {
        int x = 1;
        int y = 1;
        if (type == GridTypeBox) {
            x = arc4random()%(kCount_Grid-2);
            y = arc4random()%(kCount_Grid-2);
            x++;
            y++;
        }else{
            x = arc4random()%kCount_Grid;
            y = arc4random()%kCount_Grid;
        }
        x++;
        y++;
        UIButton *btn = (UIButton *)[vMap viewWithTag:(x+y*10)];
        return btn;
    }

    当然,得查一下重。不能一开始,所有的随机都随机到一个位置上去了是吧

    此外,还应考虑到箱子的位置,不能初始化就靠再墙壁上。不然很容易就死局了。

    -(UIButton *)checkRepeat:(UIButton*)btn gridType:(GridType)type
    {
        if ([btn isSelected] == YES) {
            btn = [self randomPoint:type];
            return [self checkRepeat:btn gridType:type];
        }else{
            return btn;
        }
    }

    为了界面的简单,我抛弃了摆方向控制键的想法,全部用手势搞定

    -(void)initAction
    {
        UISwipeGestureRecognizer *recognizer;
        recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(goRight)];
        [recognizer setDirection:(UISwipeGestureRecognizerDirectionRight)];
        [[self view] addGestureRecognizer:recognizer];
        
        recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(goLeft)];
        [recognizer setDirection:(UISwipeGestureRecognizerDirectionLeft)];
        [[self view] addGestureRecognizer:recognizer];
        
        recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(goUp)];
        [recognizer setDirection:(UISwipeGestureRecognizerDirectionUp)];
        [[self view] addGestureRecognizer:recognizer];
        
        recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(goDown)];
        [recognizer setDirection:(UISwipeGestureRecognizerDirectionDown)];
        [[self view] addGestureRecognizer:recognizer];
    }
    

    这里暴露了笔者的菜鸟真相,顺便求一句,向之上的方法怎么传参啊?因为不知道如何传参,笔者多写了四个方法

    -(void)goUp
    {
        [self moveAction:btnHero direction:MoveDirectionUp];
    }
    
    -(void)goDown
    {
        [self moveAction:btnHero direction:MoveDirectionDown];
    }
    
    -(void)goLeft
    {
        [self moveAction:btnHero direction:MoveDirectionLeft];
    }
    
    -(void)goRight
    {
        [self moveAction:btnHero direction:MoveDirectionRight];
    }
    

    然后再调到真正想执行的方法

    -(BOOL)moveAction:(UIButton *)btn direction:(MoveDirection)direction
    {
        int tag = btn.tag;
        int x = tag%10;
        int y = tag/10;
        switch (direction) {
            case MoveDirectionUp:
            {
                if (y<2) return NO;
                return [self moveItem:btn tag:(x+(y-1)*10) direction:MoveDirectionUp];
                break;
            }
            case MoveDirectionDown:
            {
                if (y+1>kCount_Grid) return NO;
                return [self moveItem:btn tag:(x+(y+1)*10) direction:MoveDirectionDown];
                break;
            }
            case MoveDirectionLeft:
            {
                if (x<2) return NO;
                return [self moveItem:btn tag:((x-1)+y*10) direction:MoveDirectionLeft];
                break;
            }
            case MoveDirectionRight:
            {
                if (x+1>kCount_Grid) return NO;
                return [self moveItem:btn tag:((x+1)+y*10) direction:MoveDirectionRight];
                break;
            }
        }
        return NO;
    }

    稍微解释一下,方格游戏的移动,其实就是坐标的+1-1,在这里笔者偷懒使用tag作为坐标,个位数表示x轴,十位数表示y轴。所以地图大小不能超过9*9

    继续,具体的移动方法

    -(BOOL)moveItem:(UIButton *)btn tag:(int)tag direction:(MoveDirection)direction
    {
        UIButton *btnTarget = (UIButton*)[vMap viewWithTag:tag];
        if (btn == btnHero) {           //移动英雄
            if ([btnTarget isSelected] == YES) {
                if ([array_Box containsObject:btnTarget]) {
                    if ([self moveAction:btnTarget direction:direction] == NO) {
                        return NO;
                    }
                }
            }
            [btnHero setBackgroundColor:kNormal];
            [btnHero setSelected:NO];
            if ([array_Dragon containsObject:btnHero]) {
                [btnHero setBackgroundColor:kDragon];
                [btnHero setSelected:YES];
            }
            btnHero = btnTarget;
            [btnHero setBackgroundColor:kHero];
            [btnHero setSelected:YES];
        }else{                          //移动箱子
            [btn setBackgroundColor:kNormal];
            [btn setSelected:NO];
            [array_Box removeObject:btn];
            if ([array_Dragon containsObject:btn]) {
                count_Cover--;
            }
            [btnTarget setBackgroundColor:kBox];
            [btnTarget setSelected:YES];
            [array_Box addObject:btnTarget];
            if ([array_Dragon containsObject:btnTarget]) {
                count_Cover++;
            }
            if (count_Cover == round) {
                if (round >= kTotalRound) {
                    UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"通过所有关卡" message:nil delegate:self cancelButtonTitle:@"再玩一遍" otherButtonTitles:nil];
                    alert.tag = 100;
                    [alert show];
                }else{
                    UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"过关" message:nil delegate:self cancelButtonTitle:@"进入下一关" otherButtonTitles:nil];
                    alert.tag = 200;
                    [alert show];
                }
                
            }
        }
        return YES;
    }

    一切为了简单,所以笔者有些地方就纯粹用逻辑堆出来。

    于是呢、第一个小游戏基本上就竣工了……当然还存在些许BUG,比如从第四管开始,有可能会出现四个箱子随机恰好挨着组成一个大正方形,然后直接死局。不过随意吧,这只怪玩家人品不好了,不是吗?

    完整代码下载:Demo

  • 相关阅读:
    Mysql 修改默认端口
    通过.pro文件生成C++工程
    内联函数知识点
    DICOM文件添加私有Tag(DCMTK Private Tag)
    poj 1185 炮兵阵地 状压dp
    cf #216 C
    cdoj1365 木杆上的蚂蚁
    cf #214 Dima and Salad
    cf #213 Matrix
    hdu 2222 Keywords Search(AC自动机入门题)
  • 原文地址:https://www.cnblogs.com/anjohnlv/p/3668692.html
Copyright © 2011-2022 走看看