cocos2d-x 3.0 贪吃蛇开发的几点经验

对cocos2d-x的开发来说,我是纯新手了。因为上周五(4月18)才开使接触cocos2d,下载开发包,配置环境,编译和运行例子…
遇到问题,不断google,look look ,然后再think think ,然后再try try。很幸运的是,在这个繁琐的过程中,偶然发现到了这里竟然有编程大战!哈,有代码可以修改、学习,也有大家做的贪吃蛇教程,更方便了进一步地学习。
看了看活动的截止日期,到4月21日,也就是今天,当时算了下时间,觉得还来到及,果断参加!

一开始下载了活动所给的书中教程,基本能理解思路,于是开工!因为之前对cocos2d 的2.x版本根本没接触过,修改到3.0版遇到了很多问题,编译不能通过,根据大家的教程和教程的部分源码,改了其中一些问题,但最后还是无法编译通过。后来自己想,既然如此,干脆放弃修改书中教程,与其研究两者差别不如干脆直接用3.0开发!

开发前,因为对cocos2d-x不熟,在网上找了一篇教程 《如何使用cocos2d-x 3.0来做一个简单的iphone游戏教程》 http://www.ityran.com/archives/6175
这篇教程非常好,我按照教程的内容完整的做了一遍,可以说这一遍对cocos2d-x有了一个初步、完整的印象,对项目的各部分内容也基本了解了。很感谢这篇文章的译者,他不仅翻译了英文原文,而且将内容都改为cocos2d-x 3.0的了。(如果大家想学习这个教程,里面有一处需要改动,把Object* 改为 Ref * 就行了)

这次活动大家都提交了很好的教程,我基本上把每个教程都看了,我主要参考了这篇教程 http://www.cocoachina.com/bbs/read.php?tid=197882 。作者从写游戏的过程和框架入手,讲解的很详细,很好。
另外,这篇教程 http://www.cocoachina.com/bbs/read.php?tid=197630 谈到做这个项目的编程中涉及到的cocos2d-x 3.0和C++11新增加的一些内容,也很好。
有了教程和范例,一步步做,就方便多了。
下面谈几点经验:

1、可以用方向链表示各节点移动
贪吃蛇的难点在于蛇的移动。把蛇看成是有节点构成的,用Vector来放这些节点就容易了。

class SnakeNode :public cocos2d::Ref
{
public:
int x;
int y;
cocos2d::Sprite* sprite;
};

cocos2d::Vector<SnakeNode*> snake;

节点中我只留了x,y坐标和精灵,方向放在另一个Vector里了。
class DirNode :public cocos2d::Ref
{
public:
int dir;
};

cocos2d::Vector<DirNode*> dirChain;//方向链

用dirChain把每一步的方向都保存好,这样可以实现节点的按像素移动。
这个设计和书中原有的设计不同。

2、声音的加入
游戏中的声音会给游戏增色不少。因为大家教程中都没加声音,于是网上搜了下,找到了实现的方法。

在程序中加入头文件
#include “SimpleAudioEngine.h”

先定义需要用的文件

#define BACKGROUND_SOUND “background.wav”
#define EAT_SOUND “effect.wav”
#define GAMEOVER_SOUND “gameover.wav”

用下面代码设置音量并播放背景音乐
CocosDenshion::SimpleAudioEngine::getInstance()->setBackgroundMusicVolume(1.0f);
CocosDenshion::SimpleAudioEngine::getInstance()->playBackgroundMusic(BACKGROUND_SOUND);

蛇吃到蛋时可以用下面代码播放音效
CocosDenshion::SimpleAudioEngine::getInstance()->playEffect(EAT_SOUND);

游戏结束时可以用下面代码停止背景音乐和全部音效
CocosDenshion::SimpleAudioEngine::getInstance()->stopBackgroundMusic();
CocosDenshion::SimpleAudioEngine::getInstance()->stopAllEffects();

3、分数的设计
这个比较简单,最高分我是用外部变量实现的,不知道有没有更好的方法,比如变量放到第一个界面的类里(class HelloWorld : public cocos2d::Layer)。
static int highScore=0;

class GameScene : public cocos2d::Layer
{
public:
int score;

}

在开始界面如果有最高分,就显示最高分

if(highScore>0){
char buff = {0};
sprintf(buff,“High Score: %d”,highScore);
auto labelHighScore = Label::createWithSystemFont(buff, “Arial”, 32);
labelHighScore->setPosition(Point(visibleSize.width/2,
visibleSize.height-320));
this->addChild(labelHighScore);
}

当蛇吃到蛋时加分
score+=1;//增加分数
if(score>highScore) highScore=score;

