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

不好的地方请大家指出

第一节 开始界面的绘制

好了,我们正式开始贪食蛇的编码工作了,首先我们要绘制一个开始界面,再开始绘制之前我们先要设置一下游戏的分辨率和屏幕适配方式。
我们打开AppDelegate.cpp文件,在applicationDidFinishLaunching()函数中添加一行代码

glview->setDesignResolutionSize(480, 320, ResolutionPolicy::EXACT_FIT);

注意:在3.0里最后一个参数的写法和2.0的不一样哦!
记得是在glview创建完后添加的哦,简单的解释一下这个函数的参数,第一个和第二个参数代表的分别是游戏分辨率的宽度和高度,第3个表示的是屏幕适配方式,我们选择的是EXACT_FIT 关于屏幕适配的具体知识我就不说了,我贴一个网址,里面还介绍了cocos2dx里面几个尺寸的概念,讲的比较好。

Cocos2dx屏幕适配新解,网址 http://blog.csdn.net/cen616899547/article/details/9110749

好了,屏幕分辨率和适配方式设定完后,我们进入绘制的阶段,在开始界面我们要完成两样东西的绘制,一个是背景图,一个是开始游戏的按钮。我们打开PS绘制一张480X320的背景图和一个按钮(按钮大小自己可以随便定,别比背景大就行了)

上面2张图就是我画的背景和开始按钮了。有了素材之后我们打开HelloWorldScene.h。在里面添加3个成员和一个成员函数

 Sprite* background;
 MenuItemImage* playbutton;
 Menu* menu;
 void ChangeScene();


```


先提一点,MenuItemImage是我们的按钮,要使这个按钮能够使用,我们还需要一个Menu类。为什么呢,我后面会写到的。
接下来我们打开HelloWorldScene.cpp重写里面的init()函数。

bool HelloWorld::init()
{
    
    if ( !Layer::init() )
    {
        return false;
    }
    
    Size visibleSize = Director::getInstance()->getVisibleSize();
    //Point origin = Director::getInstance()->getVisibleOrigin();
    background = Sprite::create("StartScene.png");
    background->setPosition(Point(visibleSize.width/2,visibleSize.height/2));
    this->addChild(background);
    
    playbutton = MenuItemImage::create("PlayButton1.png","PlayButton2.png",CC_CALLBACK_0(HelloWorld::ChangeScene,this));
    playbutton ->setPosition(Point(visibleSize.width/2,visibleSize.height/2-1.5*playbutton->getContentSize().height));
    
    menu = Menu::create(playbutton,NULL);
    menu->setPosition(Point::ZERO);
    this->addChild(menu);
    
    return true;
}


```


这个函数是HelloWorldScene这个layer的初始化函数,我们在里面设置我们的背景和按钮。这里我们先获取屏幕的可视大小,然后将背景图设置在屏幕的中心。为什么不是设置在原点的位置呢,这里牵涉到一个锚点的概念,默认的锚点是在物体的中心的,关于锚点的概念,请戳  http://blog.csdn.net/xuguangsoft/article/details/8425623

然后我们设置我们的开始按钮,前两个参数分布是按钮未按下时显示的图片以及按钮被按下时显示的图片,注意,在creat函数中我们要定义我们的回调函数,什么是回调函数呢,回调函数就是当你点击这个按钮时,这个按钮会去执行你预先设置的某个函数,回调函数是可以传参数的,CC_CALLBACK是3.0的一个新元素,写法和2.x的不一样,具体用法呢,请继续戳
http://blog.sina.com.cn/s/blog_923fdd9b0101efl1.html

我们设置的回调函数是GameLayer类里的ChangeScene函数 (GameLayer这个类会在下节讲到),这个函数有什么用呢?不要急,下一节也会讲到的。
同样,设置按钮的位置,然后我们初始化menu对象,将开始按钮对象添加到menu中,然后设置menu的位置,我们将menu的位置设置在原点。记住,Menu里面的MenuItenImage类的位置是相对Menu的,即MenuItemImage在屏幕里的实际位置等于MenuItemImage的位置加上Menu的位置。然后将所有的对象用addChild函数都加到layer中去。
Ok,到这里我们已经完成了开始画面的绘制了,下一节我们要讲到场景(Scene)的切换。
我的开始画面是这样的,你们的呢?
 
 

这里再加一个我自己设计的Icon

  

未完。。。。

第二节 游戏场景的切换

这一节我们要实现的是游戏场景的切换,既然要切换场景,我们自然要再定义一个场景,先建立一个GameLayer类,让这个类继承自Layer类,因为继承自Layer类,我们自然要实现一些父类的函数,在GameLayer.h中添加下面的成员函数。


GameLayer(void);
 ~GameLayer(void);
virtual bool init();
CREATE_FUNC(GameLayer);
static Scene* GameScene();

然后先在GameLayer.cpp中实现init函数,init函数参照HelloWorldScene里的init函数

bool GameLayer::init(){
    if ( !Layer::init() ) {
        return false;
        //添加一张背景图,参考上一节代码
    }
    return true;
}


```


我们可以在init函数里添加一张另外的背景图,好在待会切换场景的时候看一下效果。

我们这一节关键的是实现static Scene* GameScene();这个函数,在GameLayer.cpp中实现GameScene这个函数。代码如下
Scene* GameLayer::GameScene(){
    Scene* gamescene = Scene::create();
    GameLayer* gamelayer = GameLayer::create();
    gamescene->addChild(gamelayer);
    return gamescene;
}


```


接着我们回到上一节的HelloWorldScene.cpp 实现ChangeScene函数

void HelloWorld::ChangeScene(){
    //log("Change");
    Director::getInstance()->replaceScene(TransitionProgressInOut::create(0.5f,GameLayer::GameScene()));
}


```

我在场景切换过程中用到了过渡动画


```
TransitionProgressInOut::create(0.5f,GameLayer::GameScene())
```


过渡动画的种类有很多种,大家可以依次试一下,找到自己喜欢的,如果不需要过渡动画的话,改成


```
Director::getInstance()->replaceScene(GameLayer::GameScene());
```


大家就可以运行一下试试场景切换了。

第二节结束

第三节 蛇的建立

这一节我们开始创建关于蛇的类了,先创建一个Snake类,让他继承Node类,为什么不是继承Sprite类呢,要问这里的原因嘛,
请戳http://www.cnblogs.com/anndaming/archive/2012/05/20/2510285.html

Snake.h的代码如下

#ifndef __Snake__Snake__
#define __Snake__Snake__

#include 

#include "cocos2d.h"

using namespace cocos2d;

class Snake : public Node{
    
private:
    Sprite* snakenode;
public:
    void setNode(Sprite* node);
    Sprite* getNode();
    CREATE_FUNC(Snake);
    virtual bool init();

};


#endif /* defined(__Snake__Snake__) */


```


Snake.cpp的代码如下
#include "Snake.h"

Sprite* Snake::getNode(){
    return this->snakenode;
}

void Snake::setNode(Sprite* node){
    this->snakenode = node;
    this->addChild(snakenode);
}

bool Snake::init(){
    return true;
}

```

先实现Snake的create函数,用宏定义CREATE_FUNC();来实现。
好了,我们在Snake里定义一个Sprite类,然后实现他的get和set函数。
我们完成Snake的类之后定义一个SnakeHead类,为什么要定义SnakeHead类呢?,头和身体不一样啊,当然要分开定义了。让SnakeHead类先继承Snake类。

SnakeHead.h代码如下
#ifndef __Snake__SnakeHead__
#define __Snake__SnakeHead__

#include 

#include "cocos2d.h"
#include "Snake.h"

USING_NS_CC;

enum Direction {
    up = 0,
  down = 1,
  left = 2,
 right = 3,
};

class SnakeHead : public Snake{
private:
    Direction direction;
public:
    CREATE_FUNC(SnakeHead);
    virtual bool init();
    SnakeHead();
    ~SnakeHead();
    void setDirec(Direction di);
    Direction getDirec();
    
};

#endif /* defined(__Snake__SnakeHead__) */


```


SnakeHead.cpp代码如下
#include "SnakeHead.h"

bool SnakeHead::init(){
    return true;
}

SnakeHead::SnakeHead(){
    this->direction = up;
}

SnakeHead::~SnakeHead(){
    
}

Direction SnakeHead::getDirec(){
    return this->direction;
}

void SnakeHead::setDirec(Direction di){
    this->direction = di;
}


```

注意到了吧,我们在SnakeHead类里要添加头的方向,即Direction成员,然后实现他的set和get函数,这样的话,通过Head里的Direction成员我们才能知道蛇头应该往哪移动。
好了继续,我们往GameLayer.h里添加两个成员

```

SnakeHead* head;
Vector body;

```

第一个嘛,自然就是蛇头啦,第二个是蛇的身体,贪食蛇中蛇的身体是由很多节点构成的,所以我们用Vector来存储身体节点,Vector的具体用法后面会说

第三节结束

第四节 游戏界面的绘制

其实这一节和第一节差不多,主要就是在GameLayer类中添加一些按钮。
注意先include一下上一节的SnakeHead.h
打开GameLayer.h 往里面加入
成员:


    Sprite* background;
    MenuItemImage* butup;
    MenuItemImage* butdown;
    MenuItemImage* butleft;
    MenuItemImage* butright;
    MenuItemImage* pausebutton;
    MenuItemImage* playbutton;
    Label* gameover;
    Size visiblesize;
    Menu* menu;

简单解释一下,第一个成员是游戏界面的背景,第二到第四个成员是控制上下左右方向的按钮,第五个和第六个成员是控制游戏暂停和游戏恢复的按钮,第七个成员是用来显示“GameOver!”这句话的,第八个成员是屏幕可视大小,最后一个成员嘛,你懂的。

继续往GameLayer.h里添加成员函数


void SetApperance()
void SetDirection(Ref* psender,Direction direc);
void PauseGame();
void StartGame();

在GameLayer.cpp中实现 SetApperance()函数。代码如下

void GameLayer::SetApperance(){
    visiblesize = Director::getInstance()->getVisibleSize();
    
    background = Sprite::create("BackGround.png");
    background->setPosition(Point(visiblesize.width/2,visiblesize.height/2));
    this->addChild(background,0);  //this is the background
    
    butup = MenuItemImage::create("Button.png","Button2.png","Button.png",CC_CALLBACK_1(GameLayer::SetDirection,this,up));
    Size bs = butup->getContentSize();
    butup->setPosition(Point(visiblesize.width-3*bs.width+bs.width/2,3*bs.height+bs.height/2));

    butdown = MenuItemImage::create("Button.png","Button2.png","Button.png",CC_CALLBACK_1(GameLayer::SetDirection,this,down));
    butdown ->setPosition(Point(visiblesize.width-3*bs.width+bs.width/2,bs.height+bs.height/2));
    
    butleft = MenuItemImage::create("Button.png","Button2.png","Button.png",CC_CALLBACK_1(GameLayer::SetDirection,this,left));
    butleft ->setPosition(Point(visiblesize.width-4*bs.width+bs.width/2,2*bs.height+bs.height/2));
    
    butright = MenuItemImage::create("Button.png","Button2.png","Button.png",CC_CALLBACK_1(GameLayer::SetDirection,this,right));
    butright ->setPosition(Point(visiblesize.width-2*bs.width+bs.width/2,2*bs.height+bs.height/2));
    
    pausebutton = MenuItemImage::create("PauseButton.png","PauseButton.png",CC_CALLBACK_0(GameLayer::PauseGame,this));
    pausebutton->setPosition(Point(visiblesize.width - pausebutton->getContentSize().width,visiblesize.height - pausebutton->getContentSize().height/2));
    
    playbutton = MenuItemImage::create("rePlayButton1.png","rePlayButton2.png",CC_CALLBACK_0(GameLayer::StartGame, this));
    playbutton->setPosition(Point(visiblesize.width/2,visiblesize.height/2));
    playbutton->setVisible(false);
    
    menu = Menu::create(butup,butdown,butleft,butright,pausebutton,playbutton,NULL);
    menu->setPosition(Point::ZERO);
    this->addChild(menu,2);
    
    TTFConfig ttfconfig("Marker Felt.ttf",40);
    gameover = Label::createWithTTF(ttfconfig, " Game Over !",TextHAlignment::CENTER);
    gameover->setPosition(Point(visiblesize.width/2,visiblesize.height/2+gameover->getContentSize().height));
    gameover->setVisible(false);
    gameover->setColor(Color3B::BLACK);
    this->addChild(gameover,2);
}

```


