cocos2d-x 3.2 |如何实现一个贪吃蛇游戏
前情提要:今天我们来实现一个简单版的贪吃蛇游戏,利用这些经典的游戏上手cocos2d最好不过了。
忽略:本章忽略菜单、按钮、跳转、帮助等功能、主要实现贪吃蛇逻辑与效果
第一步:新建Game类,定义贪吃蛇主要功能与方法 Game.h如下:
#include <stdio.h>
#include "cocos2d.h"
USING_NS_CC;
using namespace ui;
//枚举定义蛇运动方向
enum class SNAKE_DIR
{
DIR_UP,
DIR_LEFT,
DIR_RIGHT,
DIR_DOWN
};
class SNode:public Node
{
public:
LayerColor * sprite;//纹理
int px,py;//坐标
SNAKE_DIR dir;//方向
CREATE_FUNC(SNode);
bool init();//初始化
void setColor(Color3B color);//颜色
void moveTo(int x,int y);//位移到
};
class GameScene:public Layer
{
public:
SNode * snakeHead;//蛇头
SNode *food;//食物
Vector<SNode *> allBody;//身体
int mapx;
int mapy;
CREATE_FUNC(GameScene);
bool init();
static Scene * createScene();
void gameLogc(float t);//逻辑
virtual bool onTouchBegan(Touch *touch, Event *unused_event);//触摸
};
第二步:实现Game类的方法 Game.cpp如下:
#include "Game.h"
Scene * GameScene::createScene(){
auto scene=Scene::create();
auto layer=GameScene::create();
scene->addChild(layer);
return scene;
}
bool GameScene::init(){
if(!Layer::init())
{
return false;
}
//绘制游戏背景
auto bk=LayerColor::create(Color4B(149, 149, 149, 180));
this->addChild(bk);
//绘制游戏地图
auto map=DrawNode::create();
map->setTag(100);
for (int i=0; i<=20; i++)
{
//绘制十1条横线
map->drawSegment(Vec2(0,i*30),Vec2(600,i*30),0.5,Color4F::GRAY);
map->drawSegment(Vec2(i*30,0),Vec2(i*30,600),0.5,Color4F::GRAY);
}
//map->setAnchorPoint(Vec2(0.5,0.5));
map->setPosition(Vec2(280,20));
this->addChild(map);
//绘制蛇头
this->snakeHead=SNode::create();
this->snakeHead->setColor(Color3B::MAGENTA);
map->addChild(snakeHead);
int row=0;
int col=0;
row=rand()%10;
col=rand()%10;
this->snakeHead->moveTo(col*30, row*30);
snakeHead->dir=SNAKE_DIR::DIR_DOWN;
//绘制食物
this->food=SNode::create();
this->food->setColor(Color3B::YELLOW);
map->addChild(food);
mapx=map->getPositionX();
mapy=map->getPositionY();
row=rand()%20;
col=rand()%20;
this->food->moveTo(col*30, row*30);
//让蛇头运动
this->schedule(schedule_selector(GameScene::gameLogc), 0.2);
//改变舌头方向
auto listener=EventListenerTouchOneByOne::create();
listener->onTouchBegan=CC_CALLBACK_2(GameScene::onTouchBegan, this);
Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener,this);
return true;
}
//根据按下位置,判断舌头移动方向
bool GameScene::onTouchBegan(Touch *touch, Event *unused_event){
int w=abs(touch->getLocation().x-mapx-snakeHead->px);
int h=abs(touch->getLocation().y-mapy-snakeHead->py);
if(w>h)//左右移动
{
if(touch->getLocation().x-mapx>snakeHead->px)//右
{
snakeHead->dir=SNAKE_DIR::DIR_RIGHT;
}else
{
snakeHead->dir=SNAKE_DIR::DIR_LEFT;
}
}else
{
if(touch->getLocation().y-mapy>snakeHead->py)//上
{
snakeHead->dir=SNAKE_DIR::DIR_UP;
}else
{
snakeHead->dir=SNAKE_DIR::DIR_DOWN;
}
}
return true;
}
//根据舌头移动方向,位移距离
void GameScene::gameLogc(float t){
//移动蛇头
switch (snakeHead->dir) {
case SNAKE_DIR::DIR_DOWN:
snakeHead->moveTo(snakeHead->px, snakeHead->py-30);
break;
case SNAKE_DIR::DIR_UP:
snakeHead->moveTo(snakeHead->px, snakeHead->py+30);
break;
case SNAKE_DIR::DIR_LEFT:
snakeHead->moveTo(snakeHead->px-30, snakeHead->py);
break;
case SNAKE_DIR::DIR_RIGHT:
snakeHead->moveTo(snakeHead->px+30, snakeHead->py);
break;
}
//移动身体
for(int i=allBody.size()-1;i>=0;i--)
{
SNode * nowbody=allBody.at(i);
switch (nowbody->dir) {
case SNAKE_DIR::DIR_DOWN:
nowbody->moveTo(nowbody->px, nowbody->py-30);
break;
case SNAKE_DIR::DIR_UP:
nowbody->moveTo(nowbody->px, nowbody->py+30);
break;
case SNAKE_DIR::DIR_LEFT:
nowbody->moveTo(nowbody->px-30, nowbody->py);
break;
case SNAKE_DIR::DIR_RIGHT:
nowbody->moveTo(nowbody->px+30, nowbody->py);
break;
}
if (i==0) {
allBody.at(0)->dir=snakeHead->dir;
}else
{
nowbody->dir=allBody.at(i-1)->dir;//等于上一个方向
}
}
//碰撞判断
if (snakeHead->px==food->px&&snakeHead->py==food->py)
{
int row=rand()%20;
int col=rand()%20;
this->food->moveTo(col*30, row*30);
SNode * newBody=SNode::create();
newBody->setColor(Color3B::BLUE);
//新的身体在蛇的尾部
if (allBody.size()==0)
{
switch (snakeHead->dir)
{
case SNAKE_DIR::DIR_DOWN:
newBody->moveTo(snakeHead->px, snakeHead->py+30);
break;
case SNAKE_DIR::DIR_UP:
newBody->moveTo(snakeHead->px, snakeHead->py-30);
break;
case SNAKE_DIR::DIR_LEFT:
newBody->moveTo(snakeHead->px+30, snakeHead->py);
break;
case SNAKE_DIR::DIR_RIGHT:
newBody->moveTo(snakeHead->px-30, snakeHead->py);
break;
}
allBody.pushBack(newBody);
newBody->dir=snakeHead->dir;
}
else
{
SNode * lastBody=allBody.at(allBody.size()-1);
switch (lastBody->dir) {
case SNAKE_DIR::DIR_DOWN:
newBody->moveTo(lastBody->px, lastBody->py+30);
break;
case SNAKE_DIR::DIR_UP:
newBody->moveTo(lastBody->px, lastBody->py-30);
break;
case SNAKE_DIR::DIR_LEFT:
newBody->moveTo(lastBody->px+30, lastBody->py);
break;
case SNAKE_DIR::DIR_RIGHT:
newBody->moveTo(lastBody->px-30, lastBody->py);
break;
}
allBody.pushBack(newBody);
newBody->dir=lastBody->dir;
}
this->getChildByTag(100)->addChild(newBody);
}
}
bool SNode::init(){
if(!Node::init())
{
return false;
}
this->sprite=LayerColor::create(Color4B::RED);
this->sprite->setContentSize(Size(30,30));
this->addChild(sprite);
return true;
}
void SNode::setColor(Color3B color){
this->sprite->setColor(color);
}
void SNode::moveTo(int x,int y){
this->px=x;
this->py=y;
this->sprite->setPosition(Vec2(x,y));
}
总结:文中利用DrawNode绘制方格背景,利用schedule移动蛇头。