進撃の贪食蛇 完整教程 by:zbycookie

第八节 游戏结束的判定

贪食蛇里GameOver的原因只有2种,1是蛇头碰到身体,2是蛇头碰到墙壁

我们在GameLayer.h里添加
成员

 bool ifgameover;

函数


bool OutofRange();
bool HeadCollideBody(Direction headdirec);
void GameOver();
void PauseGame();
void SetSnakeVisible(bool value);

先说OutofRange函数,代码如下

bool GameLayer::OutofRange(){
    Point po = head->getPosition();
    if (po.x < 0||po.x > visiblesize.width||po.y < 0||po.y > visiblesize.height) {
        return true;
    }
    return  false;
}


```

这个函数用来判断蛇头是否超出游戏区域。

接下来是HeadCollideBody,代码如下
bool GameLayer::HeadCollideBody(Direction headdirec){
    float x = head->getPosition().x;
    float y = head->getPosition().y;
    bool iscollide = false;
    switch (headdirec) {
        case up:
            y += 20;
            break;
        case down:
            y -= 20;
            break;
        case left:
            x -= 20;
            break;
        case right:
            x += 20;
            break;
        default:
            break;
    }
    Point headnextpos = Point (x,y);
    iscollide = ifCollideBody(headnextpos);
    return  iscollide;
}

```

这个函数是用来判断蛇头下一步移动的位置是否与身体相撞。

再下来是GameOver函数,代码如下
void GameLayer::GameOver(){
    PauseGame();
    SetSnakeVisible(false);
    playbutton->setPosition(Point(visiblesize.width/2,visiblesize.height/2-gameover->getContentSize().height));
    gameover->setVisible(true);
    ifgameover = true;
}


```

里面又用到了另外两个函数,PauseGame和SetSnakeVisible。
PauseGame函数的作用主要是用来停止游戏,代码如下
void GameLayer::PauseGame(){
    
    this->pause();
    SetSnakeVisible(false);
    playbutton->setVisible(true);
    
}


```

SetSnakeVisible就是用来显示或隐藏蛇和食物的,代码如下
void GameLayer::SetSnakeVisible(bool val){
    food->setVisible(val);
    head->getNode()->setVisible(val);
        for (int i =0; isetVisible(val);
        }
}

```

回到GameOver函数,为了美观,我们需要调整一下开始按钮的位置,因为我们还要在开始按钮上面显示“GameOver!”的label,接着将ifgameover设置为true。
最后将update函数改为下面这个样子
void GameLayer::update(float dt){
    if (!HeadCollideBody(head->getDirec()) && !OutofRange()) {
         MoveStep();
        if(ifGetFood()){
            AddBody();
            SetFood();
        }
        lastbodyposi = body.at(body.size()-1)->getPosition();
    }
    else{
        GameOver();
    }
}


```


第八节结束

第九节 游戏的暂停和恢复

我们往GameLayer.h里添加
函数

void StartGame();

StartGame主要是用来恢复游戏的,是playbutton的回调函数,先看代码

void GameLayer::StartGame(){
    if(!ifgameover){
        SetSnakeVisible(true);
        this->resume();
    playbutton->setVisible(false);
    }else{
        this->unscheduleAllSelectors();
        this->removeAllChildren();
        body.clear();
        this->init();
        
    }
}

```


游戏过程中,在两种情况下我们会去点击开始游戏按钮
第一种是人为的暂停,恢复游戏时就要恢复游戏暂停前的状态
第二种是GameOver了,我们需要重新开始游戏。

这里我们用到了上一节的ifgameover来判断具体是哪种情况。
注意,在init函数中我们要将ifgameover设置为false。
bool GameLayer::init(){
    bool bRect = false;
    
    do {
        ifgameover = false;
        SetApperance();
        SetSnake();
        SetFood();
        this->schedule(schedule_selector(GameLayer::update), 0.6);
        bRect = true;
    } while (0);
    
    return bRect;
}



```


第九节 结束

最终章 一个小bug的解决

在玩的过程中发现了一个小bug,如果方向切换的过快,就会造成HeadCollideBody的误判
解决方法如下

在GameLayer.h中添加一个成员

bool movedflag;

然后修改 SetDirection函数

void GameLayer::SetDirection(Ref* psender,Direction direc){
    Direction headdir = head->getDirec();
    if (movedflag && direc!= headdir) {
        switch (direc) {
            case up:
                if(headdir==left||headdir==right){
                    head->setDirec(up);
                }
                break;
            case down:
                if(headdir==left||headdir==right){
                    head->setDirec(down);
                }
                break;
            case left:
                if(headdir==up||headdir==down){
                    head->setDirec(left);
                }
                break;
            case right:
                if(headdir==up||headdir==down){
                    head->setDirec(right);
                }
                break;
            default:
                break;
        }
        movedflag = false;
    }else{
    
    }    
}


```


然后在MoveStep函数的第一行添加一行代码

```
movedflag = true;
```


解决!

 

哇你这个好都告诉写在哪个文件了,对我这种菜鸟来说太好了,不过这是ios的么?适用于android吗

楼主,我只能点32个赞!

太棒了!这个修改一下直接就可以商业化了。:801::801::801:

适用的哦,就是导出app的时候方式不一样

还想了好几个点子呢,有一个就是蛇的节点是有磁铁组成的分 N级和S级,食物产生的时候也有N级和S级之分,具体怎么用这个还没想好
嘛,这只是个开始啦~

您的文章已被推荐到CocoaChina首页热门文章精选,感谢您的分享。:14:

大赞,学习,学习!!

真详细啊,吓得我都趴地上了

学习了。。

感谢!非常详细!非常适合新手!

楼主能发个项目压缩包给我吗,你这个文件我打不开。476855582@qq.com 多谢给赞

新手学习下

新手用2.21,还是好多错误,完全改不来,难道真是智商捉急。

新手学习.+32.

楼主,我运行前两节,里面声明的变量,都报错“undeclared identifier”,崩溃中:10:

很详细的帖子,不过有个问题,你蛇身体移动是整条蛇的节点都往前移动一步吗?这样感觉效率很低。
可以试着每移动一步,只是蛇头往前走,然后蛇尾精灵替换原来蛇头的位置即可。

请问下,怎么往 init 函数中添加 SetApperance 和 SetSnake 函数啊?新手什么也不懂,莫见怪:964:

mark:10::10::10::10::10::10: