cocos2d-x 3.0 Win7 + VS2012 下实现贪吃蛇小游戏

做这个小游戏,看的是兄弟连沈大海老师的视频<<贪吃蛇游戏实现>>,不过沈大海老师的是在Xcode下实现的,自己看着视频在win7下实现:

(做这个游戏主要是熟练cocos2d-x的一些用法,所以游戏逻辑没怎么考虑,只简单实现了蛇吃食物,蛇变大,没有去检测边界碰撞以及自身碰撞)

直接附代码,代码注释在沈大海老师的基础上加了我自己的,已经很详细了:

首先AppDelegate.h:

#ifndef  _APP_DELEGATE_H_
#define  _APP_DELEGATE_H_

#include "cocos2d.h"

class  AppDelegate : private cocos2d::Application
{
public:
    AppDelegate();
    virtual ~AppDelegate();

    virtual bool applicationDidFinishLaunching();

    virtual void applicationDidEnterBackground();

    virtual void applicationWillEnterForeground();
};

#endif // _APP_DELEGATE_H_

AppDelegate.cpp

#include "AppDelegate.h"
#include "HelloWorldScene.h"
#include "SimpleAudioEngine.h"
USING_NS_CC;
using namespace CocosDenshion;
AppDelegate::AppDelegate() {

}

AppDelegate::~AppDelegate() 
{
}

bool AppDelegate::applicationDidFinishLaunching() {
    // initialize director
    auto director = Director::getInstance();
    auto glview = director->getOpenGLView();
    if(!glview) {
        glview = GLView::create("My Game");
		glview->setFrameSize(480,320);
        director->setOpenGLView(glview);
		

    }

    // turn on display FPS
    director->setDisplayStats(false);

    // set FPS. the default value is 1.0/60 if you don't call this
    director->setAnimationInterval(1.0 / 60);

    // create a scene. it's an autorelease object
    auto scene = HelloWorld::createScene();

    // run
    director->runWithScene(scene);
	//开始播放背景音乐
	SimpleAudioEngine::getInstance()->playBackgroundMusic("background.mp3");
    return true;
}

// This function will be called when the app is inactive. When comes a phone call,it's be invoked too
   void AppDelegate::applicationDidEnterBackground() {
   Director::getInstance()->stopAnimation();
   SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
    // if you use SimpleAudioEngine, it must be pause
    // SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
}

// this function will be called when the app is active again
   void AppDelegate::applicationWillEnterForeground() {
    Director::getInstance()->startAnimation();
   SimpleAudioEngine::getInstance()->resumeBackgroundMusic();
    // if you use SimpleAudioEngine, it must resume here
    // SimpleAudioEngine::getInstance()->resumeBackgroundMusic();
}

主场景:HelloWorldScene.h

#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__

#include "cocos2d.h"
USING_NS_CC;
class HelloWorld : public Layer
{
public:

    static Scene* createScene();//获取欢迎画面的Scene
    CREATE_FUNC(HelloWorld);
	virtual bool init(); 
    void menuCallback(Ref* object);
   
};



#endif // __HELLOWORLD_SCENE_H__


HelloWorldScene.cpp

#include "HelloWorldScene.h"
#include "GameScene.h"
#include "GameAbout.h"
#include "SimpleAudioEngine.h"
using namespace CocosDenshion;
USING_NS_CC;

Scene* HelloWorld::createScene()
{
   
    auto scene = Scene::create(); 
    auto layer = HelloWorld::create();
    scene->addChild(layer);

    
    return scene;
}

// on "init" you need to initialize your instance
bool HelloWorld::init()
{
    
    if ( !Layer::init() )
    {
        return false;
    }
	
	auto size = Director::getInstance()->getWinSize();
	//添加背景
	auto spriteBK = Sprite::create("menuback.png");
	spriteBK->setPosition(Point(size.width/2,size.height/2));//居中放置背景图片
	this->addChild(spriteBK);

	//添加2个菜单类的条目
	auto menuItemStart = MenuItemFont::create("Start",CC_CALLBACK_1(HelloWorld::menuCallback,this));
	menuItemStart->setTag(1);
	auto menuItemHelp = MenuItemFont::create("Help",CC_CALLBACK_1(HelloWorld::menuCallback,this));
	menuItemHelp->setTag(2);
	auto menu = Menu::create(menuItemStart,menuItemHelp,NULL);
	menu->setPosition(Point::ZERO);
	menuItemStart->setPosition(Point(size.width -menuItemStart->getContentSize().width-100,menuItemStart->getContentSize().height+10));
	menuItemHelp->setPosition(Point(size.width -menuItemStart->getContentSize().width-10,menuItemHelp->getContentSize().height+10));
	this->addChild(menu);
    return true;
}


void HelloWorld::menuCallback(Ref* object)
{
	auto target = (Node*)object;
	Scene* scene;
	switch(target->getTag()){
	case 1:
		scene=Game::createScene();
		break;
	case 2:
		scene = GameHelp::createScene();
		break;
	default:
		break;
	}
	Director::getInstance()->replaceScene(scene);
	
}


帮助界面:GameAbout.h

#ifndef __snakegame__GameAbout__
#define __snakegame__GameAbout__

#include "cocos2d.h"


USING_NS_CC; //相当于using namespace cocos2d
//帮助场景
class GameHelp:public Layer
{
public:
	static Scene* createScene();
	CREATE_FUNC(GameHelp);
	virtual bool init();
	void menuCallback(Ref* object);
};
#endif

GameAbout.cpp

#include "GameAbout.h"
#include "HelloWorldScene.h"

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 size = Director::getInstance()->getWinSize();
	//添加背景
	auto spriteBK = Sprite::create("menuback.png");
	spriteBK->setPosition(Point(size.width/2,size.height/2));
	spriteBK->setOpacity(85);//????不知道的地方
	this->addChild(spriteBK);

	//帮助信息
	auto labelScore = LabelTTF::create("help information","Helvetica",25);
	labelScore->setPosition(Point(size.width-120,size.height-50));
	this->addChild(labelScore);


	//返回按钮
	auto menuItemBack = MenuItemFont::create("BACK",CC_CALLBACK_1(GameHelp::menuCallback,this));
	auto menu = Menu::create(menuItemBack,NULL);
	menu->setPosition(Point::ZERO);
	menuItemBack->setPosition(Point(size.width-menuItemBack->getContentSize().width-100,menuItemBack->getContentSize().height+10));
	this->addChild(menu);
	
	return  true;
}

void GameHelp::menuCallback(Ref* object)
{
	auto scene = HelloWorld::createScene();
	Director::getInstance()->replaceScene(scene);
}


游戏实现界面:GameScene.h

//游戏画面
#ifndef __snakegame__GameScene__
#define __snakegame__GameScene__
#include "cocos2d.h"
USING_NS_CC;
//定义一个游戏的枚举类型来标识贪吃蛇的移动方向
enum  class ENUM_DIR
{
	DIR_UP,
	DIR_DOWN,
	DIR_LEFT,
	DIR_RIGHT,
	DIR_STOP
};
//蛇精灵
class SnakeNode:public Sprite//封装节点
{
public:
	
    ENUM_DIR m_dir;//移动方向
	int nodeType;//当前类型 1:蛇头2:身体3食物
	int m_row, m_col; //当前节点的行列坐标

	SnakeNode();
	~SnakeNode();
	static SnakeNode* create(int type);
	virtual bool init(int type);
	void setPositionRC(int row, int col);//设置节点的坐标
};
//游戏界面图层
class Game:public Layer{
public:
	SnakeNode* spFood;//食物
	SnakeNode* spHead;//蛇头
	int m_score; //分
	Game();
	~Game();
	Vector<SnakeNode*>allBody;//身体,身体长度是不确定的,不确定的数组利用向量Vector
	static Scene* createScene();
	CREATE_FUNC(Game);
	virtual bool init();
	void menuCallBack(Ref* object);
	void  gameLogic(float);
	void newBody();//添加一个新的身体节点
	void moveBody();//移动所有的身体节点
};
#endif


GameScene.cpp:

#include "GameScene.h"
#include "HelloWorldScene.h"
#include "SimpleAudioEngine.h"
using namespace CocosDenshion;

Game::Game(): spFood(NULL),spHead(NULL)
{

}
Game::~Game(){}
Scene* Game::createScene()
{
	auto scene = Scene::create();
	auto layer = Game::create();
	scene->addChild(layer);
	return scene;
}

SnakeNode* SnakeNode::create(int type)
{
	SnakeNode * pRet = new SnakeNode();
	if(pRet && pRet->init(type) )
	{
		pRet->autorelease();
		return pRet;
	}
	else
	{
		delete pRet;
		pRet = NULL;
		return NULL;
	}
}
SnakeNode::SnakeNode() : m_row(0),m_col(0)
{

}
SnakeNode::~SnakeNode()
{

}
bool SnakeNode::init(int type)
{
	if(!Sprite::init())
	{
		return false;
	}
	//根据类型不同初始化不同的纹理
	switch(type)
	{
	case 1://蛇头
		{
			auto sprite = Sprite::create("redstar.png");
			sprite->setAnchorPoint(Point::ZERO);//设置锚点
			this->addChild(sprite);
			m_dir = ENUM_DIR::DIR_RIGHT;//向右移动
		}
		break;
	case 2://身体
		{
			auto sprite = Sprite::create("greenstar.png");
			sprite->setAnchorPoint(Point::ZERO);
			this->addChild(sprite);
		}
		m_dir = ENUM_DIR::DIR_STOP;
		break;
	case 3://食物
		{
			auto sprite = Sprite::create("yellowstar.png");
			sprite->setAnchorPoint(Point::ZERO);
			this->addChild(sprite);

		}
		m_dir = ENUM_DIR::DIR_STOP;
		break;
	}
	return true;
}

