cocos2d-x开发日志10 ——贪食蛇源码

简单的游戏开发,比较适合和我一样的小白练手,除了游戏结束场景,全部包含在了HelloWorldScene中,先上源码,注释已经比较全面,但是具体细节会陆续更新。

HelloWorldScene.h

#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__

#include "cocos2d.h"
#include "GameOverScene.h"
#include 
#include 
#include 
#include 
using namespace cocos2d;
using namespace std;
//贪食蛇移动方向
typedef enum{
    UP=1,
    DOWN,
    LEFT,
    RIGHT
}DIR_DEF;

//蛇的头 身体 食物 共用这个node
class SnakeNode:public Node{
public:
    int row; //行
    int col; //列
    int dir; //方向
    DrawNode *pic;//要加载的图片
};

//欢迎场景
class HelloWorld : public Layer{
public:
    virtual bool init();//初始化函数
    static Scene * createScene();//获取欢迎画面的scene
    void menuCloseCallback(Ref * pSender);
    CREATE_FUNC(HelloWorld);

};

//帮助画面
class GameHelp: public Layer{
public:
    virtual bool init();
    static Scene * createScene();
    CREATE_FUNC(GameHelp);
    void menuBackToMain(Ref * pSender);
};

//游戏画面
class GameLayer : public Layer{
protected:
    bool pause_resume=0;//是否暂停 0为继续,1为暂停
    SnakeNode  *sHead;//贪食蛇的头部
    SnakeNode  *sFood;//食物
    Vector   allbody;//身体
    //暂存起点坐标 网格单位长度
    int ox = 50;
    int oy = 60;
    int unit =20;
    //获得分数
    int score = 0;
public:
    //初始化
    virtual bool init();
    static Scene * createScene();
    CREATE_FUNC(GameLayer);
    //游戏逻辑
    void logic01(float t);
    void menuBackToMain( Ref * pSender);//返回主菜单
};


#endif // __HELLOWORLD_SCENE_H__

HelloWorldScene.cpp

#include "HelloWorldScene.h"
#define START_TAG 10
#define HELP_TAG 11
#define EXIT_TAG 12
#define MAINMENU_TAG 13
#define UP_TAG 14
#define DOWN_TAG 15
#define LEFT_TAG 16
#define RIGHT_TAG 17
#define PAUSE_TAG 18
#define SCORE_TAG 19
#define MENU_TAG 20

USING_NS_CC;
using namespace cocos2d;

//************************************************************************//
//**                                                                    **//
//**                              欢迎界面                               **//
//**                                                                    **//
//************************************************************************//

//欢迎界面方法
Scene * HelloWorld::createScene(){
    Scene * scene = Scene::create();
    HelloWorld * layer = HelloWorld::create();
    scene-> addChild(layer);
    return scene;
}

//欢迎界面初始化方法
bool HelloWorld::init(){
    if (!Layer::init())
        return false;

    //游戏名称标签
    auto label = Label::createWithTTF("SNAKE", "fonts/Marker Felt.ttf", 50);
    label->setColor(Color3B(0,120,100));
    label->setPosition(Director::getInstance()->getWinSize().width/2,
                       Director::getInstance()->getWinSize().height/2+
                       label->getContentSize().height*1.5);
    this->addChild(label);

    //开始 按钮
    auto start = Label::createWithTTF("Start Game", "fonts/Marker Felt.ttf", 24);
    start->setColor(Color3B(0,255,0));
    auto start_button = MenuItemLabel::create(start,CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));
    start_button->setPositionY(start->getPositionY()+start_button->getContentSize().height*1.5);
    start_button->setTag(START_TAG);
    //帮助 按钮
    auto help = Label::createWithTTF("Help", "fonts/Marker Felt.ttf", 24);
    help->setColor(Color3B(0,0,255));
    auto help_button = MenuItemLabel::create(help,CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));
    help_button->setTag(HELP_TAG);
    //退出 按钮
    auto exit = Label::createWithTTF("Exit", "fonts/Marker Felt.ttf", 24);
    exit->setColor(Color3B(200,0,200));
    auto exit_button = MenuItemLabel::create(exit,CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));
    exit_button->setPositionY(start->getPositionY()-exit_button->getContentSize().height*1.5);
    exit_button->setTag(EXIT_TAG);
    //新建菜单
    auto menu = Menu::create(start_button,help_button,exit_button,NULL);
    this->addChild(menu);

    return true;
}