背景和按钮的设置我就不再提了,第一节里面都讲过了,稍微提一下就是第一节里的CC_CALLBACK_0 变成了CC_CALLBACK_1,因为我们要往回调函数SetDirection里面传一个Direction类型的参数。SetDirection函数先放一放,我们先来看如何创建一个label,首先我们要初始化一个ttfconfig结构体,结构体中有许多的成员,我们暂时只初始化前2个成员,分别是ttf文件的位置和字体的大小。配置完ttfconfig结构体后,我们开始创建label,利用createWithTTF函数来创建,前3个参数分别是ttfconfig结构体,你要输入的字符串,以及文字的对其方式,我们这里设置为居中。然后我们设置label的位置和颜色。

注意,这里我们先要将这个label设置为不可见,你可不想玩游戏的时候屏幕上一直有个 GameOver!吧,同样,恢复游戏的按钮也要设置为不可见。

最后用addChild函数添加成员。

好了现在我们已经完成了SetApperance函数了,在init函数中添加SetApperance函数吧!
接下来,我们开始实现SetDirection这个函数,注意如果用CC_CALLBACK1往回调函数里传参数的话,在定义回调函数的时候,要在函数参数中加入Ref* 的一个成员
代码如下
void GameLayer::SetDirection(Ref* psender,Direction direc){
    Direction headdir = head->getDirec();
        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;
        }   
}


```

在这个函数中我们先获取蛇头的方向,然后根据蛇头的方向判断是否可以更改方向,因为当蛇在上下运动的时候,想改变方向的话只能变成左右,同理当蛇在左右运动的时候,只能改成上下运动。简而言之就是不能改成与当前蛇运动相反的方向。

第四节结束

第五节 初始化蛇

在GameLayer.h中添加 void SetSnake()函数
代码如下

void GameLayer::SetSnake(){
    body.clear();
    Size visiblesize = Director::getInstance()->getVisibleSize();
    head = SnakeHead::create();
    head->setNode(Sprite::create("SnakeHead.png"));
    head->setPosition(Point(visiblesize.width/2-head->getNode()->getContentSize().width/2,visiblesize.height/2-head->getNode()->getContentSize().height/2));
    this->addChild(head,1);
    
    for (int i=1 ; i < 4; i++) {
        Snake* bodynode = Snake::create();
        bodynode->setNode(Sprite::create("Snake.png"));
        bodynode->setPosition(Point(head->getPosition().x+i*bodynode->getNode()->getContentSize().width,head->getPosition().y));
        body.pushBack(bodynode);
        this->addChild(bodynode);
    }
    
}

```

我们先初始化蛇头,然后设置蛇头的位置,注意到addchid函数中后面的参数了吧,假设其为z,z指该成员的层级(也可以说深度),z值大的成员在z值小的成员的上面;默认的z是0。除了z,addchild还有一个tag参数,这个参数可以让你可以方便的找到需要的成员,不过我们这里用不到。

好了初始化完蛇头之后,我们开始初始化蛇的身体,一开始,我们定义3个蛇的身体节点,和蛇头一样,先初始化蛇的身体节点,然后设置节点位置,最后将身体节点加入body中,并添加到layer里,这样整条蛇的初始化就结束了,将SetSnake函数添加到init函数中去吧。

本节结束(这节好短);
放一张效果图吧。
 

好帖,浅显易懂,给的链接也有很大的阅读价值。

第六节 实现蛇的运动

我们往GameLayer.h中添加
成员函数:


void MoveStep();
void MoveBody();
virtua void update(float dt);

我们先写MoveBody这个函数。
MoveBody这个函数的作用是移动蛇所有的身体节点。
他的原理就是将每个身体节点的位置设为前一个身体节点的位置,其中如果是第一个身体节点的话,就用蛇头的位置来设置身体节点的位置。
代码如下

