本文原创:转载请注明地址:http://blog.csdn.net/zp522123428/article/details/29357851
一、coco2dx-3.0环境搭建
这个网上很多参考教程也属于基础部分我就不再敷述,这里给大家提供csdn博客上的大家可以参考一下,我大概看了一下比较全面了;
参考地址:http://blog.csdn.net/aa4790139/article/details/8086635
二、coco2dx-3.0下创建项目
1、进入coco2dx-3.0的目录下,检查环境。--》在doc下执行setup.py
如果环境正确会显示如下内容:
2、创建工程
在doc下执行如下语句即可:
cocos new FlappyBird -p com.zz.hello -l cpp -d f:\cocos2d-x-3.0\project
FlappyBird为工程名称
com.zz.hello为包路径
f:\cocos2d-x-3.0\project为创建工程路径(一定是在3.0文件夹下,不然会有莫名其妙的错误哦)
3、执行完成之后会在对应路径下有相应的工程工程目录大概入下:
三、编码
新建一个Scene类
- #include "cocos2d.h"
- #include "Obstacle.h"
-
- class FlyBirdGame :public cocos2d::Layer
- {
- public:
- static cocos2d::Scene* createScene();
- virtual bool init();
- CREATE_FUNC(FlyBirdGame);
- void initUI();
- void gameStart(Object* pSender);
- void update(float time);
- Obstacle* obstacle;
- };
- #include "cocos2d.h"
- #include "FlyBirdGame.h"
- #include "resource.h";
-
- USING_NS_CC;
-
- Scene* FlyBirdGame::createScene()
- {
- auto scene = Scene::create();
- auto layer = FlyBirdGame::create();
- scene->addChild(layer);
- return scene;
- }
-
- bool FlyBirdGame::init()
- {
- if (!Layer::init())
- {
- return false;
- }
- initUI();
- return true;
- }
initUI里是一些UI初始化方法:
-
- auto winSize = Director::getInstance()->getVisibleSize();
-
-
- auto bg = Sprite::create(bird_bg);
- bg->setPosition(winSize.width / 2, winSize.height / 2);
- bg->setScale(winSize.width / bg->getContentSize().width, winSize.height / bg->getContentSize().height);
- this->addChild(bg);
-
-
- auto startBtn = MenuItemImage::create(bird_start_btn, bird_start_btn_pressed, CC_CALLBACK_1(FlyBirdGame::gameStart, this));
- auto menu = Menu::create(startBtn, NULL);
- menu->setTag(100);
- this->addChild(menu);
-
-
- auto hero = Sprite::create(bird_hero);
- hero->setPosition(winSize.width / 5, winSize.height*0.8);
- hero->setVisible(false);
- hero->setTag(200);
- this->addChild(hero);
开始游戏按钮绑定的gameStart方法:
- void FlyBirdGame::gameStart(Object* pSender)
- {
- auto btn = this->getChildByTag(100);
- btn->setVisible(false);
- auto hero = this->getChildByTag(200);
- Size win = Director::getInstance()->getWinSize();
- obstacle->gameStart = true;
- }
隐藏开始按钮,显示小鸟,水管开始移动
还有更新方法:
- scheduleUpdate();
- void FlyBirdGame::update(float time)
- {
- obstacle->update();
- }
=======================================
水管类:Obstacle.cpp
update方法里判断游戏是游戏是否开始
- void Obstacle::update()
- {
- if (gameStart == false)
- return;
- addCount++;
- if (addCount == 60)
- {
- addOne(0);
- addCount = 0;
- }
- for (int i = obstacleList->count() - 1; i >= 0; i--)
- {
- auto s = (Sprite*)obstacleList->getObjectAtIndex(i);
- s->setPositionX(s->getPositionX() - 3);
- if (s->getPositionX() < -s->getContentSize().width / 2)
- {
- obstacleList->removeObjectAtIndex(i);
- this->removeChild(s);
- }
- }
- }
水管类的更新方法里,每60帧(1秒)添加一对水管
并且遍历水管列表
出边界的化销毁
接下来是addOne方法:添加水管方法:
- void Obstacle::addOne(int offsetX)
- {
- Size size = Director::getInstance()->getWinSize();
- auto sprite = Sprite::create(bird_obstacle_up);
- Size spriteSize = sprite->getContentSize();
- obstacleList->addObject(sprite);
- this->addChild(sprite);
- auto sprite2 = Sprite::create(bird_obstacle_down);
- Size spriteSize2 = sprite->getContentSize();
- obstacleList->addObject(sprite2);
- this->addChild(sprite2);
-
- int maxUpY = size.height + spriteSize.height / 4;
- int minUpY = size.height - spriteSize.height / 4;
- int y1 = CCRANDOM_0_1()*(maxUpY - minUpY) + minUpY;
- int maxDownY = spriteSize.height / 4;
- int minDownY = -spriteSize.height / 4;
- int y2 = CCRANDOM_0_1()*(maxDownY - minDownY) + minDownY;
- if (y1 - y2 - spriteSize.height < 160)
- {
- y2 = y1 - spriteSize.height - 160;
- }
- sprite->setPosition(ccp(size.width + spriteSize.width / 2 + offsetX, y1));
- sprite2->setPosition(ccp(size.width + spriteSize2.width / 2 + offsetX, y2));
- }
这段代码比较凌乱,就是找到水管上下位置的范围
然后随机一下,并且保证上下连个水管有个最小的距离
效果如下:
=============================
此时的游戏还没触摸和碰撞逻辑
马上添加:(刚才抽空玩了把魔方:五阶的我只能搞定一个面,虽然有官方规律但是那样好像比的是记忆力)
听说cocos2dx3.0的事件监听方式改变了
先在FlyBirdGame.h里声明俩方法:
- void onTouchesEnded(const vector& touches, Event* event);
- void onTouchesBegan(const vector& touches, Event* event);
在cpp文件的初始化里绑定事件:
-
- auto dispatcher = Director::getInstance()->getEventDispatcher();
- auto listener = EventListenerTouchAllAtOnce::create();
- listener->onTouchesEnded = CC_CALLBACK_2(FlyBirdGame::onTouchesEnded, this);
- listener->onTouchesBegan = CC_CALLBACK_2(FlyBirdGame::onTouchesBegan, this);
- dispatcher->addEventListenerWithSceneGraphPriority(listener, this);
在两个事件方法里改变标记位,在小鸟的update方法里根据这个标记位来改变高度
=============================
碰撞检测:
记得cocos2dx3.0以前都是自己写一个根据CCSprite获取CCRect的方法
现在直接用 Sprite的getBoundingBox()方法
不过如果有特殊需求还得自己写,比如想扩大或缩小碰撞区域
在FlyBirdGame.cpp文件里
update算主逻辑方法:
- void FlyBirdGame::update(float time)
- {
- auto winSize = Director::getInstance()->getVisibleSize();
- auto hero = this->getChildByTag(TAG_HERO);
- Rect rHero = ((Sprite*)hero)->getBoundingBox();
-
- switch (GAME_STATUS)
- {
- case GAME_STATUS_PLAYING:
- obstacle->update();
-
- if (isFlying&&hero->getPositionY() < winSize.height)
- {
- hero->setPositionY(hero->getPositionY() + v);
- }
- else if (hero->getPositionY()>0)
- {
- hero->setPositionY(hero->getPositionY() - v);
- }
-
- for (int i = 0; i < obstacle->obstacleList->count(); i++)
- {
- Sprite* obstacleRect = (Sprite*)obstacle->obstacleList->getObjectAtIndex(i);
- bool pia = rHero.intersectsRect(obstacleRect->getBoundingBox());
- if (pia == true)
- {
- GAME_STATUS = GAME_STATUS_GAME_OVER;
- break;
- }
- }
- break;
- case GAME_STATUS_GAME_OVER:
- CCLog("over");
- this->getChildByTag(TAG_OVER)->setVisible(true);
- break;
- case GAME_STATUS_RESTART:
-
- "white-space: pre;"> obstacle->removeAllChildren();
- obstacle->obstacleList->removeAllObjects();
-
- hero->setPosition(winSize.width / 5, winSize.height*0.8);
-
- auto btn = this->getChildByTag(TAG_START_BTN);
- btn->setVisible(true);
-
- auto logo = this->getChildByTag(TAG_LOGO);
- logo->setVisible(true);
- break;
- }
- }
根据游戏状态处理。
碰撞检测方法:intersectsRect
bool pia = rHero.intersectsRect(obstacleRect->getBoundingBox());
if (pia == true)
{
GAME_STATUS = GAME_STATUS_GAME_OVER;
break;
}
游戏状态定义在 resource.h 文件里
- static const int GAME_STATUS_START = 10;
- static const int GAME_STATUS_PLAYING = 20;
- static const int GAME_STATUS_GAME_OVER = 30;
- static const int GAME_STATUS_RESTART = 40;
整个游戏流程已经通了:开始,游戏,结束,重新开始
接下来可以优化很多很多东西
===================================================
真搞不懂为什么和弦要那么别扭的按法
相较之下
还是代码简单
继续优化
添加小鸟动画:
添加到resource.h 文件中等待使用
也可以直接在cpp文件中用不过骨头习惯了资源统一管理
- Animation* an = Animation::create();
- an->addSpriteFrameWithFileName(bird_hero);
- an->addSpriteFrameWithFileName(bird_hero2);
- an->addSpriteFrameWithFileName(bird_hero3);
- an->setDelayPerUnit(0.5f / 3.0f);
- an->setLoops(-1);
- Animate* anim = Animate::create(an);
- hero->runAction(anim);
F5运行看效果,确实生动一点了
=========================================================
分辨率问题:
在AppDelegate.cpp入口方法中加入:
CCEGLView::sharedOpenGLView()->setDesignResolutionSize(320, 480, kResolutionExactFit);
其中320,480是游戏設計時的分辨率。
后面参数介绍如下“:
=============================================================
分数的显示:
之前的几个demo都是使用本办法显示的特殊数字:一排图片然后根据每位上的数字决定显示哪个图片
本来打算自己封装个方法,再一看,有更简单的:
从自带的demo里找点合适的字体资源,拷贝到fonts文件夹下
记住把fnt和对应的png都拷贝过来
然后
- auto label1 = LabelBMFont::create("123456", "fonts/futura-48.fnt");
- addChild(label1);
- label1->setPosition(Point(win.width / 2, win.height / 2));
================================================
分数显示ok了,下面看下分数逻辑
当小鸟的坐标等于柱子的坐标时,score+1(因为是上下俩柱子对象,所以除以2显示)
别忘记判断时要让小鸟飞过柱子,而不是跟柱子纵轴对齐
相关代码在检测碰撞时添加:
-
- for (int i = 0; i < obstacle->obstacleList->count(); i++)
- {
- Sprite* obstacleSprite = (Sprite*)obstacle->obstacleList->getObjectAtIndex(i);
- bool pia = rHero.intersectsRect(obstacleSprite->getBoundingBox());
- if (pia == true)
- {
- GAME_STATUS = GAME_STATUS_GAME_OVER;
- break;
- }
- int oPosX = obstacleSprite->getPositionX() + obstacleSprite->getContentSize().width / 2;
- int heroX = hero->getPositionX() - hero->getContentSize().width;
- if (oPosX == heroX)
- {
- score++;
- auto scoreSprite = (LabelBMFont*)this->getChildByTag(TAG_SCORE);
- String* s = String::createWithFormat("%d", score / 2);
- scoreSprite->setString(s->getCString());
- }
- }
======================================================
增加下游戏难度
之所以死不了是因为小鸟的速度改变的很均匀
因为触摸事件只改变速度 不改变加速度
-
- if (hero->getPositionY() > 0 && hero->getPositionY() < winSize.height)
- {
- velocity -= gravity;
- hero->setPositionY(hero->getPositionY() + velocity);
- }
-
-
-
-
-
-
-
-
-
将之前的速度改变方式修改一下,每次点击给一个向上的速度,然后重力向下,这样就类似原游戏的跳跃感了
至于数值可以继续微调来加大游戏难度
====================================================
如果要在捕捉返回键可在init方法内加
//注册捕捉监听
auto listenerkeyPad = EventListenerKeyboard::create();
listenerkeyPad->onKeyReleased = CC_CALLBACK_2(FlyBirdGame::onKeyReleased, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listenerkeyPad, this);
然后定义一个返回键响应方法(我这里是做的直接退出的响应,但让你可以改成别的响应,如提示退出等等)
//捕捉监听
void FlyBirdGame::onKeyReleased(EventKeyboard::KeyCode keycode, cocos2d::Event *event)
{
if (keycode == EventKeyboard::KeyCode::KEY_BACKSPACE) //返回
{
CCLOG("back up");
int iManSceneTag = CCDirector::sharedDirector()->getRunningScene()->getTag();//如果是主场景,则退出;
CCDirector::sharedDirector()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
exit(0);
#endif
}
else if (keycode == EventKeyboard::KeyCode::KEY_MENU)
{
}
}
===========================================上面的主场景中没有加入声音=======下面把声音部分加进去============
没声音确实有点尴尬:
3.0加入背景音乐没多大变化
#include "SimpleAudioEngine.h"
//添加命名空间;
using namespace cocos2d::extension;
//音效----ogg的在win32下是没效果的在真机上就有了。
SimpleAudioEngine::sharedEngine()->preloadBackgroundMusic("music/bg.ogg");
SimpleAudioEngine::sharedEngine()->playBackgroundMusic("music/bg.ogg", true);//播放背景音乐
// 设置默认音量 、、这个可以不设置有默认值的
SimpleAudioEngine::sharedEngine()->setEffectsVolume(1);
SimpleAudioEngine::sharedEngine()->setBackgroundMusicVolume(1);
// 暂停背景音乐、、刚刚进来是没播放背景音乐的当然你可以不要这句进来就开始播放
SimpleAudioEngine::sharedEngine()->pauseBackgroundMusic();
在判断失败的地方加入音效:
SimpleAudioEngine::sharedEngine()->pauseBackgroundMusic();
SimpleAudioEngine::sharedEngine()->playEffect("music/shibai.ogg");
在你想要音效的地方都可以加上;
==============================华丽的分割线=========================
===============到这里在win32下基本能运行了。大概逻辑也清晰了=======================
===============接下来看看android下======================
1、第一步当然是要编译一下咯可直接在doc下编译。或者你想高大上在cygwin下也一样哈哈
进入proj.android下执行python build_native.py如下图(我的是编译过的所以没那么多,最开始编译会比较慢)没报错大功告成(报错的话具体问题具体问谷哥和度娘了)
()
2、在eclipse下导入工程下面的project.android
然后就可以run了
效果图当然我是换了一下背景和bird哈哈你们也可以换自己喜欢的人物