【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

原文地址:https://www.cnblogs.com/anjohnlv/p/3668692.html