void GameLayer::MoveBody(){
    int n=body.size();
    Point HeadPosition = head->getPosition();
    Point a,temp;
    for (int i = 0; i < n; i++) {
        if(i==0){
            a = body.at(i)->getPosition();
            body.at(i)->setPosition(HeadPosition);
        }
        else {
            temp = a;
            a = body.at(i)->getPosition();
            body.at(i)->setPosition(temp);
         }
    }
    
}

```


接着,实现MoveStep函数
代码如下
void GameLayer::MoveStep(){
    movedflag = true;
    Direction temp = head->getDirec();
    Point po = head->Node::getPosition();
    switch (temp) {
        case up:
            //log("upupup");
            po.y += 20;
            break;
        case down:
            po.y -= 20;
            break;
        case left:
            po.x -= 20;
            break;
        case right:
            po.x += 20;
            break;
            
        default:
            break;
    }
    MoveBody();
    head->setPosition(po);
    
}

```


函数中,我们先获得蛇头运动方向,然后根据蛇头运动的方向来设置蛇头接下来的位置。

接着将MoveStep加入到update函数中,并在init函数中添加下面这行代码

```
this->schedule(schedule_selector(GameLayer::update), 0.6);
```


好了,我们现在已经实现蛇的运动啦。

第六节结束

第七节 放置食物及吃掉食物的判定

实现蛇的运动后我们就开始放置食物了,首先在GameLayer.h中添加
成员


Sprite* food;
Point lastbodyposi;

函数


void SetFood();
Point RandomPosition()
bool ifCollideBody(Point pos);
bool ifGetFood();
void AddBody();

首先是SetFood函数
代码如下

void GameLayer::SetFood(){
    this->removeChild(food);
    Point foodposi = RandomPosition();
    Point headposi = head->getPosition();
    while (foodposi==headposi||ifCollideBody(foodposi)) {
        foodposi = RandomPosition();
    }
    food = Sprite::create("Food.png");
    food->setPosition(foodposi);
    this->addChild(food);
}


```

里面有用到RandomPosition和ifCollideBody两个函数,
先说RandomPosition,代码如下
Point GameLayer::RandomPosition(){
    int x = (arc4random()%24);
    int y = (arc4random()%16);
    Point position = Point(x*20+10,y*20+10);
    return position;
}


```

这个函数返回的是一个Point类型的随机点

再是ifCollideBody函数,代码如下
bool GameLayer::ifCollideBody(Point pos){
    bool value = false;
    Snake* node;
    for (int i =0; igetPosition();
        if(nodepos==pos){
            value = true;
        }
    }
    return value;
}


```

这个函数的作用主要是检查给定的位置是否与蛇的身体节点重合,重合返回true,不重合返回false。

回到SetFood这个函数,因为整个游戏画面上同时只能存在一个食物,因此,当每执行SetFood的时候,要把前面设置的食物从layer中移除,所以要执行一下removeChildh函数。
接下来先获取蛇头的位置,然后产生一个随机点,检查该随机点是否与蛇头和蛇身体重合,如果重合,则继续生成随机点,直到生成的随机点与蛇头蛇身不重合为止。然后设置食物的位置为该随机点,设置食物的步骤就结束了。

接下来我们判断食物是否被吃掉,用到的是ifGetFood这个函数
代码如下
bool GameLayer::ifGetFood(){
    bool value = false;
    if(food->getPosition() == head->getPosition()){
        value = true;
    }
    return value;
}


```

非常简单吧
如果食物被吃掉,则调用AddBody函数代码如下
void GameLayer::AddBody(){
    head->setPosition(food->getPosition());
    Snake* node = Snake::create();
    node->setNode(Sprite::create("Snake.png"));
    node->setPosition(lastbodyposi);
    body.pushBack(node);
    this->addChild(node);
}


```

我们要在蛇的末尾加入一个身体节点,就要用到lastbodyposi这个成员了,这个成员保存的是上一步运动过程中,蛇的最后一个身体节点的位置。
这个lastbodyposi是在update函数中更新的,我们先来看一下update函数
void GameLayer::update(float dt){
        MoveStep();
        if(ifGetFood()){
            AddBody();
            SetFood();
        }
        lastbodyposi = body.at(body.size()-1)->getPosition();   
}

```


第七节结束

第八节 游戏结束的判定

贪食蛇里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:

大赞,学习,学习!!

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

学习了。。

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