//欢迎界面菜单回调函数
void HelloWorld::menuCloseCallback(Ref * pSender){
    switch (((MenuItemLabel*)pSender)->getTag()) {
        case START_TAG:{
            auto scene = GameLayer::createScene();
            Director::getInstance()->replaceScene(scene);
            break;
        }

        case HELP_TAG:{
            auto scene = GameHelp::createScene();
            Director::getInstance()->replaceScene(scene);
            break;
        }

        case EXIT_TAG:
            Director::getInstance()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
            exit(0);
#endif
            break;

        default:
            break;
    }
}

//************************************************************************//
//**                                                                    **//
//**                              帮助界面                                **//
//**                                                                    **//
//************************************************************************//

//帮助画面方法
Scene * GameHelp::createScene(){
    auto scene = Scene::create();
    auto layer = GameHelp::create();
    scene-> addChild(layer);
    return scene;
}

//帮助画面初始化方法
bool GameHelp::init(){
    if (!Layer::init())
        return false;

    //帮助文字
    auto label = Label::createWithTTF("DO NOT TELL ME YOU CAN'T DO THIS ,YOU FOOL!", "fonts/Marker Felt.ttf", 24);
    label->setColor(Color3B(200,70,200));
    label->setPosition(Director::getInstance()->getWinSize().width/2,
                       Director::getInstance()->getWinSize().height/2+50);
    this->addChild(label);

    //返回主菜单 按钮
    auto MainMenu = Label::createWithTTF("Main Menu", "fonts/Marker Felt.ttf", 24);
    MainMenu->setColor(Color3B(0,200,200));
    auto MainMenu_button = MenuItemLabel::create(MainMenu,CC_CALLBACK_1(GameHelp::menuBackToMain, this));
    MainMenu_button->setPositionY(MainMenu_button->getPositionY()-50);
    MainMenu_button->setTag(EXIT_TAG);
    //新建菜单
    auto menu = Menu::create(MainMenu_button,NULL);
    this->addChild(menu);

    return true;
}

//帮助画面菜单回调方法
void GameHelp::menuBackToMain(Ref * pSender){
    auto scene = HelloWorld::createScene();
    Director::getInstance()->replaceScene(scene);
}


//************************************************************************//
//**                                                                    **//
//**                              游戏界面                                **//
//**                                                                    **//
//************************************************************************//

//游戏界面方法
Scene * GameLayer:: createScene(){
    auto scene = Scene::create();
    auto layer = GameLayer::create();
    scene->addChild(layer);
    return scene;
}