void SnakeNode::setPositionRC(int row, int col)//设置节点的坐标
{
	this->m_row = row;
	this->m_col = col;
	setPosition(Point(m_col*32,m_row*32));
}
 bool Game::init()
 {
	 if(!Layer::init())
	 {
		 return false;
	 }
	 //添加地图
	 auto draw = DrawNode::create();
	 draw->setAnchorPoint(Point::ZERO);
	 draw->setPosition(Point::ZERO);
	 this->addChild(draw);
	 for(int i = 0; i < 11; i++)
	 {
		 draw->drawSegment(Point(0,32*i),Point(320,32*i),1,Color4F(1,1,1,1));//添加10条横向的线条
		 draw->drawSegment(Point(32*i,0),Point(32*i,320),1,Color4F(1,1,1,1));//添加10条纵向的线条
	 }
	 //添加蛇头
	 spHead = SnakeNode::create(1);
	 spHead->setPositionRC(0,0);
	 this->addChild(spHead);
	 
	 CCLog("spHead  %d,%d",spHead->m_col,spHead->m_row);
	 //添加身体
	 //添加食物
	 spFood = SnakeNode::create(3);
	 int row = rand()%10;
	 int col = rand()%10;
	 spFood->setPositionRC(row,col);
	 CCLog(" spFood %d,%d",spFood->m_col,spFood->m_row);
	 this->addChild(spFood);

	 auto size = Director::getInstance()->getWinSize();
	 //添加背景
	 auto spriteBK = Sprite::create("menuback.png");
	 spriteBK->setPosition(Point(size.width/2,size.height/2));
	 spriteBK->setOpacity(75);
	 this->addChild(spriteBK);

	 //分数显示
	 m_score = 0;
	 auto labelScore = Label::create("Score is 0","宋体",25);
	 labelScore->setTag(110);
	 labelScore->setPosition(Point(size.width-80,size.height -50 ));
	 this->addChild(labelScore);

	 //返回按钮
	auto menuItemBack=MenuItemFont::create("Back", CC_CALLBACK_1(Game::menuCallBack,this));
    auto menu=Menu::create(menuItemBack,NULL);
    menu->setPosition(Point::ZERO);
    menuItemBack->setPosition(Point(size.width-menuItemBack->getContentSize().width-50,menuItemBack->getContentSize().height+10));
    this->addChild(menu);
	//计划任务
	this->schedule(schedule_selector(Game::gameLogic),0.5);
    //加入用户触摸事件监听
	auto listener = EventListenerTouchOneByOne::create();
	listener->setSwallowTouches(true);//不向下触摸,简单点来说,比如有两个sprite ,A 和 B,A在上B在下(位置重叠),触摸A的时候,B不会受到影响 
	//listener->setSwallowTouches(false)反之,向下传递触摸,触摸A也等于触摸了B

	listener->onTouchBegan= [&](Touch* t, Event* e){
	
		//改变贪吃蛇移动的方向
		int col = t->getLocation().x/32;
		int row = t->getLocation().y/32;
		CCLog("your touchbegin %f,%f", t->getLocation().x,t->getLocation().y);
		int spHeadCol = spHead->getPositionX()/32;//列
		int spHeadRow = spHead->getPositionY()/32;//行
		if(abs(spHeadCol - col)> abs(spHeadRow - row))//如果点击一个位置后该位置与蛇头相比列的差值大于行的差值,就执行左右移动
		{
			if (spHeadCol < col)//列影响的是左右移动
			{
				spHead->m_dir = ENUM_DIR::DIR_RIGHT;
			}
			else
			{
				spHead->m_dir = ENUM_DIR::DIR_LEFT;
			}
		}
		else//行的差值大于列的差值
		{
			if(spHeadRow < row)//行影响的是上下的移动
			{
				spHead->m_dir = ENUM_DIR::DIR_UP;
			}
			else
			{
				spHead->m_dir = ENUM_DIR::DIR_DOWN;
			}
		}
		return true;	 
	};
	_eventDispatcher->addEventListenerWithSceneGraphPriority(listener,this);
	 return true;
 }
 void Game::gameLogic(float t)
 {
	 moveBody();//移动身体所有节点
	 //蛇头移动
	 switch (spHead->m_dir)
	 {
	 case ENUM_DIR::DIR_RIGHT:
		 spHead->runAction(MoveBy::create(0.3,Point(32,0)));//向右移动32个像素,也就是向右移动一个单位
		 spHead->m_col++;
		 break;
	 case ENUM_DIR::DIR_LEFT:
		   spHead->runAction(MoveBy::create(0.3, Point(-32,0)));//向左移动32个像素
           spHead->m_col--;
           break;
     case ENUM_DIR::DIR_DOWN:
           spHead->runAction(MoveBy::create(0.3, Point(0,-32)));
           spHead->m_row--;
           break;
     case ENUM_DIR::DIR_UP:
			spHead->runAction(MoveBy::create(0.3, Point(0,32)));
			spHead->m_row++;
			break;
	 default:
		 break;
	 }
	  //碰撞检测
    if(spHead->m_row==spFood->m_row&&
       spHead->m_col==spFood->m_col)
    {  //音效的播放
        SimpleAudioEngine::getInstance()->playEffect("eat.wav");
        //分数增加
        this->m_score+=100;
        Label * label=(Label *)this->getChildByTag(110);
        char strscore[20];
        sprintf(strscore, "Score is:%d",m_score);
        label->setString(strscore);
      //食物产生新的位置
        int row=rand()%10;
        int col=rand()%10;
        spFood->setPositionRC(row,col);
      //添加节点
        newBody();
    }

 }

 void Game::newBody()
 {
	 auto bodynode = SnakeNode::create(2);//新建身体节点
	 //设置这个节点的方向和坐标
	 if(allBody.size()>0)//有身体节点
	 {
		 //最后一个身体的节点
		 auto lastbody = allBody.at(allBody.size()-1);
		 bodynode->m_dir = lastbody->m_dir;

		 switch (bodynode->m_dir)
		 {
		 case ENUM_DIR::DIR_UP:
			 bodynode->setPositionRC(lastbody->m_row-1,lastbody->m_col);
			 break;
		case ENUM_DIR::DIR_DOWN:
			bodynode->setPositionRC(lastbody->m_row+1, lastbody->m_col);
			break;
		case ENUM_DIR::DIR_LEFT:
			bodynode->setPositionRC(lastbody->m_row, lastbody->m_col+1);
			break;
		case ENUM_DIR::DIR_RIGHT:
			bodynode->setPositionRC(lastbody->m_row, lastbody->m_col-1);
			break;
		 default:
			 break;
		 }
	 }else
	 {
		 bodynode->m_dir = spHead->m_dir;
		 switch (bodynode->m_dir)
		 {
			case ENUM_DIR::DIR_UP:
                bodynode->setPositionRC(spHead->m_row-1, spHead->m_col);
                break;
            case ENUM_DIR::DIR_DOWN:
                bodynode->setPositionRC(spHead->m_row+1, spHead->m_col);
                break;
            case ENUM_DIR::DIR_LEFT:
                bodynode->setPositionRC(spHead->m_row, spHead->m_col+1);
                break;
            case ENUM_DIR::DIR_RIGHT:
                bodynode->setPositionRC(spHead->m_row, spHead->m_col-1);
                break;
			default:
				break;
		 }
	 }
	 //添加节点到当前图层
	 this->addChild(bodynode);
	 //添加节点到集合中
	 allBody.pushBack(bodynode);
 }

