最终效果图:
环境版本:cocos2d-x-3.3beta0 使用内置的物理引擎
游戏主场景
//
// HeroScene.h
// 01_cocos2d-x
//
// Created by beyond on 14-10-6.
//
//
#ifndef __HeroScene_SCENE_H__
#define __HeroScene_SCENE_H__
#include "cocos2d.h"
#include "GameCtrl.h"
// 继承自 有颜色的Layer
class HeroScene : public cocos2d::LayerColor
{
private:
// 屏幕尺寸
Size winSize;
// 数组 不同的层 对应不同的控制器
cocos2d::Vector<GameCtrl*> gameCtrlArr;
public:
// 宏定义的Create方法,内部会调用init方法
CREATE_FUNC(HeroScene);
// 供外界调用的 实例化场景的方法
static cocos2d::Scene* createScene();
// 初始化方法
virtual bool init();
// 时钟方法
// 在场景的时钟方法中,更新\控制 每一个游戏控制器的时钟方法
virtual void update(float dt);
};
#endif // __HeroScene_SCENE_H__
//
// HeroScene.h
// 01_cocos2d-x
//
// Created by beyond on 14-10-6.
//
//
#include "HeroScene.h"
#include "GameOverScene.h"
USING_NS_CC;
#pragma mark - 生命周期方法
Scene* HeroScene::createScene()
{
// 使用cocos2d 内置的物理引擎
auto scene = Scene::createWithPhysics();
// 显示 调试用的 刚体 边线
// scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);
// 调整重力加速度
scene->getPhysicsWorld()->setGravity(Vec2(0,-1000));
// 标准代码 通过静态的create方法创建Layer,添加到场景,并返回场景
auto layer = HeroScene::create();
scene->addChild(layer);
return scene;
}
// 实例化特有的对象
bool HeroScene::init()
{
// 创建一个白色的Layer
if ( !LayerColor::initWithColor(Color4B(255,255,255)) ) return false;
// 屏幕尺寸
winSize = Director::getInstance()->getVisibleSize();
log("winSize:%f,%f",winSize.width,winSize.height);
// 创建2个 GameCtrl (2层)
gameCtrlArr.insert(0,GameCtrl::create(this,30));
if(rand()%2 == 0){
gameCtrlArr.insert(0,250));
}
// 开启消息调度
scheduleUpdate();
// ********************************************
// 物理碰撞检测 「PhysicsContact」
auto listener = EventListenerPhysicsContact::create();
// 开始碰撞 游戏结束
listener->onContactBegin = [this](PhysicsContact & contact){
// 取消 消息调度
this->unscheduleUpdate();
// 切换至Game Over场景
Director::getInstance()->replaceScene(GameOverScene::createScene());
return true;
};
// 向事件分发器,注册listener
Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraPHPriority(listener,this);
// ********************************************
// 用户单点触摸 jump high 【TouchOneByOne】
auto touchListener = EventListenerTouchOneByOne::create();
// 开始触摸 原地 跳一下
touchListener->onTouchBegan = [this](Touch * t,Event * e){
// 每一个游戏控制器 都执行一下 方法
for (auto it = gameCtrlArr.begin(); it!=gameCtrlArr.end(); it++)
{
// 解引用 就可以获得数组成员对象了
// 如果 是点在自己的那一层 才执行 跳高动作
if ((*it)->hitTestPoint(t->getLocation()))
{
(*it)->onUserTouch();
break;
}
}
return false;
};
// 向事件分发器,注册listener
Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraPHPriority(touchListener,this);
return true;
}
#pragma mark - 时钟方法
void HeroScene::update(float dt)
{
// 在场景的时钟方法中,更新\控制 每一个游戏控制器的时钟方法
for (auto it = gameCtrlArr.begin(); it!=gameCtrlArr.end(); it++)
{
// 解引用 就可以获得数组成员对象了
// 每一个游戏控制器 开启时钟方法
(*it)->startUpdate(dt);
}
}
游戏结束时的场景
//
// GameOverScene.h
// 01_cocos2d-x
//
// Created by beyond on 14-10-6.
//
//
#include <cocos2d.h>
#include "MainScene.h"
using namespace cocos2d;
// 继承自 有颜色的Layer
class GameOverScene:public LayerColor {
private:
Size winSize;
public:
// 供外界调用
static Scene* createScene()
{
auto s = Scene::create();
auto l = GameOverScene::create();
s->addChild(l);
return s;
};
// 宏定义的Create方法,内部会调用init方法
CREATE_FUNC(GameOverScene);
// 初始化,自己用
virtual bool init()
{
// 父类的init方法
LayerColor::initWithColor(Color4B::WHITE);
// 屏幕大小
winSize = Director::getInstance()->getVisibleSize();
// 创建一个Label
auto label = Label::create();
label->setString("Game Over");
label->setSystemFontSize(40);
label->setName("label");
label->setColor(Color3B::BLACK);
label->setPosition(winSize.width/2,winSize.height/2);
// 添加到Layer
addChild(label);
// 添加一个事件,点击 Label,返回到主场景的事件
// 2.触摸Label,开启 时钟updatePosition
// 实例化一个触摸监听器 对象
auto listener = EventListenerTouchOneByOne::create();
// 当触摸开始时,绑定一个闭包函数;
// 【】表示 要传入的外界对象,此处是this
// ()表示参数
listener->onTouchBegan = [this](Touch *t,Event *e){
// 如果 点击 了label,才每隔一秒执行一次 更新位置方法
Label *label =(Label *) e->getCurrentTarget()->getChildByName("label");
if (label->getBoundingBox().containsPoint(t->getLocation())) {
// 回到主场景
// 创建场景,自动释放 it's an autorelease object
auto scene = MainScene::createScene();
// 替换场景
Director::getInstance()->replaceScene(scene);
}
return false;
};
// 5、获取事件分发器,添加一个事件监听器,到this身上;即监听的是this对象【整个图层Layer】
Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraPHPriority(listener,this);
return true;
};
};
一个游戏控制器实例
对应一层子游戏
【
核心
】
//
// GameCtrl.h
// 01_cocos2d-x
//
// Created by beyond on 14-10-6.
//
//
#ifndef ___1_cocos2d_x__GameCtrl__
#define ___1_cocos2d_x__GameCtrl__
#include <cocos2d.h>
// 全屏的边框
#include "Boundary.h"
#include "Hero.h"
#include "Block.h"
USING_NS_CC;
// 继承自 Ref,就自动拥有了 释放机制
class GameCtrl:public Ref
{
private:
// 屏幕尺寸
Size winSize;
// 边界 边框,用成员变量记住,是因为 碰撞检测要用到
Boundary * boundary;
Hero * hero;
// 重要~~~Layer就相当于HeroScene场景,因为所有的子精灵 全添加到Layer中,所以需要传入Layer
// 成员变量记住(其他方法中要用到)
Layer * _layer;
float _positionY;
// 临时变量,用于累计 记录 流逝的时间
int tempTimeDelta;
// 总共的时间间隔 (即 时间delta累计到 该间隔时,创建并添加一个障碍物)
int totalIntervalTime;
private:
// 每添加一个新的障碍物之后,需重置 用于累计 记录 流逝的时间 的变量
void resetTempTimeDelta();
// 每隔 随机的时间,创建并添加一个障碍物
void addBlock();
public:
// 重要~~~这个Layer就相当于HeroScene场景,所以需要传入Layer
// 参数 就是在屏幕的y值
// 供外界
static GameCtrl* create(Layer *layer,float positionY);
// 自己初始化
virtual bool init(Layer * layer,float positionY);
// 供场景调用,让场景来 开启和关闭 游戏控制器 中的 时钟方法
void startUpdate(float dt);
// 当被用户触摸了 时侯调用,给英雄一个向上的速度
void onUserTouch();
bool hitTestPoint(Vec2 point);
};
#endif /* defined(___1_cocos2d_x__GameCtrl__) */
//
// GameCtrl.cpp
// 01_cocos2d-x
//
// Created by beyond on 14-10-6.
//
//
#include "GameCtrl.h"
// 重要~~~这个Layer就相当于HeroScene场景,所以需要传入Layer
// 参数 就是在屏幕的y值
// 供外界
GameCtrl* GameCtrl::create(cocos2d::Layer *layer,float positionY)
{
auto gameCtrl = new GameCtrl();
// 调用自己的init初始化,将参数 传递过去
gameCtrl->init(layer,positionY);
// 自动释放
gameCtrl->autorelease();
return gameCtrl;
}
// 自己初始化
bool GameCtrl::init(cocos2d::Layer *layer,float positionY)
{
// 成员变量记住,其他方法中 要用到
_layer = layer;
_positionY = positionY;
// 全屏
winSize = Director::getInstance()->getVisibleSize();
//**************************************
// 1、添加游戏的边框、边界
boundary = Boundary::create();
// 居中 (注意 不同的控制器,可能在不同的层 其y值不同 高度也不同)
boundary->setPosition(winSize.width/2,winSize.height/2+positionY);
// 全屏
boundary->setContentSize(winSize);
// 添加到Layer
layer->addChild(boundary);
//**************************************
// 2、添加地板 (不需要关联物理世界)
auto ground = Sprite::create();
ground->setColor(Color3B(0,0));
ground->setTextureRect(Rect(0,3));
// (注意 不同的控制器,可能在不同的层 其y值不同) 3 和1.5
ground->setPosition(winSize.width/2,1.5+positionY);
// 添加到Layer
layer->addChild(ground);
//**************************************
// 3、添加Hero
hero = Hero::create();
// (注意 不同的控制器,可能在不同的层 其y值不同)
hero->setPosition(50,hero->getContentSize().height/2+positionY);
// 添加到Layer
layer->addChild(hero);
// 每添加一个新的障碍物之后,需重置 用于累计 记录 流逝的时间 的变量
resetTempTimeDelta();
return true;
}
#pragma mark - 供外界场景调用
// 供场景调用,让场景来 开启和关闭 游戏控制器 中的 时钟方法
void GameCtrl::startUpdate(float dt)
{
// 临时变量,用于累计 记录 流逝的时间
tempTimeDelta++;
// 总共的时间间隔 (即 时间delta累计到 该间隔时,创建并添加一个障碍物)
if (tempTimeDelta >= totalIntervalTime)
{
// 每添加一个新的障碍物之后,需重置 用于累计 记录 流逝的时间 的变量
resetTempTimeDelta();
// 每隔 随机的时间,创建并添加一个障碍物
addBlock();
}
}
// 每添加一个新的障碍物之后,需重置 用于累计 记录 流逝的时间 的变量
void GameCtrl::resetTempTimeDelta()
{
tempTimeDelta = 0;
totalIntervalTime = (rand()%120) + 100;
}
// 创建 并 添加 障碍物 (在随机的 时间 间隔 之后 )
void GameCtrl::addBlock()
{
auto b = Block::create();
_layer->addChild(b);
// 注意 障碍物的y值是 和当前游戏控制器 自己的y值 相同的
// 即 block的半高 + 当前控制器自己的y
b->setPositionY(b->getContentSize().height/2 + _positionY);
}
#pragma mark - 触摸事件
// 当被用户触摸了 时侯调用,给英雄一个向上的速度
void GameCtrl::onUserTouch()
{
hero->getPhysicsBody()->setVelocity(Vec2(0,400));
}
bool GameCtrl::hitTestPoint(cocos2d::Vec2 point)
{
return boundary->getBoundingBox().containsPoint(point);
}
边框、边界
//
// Boundary.h
// 01_cocos2d-x
//
// Created by beyond on 14-10-6.
//
// 边框、边界,其大小和winSize一样
#ifndef __Boundary__
#define __Boundary__
#include <cocos2d.h>
USING_NS_CC;
class Boundary:public Node {
public:
// 宏定义 一个静态的create方法,内部会调用init方法
CREATE_FUNC(Boundary);
// 初始化方法
virtual bool init();
};
#endif /* defined(__Boundary__) */
//
// Boundary.h
// 01_cocos2d-x
//
// Created by beyond on 14-10-6.
//
// 边框、边界,其大小和winSize一样
#include "Boundary.h"
bool Boundary::init(){
// 父类的init方法,内部 直接返回一个true
Node::init();
// 960 * 640
Size winSize = Director::getInstance()->getVisibleSize();
// 设置Node大小 全屏
setContentSize(winSize);
// 设置物理刚体body,大小和winSize一样
setPhysicsBody(PhysicsBody::createEdgeBox(winSize));
return true;
}
Hero主角
//
// Hero.h
// 01_cocos2d-x
//
// Created by beyond on 14-10-6.
//
// 主角,继承自Sprite,奔跑的小人
#ifndef ___1_cocos2d_x__Hero__
#define ___1_cocos2d_x__Hero__
#include <cocos2d.h>
USING_NS_CC;
class Hero:public Sprite {
public:
// 宏,静态的create方法,内部会调用init方法
CREATE_FUNC(Hero);
virtual bool init();
};
#endif /* defined(___1_cocos2d_x__Hero__) */
//
// Hero.cpp
// 01_cocos2d-x
//
// Created by beyond on 14-10-6.
//
// 主角,奔跑的小人
#include "Hero.h"
#include "FlashTool.h"
bool Hero::init()
{
// 父类的init方法
Sprite::init();
// 执行 帧动画 一直奔跑 RepeatForever
runAction(RepeatForever::create(FlashTool::animateFromJsonFile("Hero.json",0.2f)));
// Json中的尺寸
Size s = Size(44,52);
// 精灵的大小
setContentSize(s);
// 设置物理世界的刚体body
setPhysicsBody(PhysicsBody::createBox(s));
// 刚体不允许 旋转
getPhysicsBody()->setRotationEnable(false);
// 重要~~~若想参与 碰撞,必须绑定一个碰撞标识
getPhysicsBody()->setContactTestBitmask(1);
return true;
}
障碍物
//
// Block.h
// 01_cocos2d-x
//
// Created by beyond on 14-10-6.
//
//
#ifndef ___1_cocos2d_x__Block__
#define ___1_cocos2d_x__Block__
#include <cocos2d.h>
USING_NS_CC;
class Block:public Sprite {
public:
// 宏,内部会调用init方法
CREATE_FUNC(Block);
virtual bool init();
// 时钟方法,内部会 让 障碍物不断地向左移动
virtual void update(float dt);
};
#endif /* defined(___1_cocos2d_x__Block__) */
//
// Block.cpp
// 01_cocos2d-x
//
// Created by beyond on 14-10-6.
//
//
#include "Block.h"
bool Block::init()
{
// 父类的init方法
Sprite::init();
// 屏幕大小
Size winSize = Director::getInstance()->getVisibleSize();
// 放在屏幕的外边
setPositionX(winSize.width);
// 黑色 障碍物
setColor(Color3B(0,0));
Size size = Size((rand()%20)+5,(rand()%30)+10);
// 随机生成 不同大小的 障碍物
setContentSize(size);
// 黑色的方块区域
setTextureRect(Rect(0,size.width,size.height));
// ***************************************
// 设置 物理刚体
setPhysicsBody(PhysicsBody::createBox(size));
// 不是动态的刚体 即:是静态的刚体
getPhysicsBody()->setDynamic(false);
// 重要~~~若想参与 碰撞,必须绑定一个碰撞标识
getPhysicsBody()->setContactTestBitmask(1);
// ***************************************
// 开启时钟方法
scheduleUpdate();
return true;
}
#pragma mark - 时钟方法
// 时钟方法,内部会 让 障碍物不断地向左移动
void Block::update(float dt){
this->setPositionX(getPositionX()-8);
// 移动到屏幕外边时,就停止消息调度,并且移除
if (getPositionX()<0)
{
unscheduleUpdate();
removeFromParent();
}
}
//
// FlashTool.h
// 01_cocos2d-x
//
// Created by beyond on 14-10-6.
//
//
#ifndef ___1_cocos2d_x__FlashTool__
#define ___1_cocos2d_x__FlashTool__
#include <cocos2d.h>
USING_NS_CC;
class FlashTool {
public:
// 通过解析flash cc 导出的Json文件+大图片,生成一个Animate对象,用于执行序列帧动画
static Animate * animateFromJsonFile(std::string jsonFile,float delayPerUnit);
};
#endif /* defined(___1_cocos2d_x__FlashTool__) */
//
// FlashTool.cpp
// 01_cocos2d-x
//
// Created by beyond on 14-10-6.
//
//
#include "FlashTool.h"
// Json解析 使用cocos2d 内置的rapidJson库
#include <json/document.h>
// 通过解析flash cc 导出的Json文件+大图片,用于执行序列帧动画
Animate * FlashTool::animateFromJsonFile(std::string jsonFile,float delayPerUnit)
{
// 文档 对象
rapidjson::Document doc;
// FileUtils工具类 读入json文件
std::string fileContent = FileUtils::getInstance()->getStringFromFile(jsonFile);
//
fileContent.erase(0,fileContent.find_first_of('{'));
// 标记默认为 0,开始解析
doc.Parse<0>(fileContent.c_str());
// 得到大图片的 图片名
std::string imgFileName = doc["Meta"]["image"].GetString();
auto &frames = doc["frames"];
// 精灵帧缓存
auto sfc = SpriteFrameCache::getInstance();
// 容器用于 存放所有的 动画帧
Vector<AnimationFrame*> animFrames;
// 遍历,裁剪,创建,添加到容器
for (auto m=frames.MemberonBegin(); m!=frames.MemberonEnd(); m++) {
auto frameName = m->name.GetString();
auto & frameProperties = m->value["frame"];
auto & spriteSourceSize = m->value["spriteSourceSize"];
auto sf = sfc->getSpriteFrameByName(frameName);
if (!sf) {
sf = SpriteFrame::create(imgFileName,Rect(frameProperties["x"].GetInt(),frameProperties["y"].GetInt(),frameProperties["w"].GetInt(),frameProperties["h"].GetInt()),m->value["rotated"].GetBool(),Vec2(spriteSourceSize["x"].GetInt(),spriteSourceSize["y"].GetInt()),Size(spriteSourceSize["w"].GetInt(),spriteSourceSize["h"].GetInt()));
sfc->addSpriteFrame(sf,frameName);
}
animFrames.pushBack(AnimationFrame::create(sf,delayPerUnit,ValueMapNull));
}
// 生成用于Action的Animate
Animation * animation = Animation::create(animFrames,delayPerUnit);
return Animate::create(animation);
}
{"frames": {
"hero0000":
{
"frame": {"x":0,"y":0,"w":44,"h":52},"rotated": false,"trimmed": false,"spriteSourceSize": {"x":0,"sourceSize": {"w":44,"h":52}
},"hero0001":
{
"frame": {"x":44,"w":42,"trimmed": true,"spriteSourceSize": {"x":2,"hero0002":
{
"frame": {"x":86,"hero0003":
{
"frame": {"x":0,"y":52,"hero0004":
{
"frame": {"x":42,"h":52}
}},"Meta": {
"app": "Adobe Flash Professional","version": "13.1.0.226","image": "Hero.png","format": "RGBA8888","size": {"w":128,"h":128},"scale": "1"
}
}
// // HeroScene.h // 01_cocos2d-x // // Created by beyond on 14-10-6. // // #ifndef __HeroScene_SCENE_H__ #define __HeroScene_SCENE_H__ #include "cocos2d.h" #include "GameCtrl.h" // 继承自 有颜色的Layer class HeroScene : public cocos2d::LayerColor { private: // 屏幕尺寸 Size winSize; // 数组 不同的层 对应不同的控制器 cocos2d::Vector<GameCtrl*> gameCtrlArr; public: // 宏定义的Create方法,内部会调用init方法 CREATE_FUNC(HeroScene); // 供外界调用的 实例化场景的方法 static cocos2d::Scene* createScene(); // 初始化方法 virtual bool init(); // 时钟方法 // 在场景的时钟方法中,更新\控制 每一个游戏控制器的时钟方法 virtual void update(float dt); }; #endif // __HeroScene_SCENE_H__
// // HeroScene.h // 01_cocos2d-x // // Created by beyond on 14-10-6. // // #include "HeroScene.h" #include "GameOverScene.h" USING_NS_CC; #pragma mark - 生命周期方法 Scene* HeroScene::createScene() { // 使用cocos2d 内置的物理引擎 auto scene = Scene::createWithPhysics(); // 显示 调试用的 刚体 边线 // scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL); // 调整重力加速度 scene->getPhysicsWorld()->setGravity(Vec2(0,-1000)); // 标准代码 通过静态的create方法创建Layer,添加到场景,并返回场景 auto layer = HeroScene::create(); scene->addChild(layer); return scene; } // 实例化特有的对象 bool HeroScene::init() { // 创建一个白色的Layer if ( !LayerColor::initWithColor(Color4B(255,255,255)) ) return false; // 屏幕尺寸 winSize = Director::getInstance()->getVisibleSize(); log("winSize:%f,%f",winSize.width,winSize.height); // 创建2个 GameCtrl (2层) gameCtrlArr.insert(0,GameCtrl::create(this,30)); if(rand()%2 == 0){ gameCtrlArr.insert(0,250)); } // 开启消息调度 scheduleUpdate(); // ******************************************** // 物理碰撞检测 「PhysicsContact」 auto listener = EventListenerPhysicsContact::create(); // 开始碰撞 游戏结束 listener->onContactBegin = [this](PhysicsContact & contact){ // 取消 消息调度 this->unscheduleUpdate(); // 切换至Game Over场景 Director::getInstance()->replaceScene(GameOverScene::createScene()); return true; }; // 向事件分发器,注册listener Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraPHPriority(listener,this); // ******************************************** // 用户单点触摸 jump high 【TouchOneByOne】 auto touchListener = EventListenerTouchOneByOne::create(); // 开始触摸 原地 跳一下 touchListener->onTouchBegan = [this](Touch * t,Event * e){ // 每一个游戏控制器 都执行一下 方法 for (auto it = gameCtrlArr.begin(); it!=gameCtrlArr.end(); it++) { // 解引用 就可以获得数组成员对象了 // 如果 是点在自己的那一层 才执行 跳高动作 if ((*it)->hitTestPoint(t->getLocation())) { (*it)->onUserTouch(); break; } } return false; }; // 向事件分发器,注册listener Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraPHPriority(touchListener,this); return true; } #pragma mark - 时钟方法 void HeroScene::update(float dt) { // 在场景的时钟方法中,更新\控制 每一个游戏控制器的时钟方法 for (auto it = gameCtrlArr.begin(); it!=gameCtrlArr.end(); it++) { // 解引用 就可以获得数组成员对象了 // 每一个游戏控制器 开启时钟方法 (*it)->startUpdate(dt); } }
// // GameOverScene.h // 01_cocos2d-x // // Created by beyond on 14-10-6. // // #include <cocos2d.h> #include "MainScene.h" using namespace cocos2d; // 继承自 有颜色的Layer class GameOverScene:public LayerColor { private: Size winSize; public: // 供外界调用 static Scene* createScene() { auto s = Scene::create(); auto l = GameOverScene::create(); s->addChild(l); return s; }; // 宏定义的Create方法,内部会调用init方法 CREATE_FUNC(GameOverScene); // 初始化,自己用 virtual bool init() { // 父类的init方法 LayerColor::initWithColor(Color4B::WHITE); // 屏幕大小 winSize = Director::getInstance()->getVisibleSize(); // 创建一个Label auto label = Label::create(); label->setString("Game Over"); label->setSystemFontSize(40); label->setName("label"); label->setColor(Color3B::BLACK); label->setPosition(winSize.width/2,winSize.height/2); // 添加到Layer addChild(label); // 添加一个事件,点击 Label,返回到主场景的事件 // 2.触摸Label,开启 时钟updatePosition // 实例化一个触摸监听器 对象 auto listener = EventListenerTouchOneByOne::create(); // 当触摸开始时,绑定一个闭包函数; // 【】表示 要传入的外界对象,此处是this // ()表示参数 listener->onTouchBegan = [this](Touch *t,Event *e){ // 如果 点击 了label,才每隔一秒执行一次 更新位置方法 Label *label =(Label *) e->getCurrentTarget()->getChildByName("label"); if (label->getBoundingBox().containsPoint(t->getLocation())) { // 回到主场景 // 创建场景,自动释放 it's an autorelease object auto scene = MainScene::createScene(); // 替换场景 Director::getInstance()->replaceScene(scene); } return false; }; // 5、获取事件分发器,添加一个事件监听器,到this身上;即监听的是this对象【整个图层Layer】 Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraPHPriority(listener,this); return true; }; };
// // GameCtrl.h // 01_cocos2d-x // // Created by beyond on 14-10-6. // // #ifndef ___1_cocos2d_x__GameCtrl__ #define ___1_cocos2d_x__GameCtrl__ #include <cocos2d.h> // 全屏的边框 #include "Boundary.h" #include "Hero.h" #include "Block.h" USING_NS_CC; // 继承自 Ref,就自动拥有了 释放机制 class GameCtrl:public Ref { private: // 屏幕尺寸 Size winSize; // 边界 边框,用成员变量记住,是因为 碰撞检测要用到 Boundary * boundary; Hero * hero; // 重要~~~Layer就相当于HeroScene场景,因为所有的子精灵 全添加到Layer中,所以需要传入Layer // 成员变量记住(其他方法中要用到) Layer * _layer; float _positionY; // 临时变量,用于累计 记录 流逝的时间 int tempTimeDelta; // 总共的时间间隔 (即 时间delta累计到 该间隔时,创建并添加一个障碍物) int totalIntervalTime; private: // 每添加一个新的障碍物之后,需重置 用于累计 记录 流逝的时间 的变量 void resetTempTimeDelta(); // 每隔 随机的时间,创建并添加一个障碍物 void addBlock(); public: // 重要~~~这个Layer就相当于HeroScene场景,所以需要传入Layer // 参数 就是在屏幕的y值 // 供外界 static GameCtrl* create(Layer *layer,float positionY); // 自己初始化 virtual bool init(Layer * layer,float positionY); // 供场景调用,让场景来 开启和关闭 游戏控制器 中的 时钟方法 void startUpdate(float dt); // 当被用户触摸了 时侯调用,给英雄一个向上的速度 void onUserTouch(); bool hitTestPoint(Vec2 point); }; #endif /* defined(___1_cocos2d_x__GameCtrl__) */
// // GameCtrl.cpp // 01_cocos2d-x // // Created by beyond on 14-10-6. // // #include "GameCtrl.h" // 重要~~~这个Layer就相当于HeroScene场景,所以需要传入Layer // 参数 就是在屏幕的y值 // 供外界 GameCtrl* GameCtrl::create(cocos2d::Layer *layer,float positionY) { auto gameCtrl = new GameCtrl(); // 调用自己的init初始化,将参数 传递过去 gameCtrl->init(layer,positionY); // 自动释放 gameCtrl->autorelease(); return gameCtrl; } // 自己初始化 bool GameCtrl::init(cocos2d::Layer *layer,float positionY) { // 成员变量记住,其他方法中 要用到 _layer = layer; _positionY = positionY; // 全屏 winSize = Director::getInstance()->getVisibleSize(); //************************************** // 1、添加游戏的边框、边界 boundary = Boundary::create(); // 居中 (注意 不同的控制器,可能在不同的层 其y值不同 高度也不同) boundary->setPosition(winSize.width/2,winSize.height/2+positionY); // 全屏 boundary->setContentSize(winSize); // 添加到Layer layer->addChild(boundary); //************************************** // 2、添加地板 (不需要关联物理世界) auto ground = Sprite::create(); ground->setColor(Color3B(0,0)); ground->setTextureRect(Rect(0,3)); // (注意 不同的控制器,可能在不同的层 其y值不同) 3 和1.5 ground->setPosition(winSize.width/2,1.5+positionY); // 添加到Layer layer->addChild(ground); //************************************** // 3、添加Hero hero = Hero::create(); // (注意 不同的控制器,可能在不同的层 其y值不同) hero->setPosition(50,hero->getContentSize().height/2+positionY); // 添加到Layer layer->addChild(hero); // 每添加一个新的障碍物之后,需重置 用于累计 记录 流逝的时间 的变量 resetTempTimeDelta(); return true; } #pragma mark - 供外界场景调用 // 供场景调用,让场景来 开启和关闭 游戏控制器 中的 时钟方法 void GameCtrl::startUpdate(float dt) { // 临时变量,用于累计 记录 流逝的时间 tempTimeDelta++; // 总共的时间间隔 (即 时间delta累计到 该间隔时,创建并添加一个障碍物) if (tempTimeDelta >= totalIntervalTime) { // 每添加一个新的障碍物之后,需重置 用于累计 记录 流逝的时间 的变量 resetTempTimeDelta(); // 每隔 随机的时间,创建并添加一个障碍物 addBlock(); } } // 每添加一个新的障碍物之后,需重置 用于累计 记录 流逝的时间 的变量 void GameCtrl::resetTempTimeDelta() { tempTimeDelta = 0; totalIntervalTime = (rand()%120) + 100; } // 创建 并 添加 障碍物 (在随机的 时间 间隔 之后 ) void GameCtrl::addBlock() { auto b = Block::create(); _layer->addChild(b); // 注意 障碍物的y值是 和当前游戏控制器 自己的y值 相同的 // 即 block的半高 + 当前控制器自己的y b->setPositionY(b->getContentSize().height/2 + _positionY); } #pragma mark - 触摸事件 // 当被用户触摸了 时侯调用,给英雄一个向上的速度 void GameCtrl::onUserTouch() { hero->getPhysicsBody()->setVelocity(Vec2(0,400)); } bool GameCtrl::hitTestPoint(cocos2d::Vec2 point) { return boundary->getBoundingBox().containsPoint(point); }
// // Boundary.h // 01_cocos2d-x // // Created by beyond on 14-10-6. // // 边框、边界,其大小和winSize一样 #ifndef __Boundary__ #define __Boundary__ #include <cocos2d.h> USING_NS_CC; class Boundary:public Node { public: // 宏定义 一个静态的create方法,内部会调用init方法 CREATE_FUNC(Boundary); // 初始化方法 virtual bool init(); }; #endif /* defined(__Boundary__) */
// // Boundary.h // 01_cocos2d-x // // Created by beyond on 14-10-6. // // 边框、边界,其大小和winSize一样 #include "Boundary.h" bool Boundary::init(){ // 父类的init方法,内部 直接返回一个true Node::init(); // 960 * 640 Size winSize = Director::getInstance()->getVisibleSize(); // 设置Node大小 全屏 setContentSize(winSize); // 设置物理刚体body,大小和winSize一样 setPhysicsBody(PhysicsBody::createEdgeBox(winSize)); return true; }
// // Hero.h // 01_cocos2d-x // // Created by beyond on 14-10-6. // // 主角,继承自Sprite,奔跑的小人 #ifndef ___1_cocos2d_x__Hero__ #define ___1_cocos2d_x__Hero__ #include <cocos2d.h> USING_NS_CC; class Hero:public Sprite { public: // 宏,静态的create方法,内部会调用init方法 CREATE_FUNC(Hero); virtual bool init(); }; #endif /* defined(___1_cocos2d_x__Hero__) */
// // Hero.cpp // 01_cocos2d-x // // Created by beyond on 14-10-6. // // 主角,奔跑的小人 #include "Hero.h" #include "FlashTool.h" bool Hero::init() { // 父类的init方法 Sprite::init(); // 执行 帧动画 一直奔跑 RepeatForever runAction(RepeatForever::create(FlashTool::animateFromJsonFile("Hero.json",0.2f))); // Json中的尺寸 Size s = Size(44,52); // 精灵的大小 setContentSize(s); // 设置物理世界的刚体body setPhysicsBody(PhysicsBody::createBox(s)); // 刚体不允许 旋转 getPhysicsBody()->setRotationEnable(false); // 重要~~~若想参与 碰撞,必须绑定一个碰撞标识 getPhysicsBody()->setContactTestBitmask(1); return true; }
// // Block.h // 01_cocos2d-x // // Created by beyond on 14-10-6. // // #ifndef ___1_cocos2d_x__Block__ #define ___1_cocos2d_x__Block__ #include <cocos2d.h> USING_NS_CC; class Block:public Sprite { public: // 宏,内部会调用init方法 CREATE_FUNC(Block); virtual bool init(); // 时钟方法,内部会 让 障碍物不断地向左移动 virtual void update(float dt); }; #endif /* defined(___1_cocos2d_x__Block__) */
// // Block.cpp // 01_cocos2d-x // // Created by beyond on 14-10-6. // // #include "Block.h" bool Block::init() { // 父类的init方法 Sprite::init(); // 屏幕大小 Size winSize = Director::getInstance()->getVisibleSize(); // 放在屏幕的外边 setPositionX(winSize.width); // 黑色 障碍物 setColor(Color3B(0,0)); Size size = Size((rand()%20)+5,(rand()%30)+10); // 随机生成 不同大小的 障碍物 setContentSize(size); // 黑色的方块区域 setTextureRect(Rect(0,size.width,size.height)); // *************************************** // 设置 物理刚体 setPhysicsBody(PhysicsBody::createBox(size)); // 不是动态的刚体 即:是静态的刚体 getPhysicsBody()->setDynamic(false); // 重要~~~若想参与 碰撞,必须绑定一个碰撞标识 getPhysicsBody()->setContactTestBitmask(1); // *************************************** // 开启时钟方法 scheduleUpdate(); return true; } #pragma mark - 时钟方法 // 时钟方法,内部会 让 障碍物不断地向左移动 void Block::update(float dt){ this->setPositionX(getPositionX()-8); // 移动到屏幕外边时,就停止消息调度,并且移除 if (getPositionX()<0) { unscheduleUpdate(); removeFromParent(); } }
// // FlashTool.h // 01_cocos2d-x // // Created by beyond on 14-10-6. // // #ifndef ___1_cocos2d_x__FlashTool__ #define ___1_cocos2d_x__FlashTool__ #include <cocos2d.h> USING_NS_CC; class FlashTool { public: // 通过解析flash cc 导出的Json文件+大图片,生成一个Animate对象,用于执行序列帧动画 static Animate * animateFromJsonFile(std::string jsonFile,float delayPerUnit); }; #endif /* defined(___1_cocos2d_x__FlashTool__) */
// // FlashTool.cpp // 01_cocos2d-x // // Created by beyond on 14-10-6. // // #include "FlashTool.h" // Json解析 使用cocos2d 内置的rapidJson库 #include <json/document.h> // 通过解析flash cc 导出的Json文件+大图片,用于执行序列帧动画 Animate * FlashTool::animateFromJsonFile(std::string jsonFile,float delayPerUnit) { // 文档 对象 rapidjson::Document doc; // FileUtils工具类 读入json文件 std::string fileContent = FileUtils::getInstance()->getStringFromFile(jsonFile); // fileContent.erase(0,fileContent.find_first_of('{')); // 标记默认为 0,开始解析 doc.Parse<0>(fileContent.c_str()); // 得到大图片的 图片名 std::string imgFileName = doc["Meta"]["image"].GetString(); auto &frames = doc["frames"]; // 精灵帧缓存 auto sfc = SpriteFrameCache::getInstance(); // 容器用于 存放所有的 动画帧 Vector<AnimationFrame*> animFrames; // 遍历,裁剪,创建,添加到容器 for (auto m=frames.MemberonBegin(); m!=frames.MemberonEnd(); m++) { auto frameName = m->name.GetString(); auto & frameProperties = m->value["frame"]; auto & spriteSourceSize = m->value["spriteSourceSize"]; auto sf = sfc->getSpriteFrameByName(frameName); if (!sf) { sf = SpriteFrame::create(imgFileName,Rect(frameProperties["x"].GetInt(),frameProperties["y"].GetInt(),frameProperties["w"].GetInt(),frameProperties["h"].GetInt()),m->value["rotated"].GetBool(),Vec2(spriteSourceSize["x"].GetInt(),spriteSourceSize["y"].GetInt()),Size(spriteSourceSize["w"].GetInt(),spriteSourceSize["h"].GetInt())); sfc->addSpriteFrame(sf,frameName); } animFrames.pushBack(AnimationFrame::create(sf,delayPerUnit,ValueMapNull)); } // 生成用于Action的Animate Animation * animation = Animation::create(animFrames,delayPerUnit); return Animate::create(animation); }
{"frames": { "hero0000": { "frame": {"x":0,"y":0,"w":44,"h":52},"rotated": false,"trimmed": false,"spriteSourceSize": {"x":0,"sourceSize": {"w":44,"h":52} },"hero0001": { "frame": {"x":44,"w":42,"trimmed": true,"spriteSourceSize": {"x":2,"hero0002": { "frame": {"x":86,"hero0003": { "frame": {"x":0,"y":52,"hero0004": { "frame": {"x":42,"h":52} }},"Meta": { "app": "Adobe Flash Professional","version": "13.1.0.226","image": "Hero.png","format": "RGBA8888","size": {"w":128,"h":128},"scale": "1" } }