bool GameLayer::init(){
    if (!Layer::init())
        return false;


    //返回主菜单 按键
    auto MainMenu = Label::createWithTTF("Main Menu", "fonts/Marker Felt.ttf", 24);
    MainMenu->setColor(Color3B(0,200,200));
    auto MainMenu_button = MenuItemLabel::create(MainMenu,CC_CALLBACK_1(GameLayer::menuBackToMain, this));
    MainMenu_button->setTag(0);
    MainMenu_button->setPosition(Director::getInstance()->getWinSize().width*0.3,
                                -Director::getInstance()->getWinSize().height*0.3);
    //暂停 按键
    auto pause = Label::createWithTTF("PAUSE", "fonts/Marker Felt.ttf", 24);
    pause->setColor(Color3B(255,100,100));
    auto pause_button = MenuItemLabel::create(pause,CC_CALLBACK_1(GameLayer::menuBackToMain, this));
    pause_button->setTag(PAUSE_TAG);
    pause_button->setPosition(Director::getInstance()->getWinSize().width*0.3,
                           -Director::getInstance()->getWinSize().height*0.3+140);
    //向上 按键
    auto up = Label::createWithTTF("UP", "fonts/Marker Felt.ttf", 24);
    up->setColor(Color3B(0,255,0));
    auto up_button = MenuItemLabel::create(up,CC_CALLBACK_1(GameLayer::menuBackToMain, this));
    up_button->setTag(UP_TAG);
    up_button->setPosition(Director::getInstance()->getWinSize().width*0.3,
                        -Director::getInstance()->getWinSize().height*0.3+100);

    //向下 按键
    auto down = Label::createWithTTF("DOWN", "fonts/Marker Felt.ttf", 24);
    down->setColor(Color3B(0,255,0));
    auto down_button = MenuItemLabel::create(down,CC_CALLBACK_1(GameLayer::menuBackToMain, this));
   down_button->setTag(DOWN_TAG);
    down_button->setPosition(Director::getInstance()->getWinSize().width*0.3,
                           -Director::getInstance()->getWinSize().height*0.3+40);

    //向左 按键
    auto left = Label::createWithTTF("LEFT", "fonts/Marker Felt.ttf", 24);
    left->setColor(Color3B(0,255,0));
    auto left_button = MenuItemLabel::create(left,CC_CALLBACK_1(GameLayer::menuBackToMain, this));
    left_button->setTag(LEFT_TAG);
    left_button->setPosition(Director::getInstance()->getWinSize().width*0.3-30,
                             -Director::getInstance()->getWinSize().height*0.3+70);

    //向右 按键
    auto right = Label::createWithTTF("RIGHT", "fonts/Marker Felt.ttf", 24);
    right->setColor(Color3B(0,255,0));
    auto right_button = MenuItemLabel::create(right,CC_CALLBACK_1(GameLayer::menuBackToMain, this));
    right_button->setTag(RIGHT_TAG);
    right_button->setPosition(Director::getInstance()->getWinSize().width*0.3+30,
                             -Director::getInstance()->getWinSize().height*0.3+70);
    //新建菜单
    auto menu = Menu::create(MainMenu_button,up_button,left_button,down_button,right_button,pause_button,NULL);
    this->addChild(menu);
    menu->setTag(MENU_TAG);

    //显示分数
    char a[3] ;
    stringstream stream;
    stream << score;
    stream >> a;
    auto score_label = Label::createWithTTF (a, "fonts/Marker Felt.ttf", 40);
    score_label->setPosition(Director::getInstance()->getWinSize().width*0.8,
                              Director::getInstance()->getWinSize().height*0.8);
    score_label->setTag(SCORE_TAG);
    this->addChild(score_label);


    //设置网格
    for(int i=0; i<11; i++){
        for(int j=0; j<11 ;j++){
            auto head1 = DrawNode::create();
            head1->drawDot(Point(0,0), 1, Color4F(1, 1, 1, 0.5));
            head1->setPosition(Vec2(ox+unit*i, oy+unit*j));
            this->addChild(head1,4);
        }
    }

    //初始化蛇头
    sHead = new SnakeNode();
    sHead->row = arc4random()%10;
    sHead->col = arc4random()%10;
    sHead->dir = arc4random()%4+1;
    CCLOG("%d %d",sHead->row,sHead->col);
    sHead->pic = DrawNode::create();
    sHead->pic->drawSolidRect(Point(0,0),Point(unit,unit),Color4F(1, 0, 0, 0.8));
    sHead->pic->setPosition(Vec2(ox+sHead->col*unit,oy+sHead->row*unit));
    this->addChild(sHead->pic,2);

    //初始化食物
    sFood = new SnakeNode;
    sFood->row = arc4random()%10;
    sFood->col = arc4random()%10;
    sFood->pic = DrawNode::create();
    sFood->pic->drawSolidRect(Point(0,0),Point(unit,unit), Color4F(1,1,1,1));
    sFood->pic->setPosition(Vec2(ox+sFood->col*unit,oy+sFood->row*unit));
    this->addChild(sFood->pic,2);

    //初始化身体
    //allbody.reserve(1);
    //执行计划任务
   this->schedule(schedule_selector(GameLayer::logic01), 0.8);
    return true;
}