void Game::moveBody()//移动所有的身体节点
{
	if(allBody.size() == 0)
	{
		return;
	}
	for (auto bodynode:allBody)
	{
		switch (bodynode->m_dir)
		{
		case ENUM_DIR::DIR_RIGHT:
            bodynode->runAction(MoveBy::create(0.3, Point(32,0)));
            bodynode->m_col++;
            break;
        case ENUM_DIR::DIR_LEFT:
            bodynode->runAction(MoveBy::create(0.3, Point(-32,0)));
            bodynode->m_col--;
            break;
        case ENUM_DIR::DIR_DOWN:
            bodynode->runAction(MoveBy::create(0.3, Point(0,-32)));
            bodynode->m_row--;
            break;
        case ENUM_DIR::DIR_UP:
            bodynode->runAction(MoveBy::create(0.3, Point(0,32)));
            bodynode->m_row++;
            break;
		default:
			break;
		}
	}
	//移动完成后,改变每个body的方向
	for(int i = allBody.size()-1;i > 0; i--)
	{
		//每个节点的方向调整为它前一个节点的方向
		allBody.at(i)->m_dir = allBody.at(i-1)->m_dir;
	}
	allBody.at(0)->m_dir = spHead->m_dir;



}
void Game::menuCallBack(Ref* object)
{
	auto scene = HelloWorld::createScene();
	Director::getInstance()->replaceScene(scene);
}


刚开始看着沈大海老师的视频,实现后蛇头与食物碰撞后没有反应,后面找到原因是蛇头没有初始化,但是沈老师的视频里面用的Xcode的确没有初始化,可能默认为0,而VS编译器检查严格一点,所以没有实现效果,要自己写出构造函数初始化它拥有的成员变量!!!


 



 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值