4、手势的处理
书中是根据点击屏幕位置来进行判断并进行移动。我觉得用手势更好,向哪里滑动就移向哪里。
用touch_x、touch_x保留onTouchBegan时的位置,然后在onTouchEnded时完成手势的判断。

bool GameScene::init()
{

//建立触摸监听
auto listener = EventListenerTouchOneByOne::create();
listener->onTouchBegan = CC_CALLBACK_2(GameScene::onTouchBegan, this);
listener->onTouchEnded = CC_CALLBACK_2(GameScene::onTouchEnded, this);
this->_eventDispatcher->addEventListenerWithSceneGraphPriority(listener,this);

}

bool GameScene::onTouchBegan( Touch* touch, Event* event )
{
Point touchPoint = touch->getLocation();
touch_x= (int)touchPoint.x;
touch_y= (int)touchPoint.y;
return true;
}
void GameScene::onTouchEnded( Touch* touch, Event* event )
{
Point touchPoint = touch->getLocation();
int x = (int)touchPoint.x;
int y = (int)touchPoint.y;
int x1=touch_x;
int y1=touch_y;
int dir;

if (abs(y - y1) > abs(x - x1)) { 
    if (y > y1) dir = DIR_DEF::UP; 
    else dir = DIR_DEF::DOWN; 
} 
else { 
    if (x > x1) 
        dir = DIR_DEF::RIGHT; 
    else dir = DIR_DEF::LEFT; 
} 
snakeMove(dir); 

}

5、键盘的处理
因为cocos2d-x可以实现跨平台开发,手机屏幕都是触摸屏,但电脑来说,键盘是必须的。
与上面代码类似,用监听方式来处理。

//建立键盘监听 
auto listenerKeyboard = EventListenerKeyboard::create(); 
listenerKeyboard->onKeyPressed = CC_CALLBACK_2(GameScene::onKeyPressed, this); 
listenerKeyboard->onKeyReleased = CC_CALLBACK_2(GameScene::onKeyReleased, this); 
_eventDispatcher->addEventListenerWithSceneGraphPriority(listenerKeyboard, this); 

// Implementation of the keyboard event callback function prototype
void GameScene::onKeyPressed(EventKeyboard::KeyCode keyCode, Event* event)
{
log(“Key with keycode %d pressed”, keyCode);
if(keyCode==EventKeyboard::KeyCode::KEY_LEFT_ARROW) snakeMove(DIR_DEF::LEFT);
else if(keyCode==EventKeyboard::KeyCode::KEY_UP_ARROW) snakeMove(DIR_DEF::UP);
else if(keyCode==EventKeyboard::KeyCode::KEY_RIGHT_ARROW) snakeMove(DIR_DEF::RIGHT);
else if(keyCode==EventKeyboard::KeyCode::KEY_DOWN_ARROW) snakeMove(DIR_DEF::DOWN);

}
void GameScene::onKeyReleased(EventKeyboard::KeyCode keyCode, Event* event)
{
}

我一开始把keyCode在控制台显示出来,然后记下那些数字,发现如果用数字判断编译不能通过,比如 if(keyCode==4178)
后来google 了好久才找到keyCode的常量表示。

后记:
今天中午前完成了程序的全部内容,下午实现了在ios平台的编译,Mac OS桌面和我的iPode Touch 4都可以玩这个游戏了。晚上九点多,总算完成了android平台的编译,附件就是android版的,下载后把zip改成apk就能运行了(另一个是ipa的程序)。
另外,程序中用到的图片和声音资源来自于另一个贪吃蛇游戏,这里仅作为教程使用,特此说明。

这几天的实践,让我感觉用cocos2d-x 3.0开发跨平台游戏真的是很方便!而且跨平台的功能让人印象深刻!

org.cocos2d-x.SnakeGame-iOS.zip (5485 KB)

不错不错 ~~不过啊~~~你们为什么都没仔细看帖啊 源代码别发啊 发给偶尔由他统一发啊。。。不过还是支持楼主的分享

楼主你好 为什么我按例子里的键盘代码写了后没反应呢

我在Game::init()里写的
    auto keyBoardEvent = EventListenerKeyboard::create();

    keyBoardEvent->onKeyPressed = CC_CALLBACK_2(Game::onKeyPressed,this);
    keyBoardEvent->onKeyReleased = CC_CALLBACK_2(Game::onKeyReleased,this);

    _eventDispatcher->addEventListenerWithSceneGraphPriority(keyBoardEvent,this);


void Game::onKeyPressed(EventKeyboard::KeyCode keyCode, Event* event)
{
    MessageBoxA(NULL,"test","KeyBoard",MB_OK);
}
void Game::onKeyReleased(EventKeyboard::KeyCode keyCode, Event* event)
{
    MessageBoxA(NULL,"test","KeyBoard",MB_OK);
}


```