//游戏界面菜单回调方法
void GameLayer::menuBackToMain( Ref * pSender){
    auto p = (MenuItemLabel*)pSender;
    switch (p->getTag()) {
        case 0:{
            auto scene = HelloWorld::createScene();
            Director::getInstance()->replaceScene(scene);
            break;
        }

        case UP_TAG:{
            if(sHead->dir!=DIR_DEF::DOWN)
            sHead->dir = DIR_DEF::UP;
            break;
        }

        case DOWN_TAG:{
            if(sHead->dir!=DIR_DEF::UP)
            sHead->dir = DIR_DEF::DOWN;
            break;
        }

        case LEFT_TAG:{
            if(sHead->dir!=DIR_DEF::RIGHT)
            sHead->dir = DIR_DEF::LEFT;
            break;
        }

        case RIGHT_TAG:{
            if(sHead->dir!=DIR_DEF::LEFT)
            sHead->dir = DIR_DEF::RIGHT;
            break;
        }

        case PAUSE_TAG:{
            if(pause_resume == 0){
                pause_resume = 1;
                unschedule(schedule_selector(GameLayer::logic01));
                MenuItemLabel* l = (MenuItemLabel*)this->getChildByTag(MENU_TAG)-> getChildByTag(PAUSE_TAG);
                l->setString("RESUME");
            }
            else{
                //Director::getInstance()->resume();
                pause_resume = 0;
                schedule(schedule_selector(GameLayer::logic01), 0.8);
                MenuItemLabel * l = (MenuItemLabel*)this->getChildByTag(MENU_TAG)->getChildByTag(PAUSE_TAG);
                l->setString("PAUSE");
            }
            break;
        }
        default:
            break;
    }
}

//计划任务
void GameLayer::logic01(float t){


    //移动身体
    for (int i = allbody.size()-1; i>=0; i--) {
        SnakeNode * sn = allbody.at(i);
        if (i>0) {
            auto snpre = allbody.at(i-1);
            sn->dir = snpre->dir;
            sn->row = snpre->row;
            sn->col = snpre->col;
        }
        //移动第一个节点
        else if (i==0) {
            sn->dir = sHead->dir;
            sn->row = sHead->row;
            sn->col = sHead->col;

        }
    }


    //移动蛇头
    switch (sHead->dir) {
        case DIR_DEF::UP:{
            sHead->row++;
            if(sHead->row >= 10)
            sHead->row = 0;
            break;
        }

        case DIR_DEF::DOWN:{
            sHead->row--;
            if(sHead->row < 0)
                sHead->row = 9;
            break;
        }

        case DIR_DEF::LEFT:{
            sHead->col--;
            if(sHead->col < 0)
                sHead->col = 9;
            break;
        }

        case DIR_DEF::RIGHT:{
            sHead->col++;
            if(sHead->col >= 10)
                sHead->col = 0;
            break;
        }


    }


    //头结点重置图像位置
    sHead->pic->setPosition(Vec2(ox+sHead->col*unit,oy+sHead->row*unit));

    //碰撞检测
    if(sHead->row==sFood->row && sHead->col==sFood->col){
        score ++;
        char a[3] ;
        stringstream stream;
        stream << score;
        stream >> a;
        auto l =(Label *)this->getChildByTag(SCORE_TAG);
        l->setString(a);

        //食物消失
        while(1){
            bool flag = true;
            sFood->row = rand()%10;
            sFood->col = rand()%10;
            for (int i=0; iif(allbody.at(i)->row==sFood->row && allbody.at(i)->col==sFood->col)
                    flag = false;
            }
            if(flag == true) break;
        }
        sFood->pic->setPosition(Vec2(ox+sFood->col*unit,oy+sFood->row*unit));
        //添加身体到集合
        SnakeNode  * sn;
        sn = new SnakeNode;
        SnakeNode  *lastNode;
        if (allbody.size()>0)
            lastNode = allbody.at(allbody.size()-1);
        else
            lastNode = sHead;
        switch (lastNode->dir) {
            case DIR_DEF::UP:
                sn->row = lastNode->row-1;
                sn->col = lastNode->col;
                break;

            case DIR_DEF::DOWN:
                sn->row = lastNode->row+1;
                sn->col = lastNode->col;
                break;

            case DIR_DEF::LEFT:
                sn->row = lastNode->row;
                sn->col = lastNode->col+1;
                break;

            case DIR_DEF::RIGHT:
                sn->row = lastNode->row;
                sn->col = lastNode->col-1;
                break;
        }
        sn->dir = lastNode->dir;
        this->allbody.pushBack(sn);
        sn->pic = DrawNode::create();
        sn->pic->drawSolidRect(Point(0,0),Point(unit,unit),Color4F(0, 1, 0, 0.8));
        sn->pic->setPosition(Vec2(ox+sn->col*unit,oy+sn->row*unit));
        this->addChild(sn->pic);

    }
    //重置身体位置
    for (int i = 0; ipic->setPosition(Vec2(ox+allbody.at(i)->col*unit,oy+allbody.at(i)->row*unit));
    }

    //game over 判定
    for (int i=0; iif(allbody.at(i)->row==sHead->row && allbody.at(i)->col==sHead->col){
            auto scene = GameOver::createScene();
            Director::getInstance()->replaceScene(scene);
        }
}

GameOverScene.h

//
//  GameOverScene.h
//  snakegame
//
//  Created by jiumiao on 15/8/9.
//
//

#ifndef __snakegame__GameOverScene__
#define __snakegame__GameOverScene__

#include 
#include "cocos2d.h"
#include "HelloWorldScene.h"
USING_NS_CC;

class GameOver : public Layer{
public:
    bool init();//初始化函数
    static Scene * createScene();//获取欢迎画面的scene
    void menuCloseCallback(Ref * pSender);
    CREATE_FUNC(GameOver);

};

#endif /* defined(__snakegame__GameOverScene__) */

GameOverScene.cpp

//
//  GameOverScene.cpp
//  snakegame
//
//  Created by jiumiao on 15/8/9.
//
//

#include "GameOverScene.h"

//初始化函数
bool GameOver:: init(){
    if(!Layer::init())
        return false;
    //Game Over
    auto label = Label::createWithTTF("Game Over", "fonts/Marker Felt.ttf", 50);
    label->setColor(Color3B(255,120,100));
    label->setPosition(Director::getInstance()->getWinSize().width/2,
                       Director::getInstance()->getWinSize().height/2+
                       label->getContentSize().height*1.5);
    this->addChild(label);

    //返回游戏 按钮
    auto tryagain = Label::createWithTTF("Try Again", "fonts/Marker Felt.ttf", 24);
    tryagain->setColor(Color3B(0,200,200));
    auto tryagain_button = MenuItemLabel::create(tryagain,CC_CALLBACK_1(GameOver::menuCloseCallback, this));
    tryagain_button->setPositionY(tryagain_button->getPositionY()-50);
    tryagain_button->setTag(20);
    auto menu = Menu::create(tryagain_button,NULL);
    this->addChild(menu);


    return true;
}

//获取结束画面
Scene * GameOver::createScene(){
    auto scene = Scene::create();
    auto layer = GameOver::create();
    scene-> addChild(layer);
    return scene;
}


void GameOver::menuCloseCallback(Ref * pSender){
    auto scene = GameLayer::createScene();
    Director::getInstance()->replaceScene(scene);
}

你可能感兴趣的:(cocos2d-x)