当前游戏的环境怎么样?cocos2dx开发环境-x 开始没落了么

5560人阅读
cocos2d-x游戏开发(67)
欢迎转载:
吐槽一下,刚写了一个小时,这CSDN不知抽什么风就是发不了,我以为存草稿了就刷新了一下,结果没存草稿。擦...
cocos2d-x引擎实现的场景切换特效有41个,我这里就不列举了。有兴趣的童鞋自行看源码或谷歌之,一大把介绍的。昨天看了红孩儿的场景切换,写的很详细,代码逐行注释。我这里不想详细解释代码,只侧重流程。
cocos2d-x里面的场景,分为两类
1.普通场景,就是CCScene::create()出来的。这类没有特效,运行的话直接就出来了。
2.过渡场景,就是有特效的场景,我称之为过渡场景。这类场景切换的时候有特效。
刚写了一遍,实在懒的详细写了。直接说结论:
所谓的过渡场景,就是将你create出来的场景包装了一下,比如
CCScene *scene = About::scene();
CCDirector::sharedDirector()-&replaceScene(CCTransitionFade::create(1.2, scene));
而所谓的特效,实质上就是实现了CCScene的onEnter()系列函数。
就CCTransitionFade为例子看下:
class CC_DLL CCTransitionFade : public CCTransitionScene
protected:
CCTransitionFade();
virtual ~CCTransitionFade();
/** creates the transition with a duration and with an RGB color
* Example: FadeTransition::create(2, scene, ccc3(255,0,0); // red color
static CCTransitionFade* create(float duration,CCScene* scene, const ccColor3B& color);
static CCTransitionFade* create(float duration,CCScene* scene);
/** initializes the transition with a duration and with an RGB color */
virtual bool initWithDuration(float t, CCScene*scene ,const ccColor3B& color);
virtual bool initWithDuration(float t,CCScene* scene);
virtual void onEnter();// 过渡回调
virtual void onExit();
所有的过渡场景都是CCTransitionScene的子类,有兴趣的可以看源码或红孩儿的博文。
看这里,它实现了onEnter。在这个函数里面才是实质上的过渡特效实现,就是一系列的动作。动作完了调finish(),finish里面又调setNewScene函数,这个函数比较重要:
void CCTransitionScene::setNewScene(float dt)
CC_UNUSED_PARAM(dt);
// [self unschedule:_cmd];
// &_cmd& is a local variable automatically defined in a method
// that contains the selector for the method
this-&unschedule(schedule_selector(CCTransitionScene::setNewScene));
CCDirector *director = CCDirector::sharedDirector();
// Before replacing, save the &send cleanup to scene&
m_bIsSendCleanupToScene = director-&isSendCleanupToScene();
director-&replaceScene(m_pInScene); // 看这里,这是后面要用的
// enable events while transitions
director-&getTouchDispatcher()-&setDispatchEvents(true);
// issue #267
m_pOutScene-&setVisible(true);
过渡特效就完了。
看主循环如何调度:直接看setNextScene函数
void CCDirector::setNextScene(void)
// 布尔变量,当前场景是过渡场景则true,反之false
bool runningIsTransition = dynamic_cast&CCTransitionScene*&(m_pRunningScene) != NULL;
// 布尔变量,载入的场景是过渡场景则true,反之false
bool newIsTransition = dynamic_cast&CCTransitionScene*&(m_pNextScene) != NULL;
// If it is not a transition, call onExit/cleanup
// 如果载入的不是一个过渡场景,那么调用当前场景的onExit和cleanup
if (! newIsTransition)
if (m_pRunningScene)// 有可能是个过渡场景
m_pRunningScene-&onExitTransitionDidStart();
m_pRunningScene-&onExit();
// issue #709. the root node (scene) should receive the cleanup message too
// otherwise it might be leaked.
if (m_bSendCleanupToScene && m_pRunningScene)
m_pRunningScene-&cleanup();
if (m_pRunningScene)
m_pRunningScene-&release();
// 当前场景指针指向载入场景
m_pRunningScene = m_pNextS
m_pNextScene-&retain();
m_pNextScene = NULL;
// 如果当前场景不是一个过渡场景,那么调用载入场景的onEnter和onEnterTransitionDidFinish
if ((! runningIsTransition) && m_pRunningScene)
m_pRunningScene-&onEnter();// 本质是调onEnter
m_pRunningScene-&onEnterTransitionDidFinish();
一开始两个布尔变量并不总是true,即使你每个场景都用了特效。原因如下:
看前面特效场景类的setNewScene函数,有一句director-&replaceScene(m_pInScene)。
这个就将你的场景(CCScene::create()出来的那个,不是你包装的特效场景)设为要载入场景,而这个场景不是一个过渡场景,呵呵。
如果你调试TestCpp的TransitionsTest列子,你会发现这两个布尔变量总是一个true,一个false,呵呵。
本质上来说,一个过渡场景就是实现了CCScene的onEnter系列函数。可以仿照已有的列子自己写,嘿嘿。
就写这么多了,不知道说清楚了没有。
&&相关文章推荐
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:507098次
积分:6124
积分:6124
排名:第3735名
原创:123篇
评论:276条
QQ: Email:
文章:16篇
阅读:29818
文章:18篇
阅读:138786
(1)(2)(19)(4)(1)(3)(1)(2)(15)(1)(1)(2)(3)(2)(1)(16)(3)(1)(4)(8)(9)(1)(5)(5)(6)(7)(5)(3)一、前提:
完成前一篇的内容。
具体参考:
二、本篇目标:
l& 说说游戏中各种角色的动作、属性以及重构思路
l& 进行代码重构让色狼大叔和女主角生动鲜活起来
三、内容:
l& 说说游戏中各种角色的动作、属性以及重构思路
通过前两篇我们建立的一个简陋的游戏原型,但是游戏中的人物比如色狼大叔、女主角都看去来很呆板不够鲜活,比如色狼会沿着道路移动,那这个只能说是移动根本不像是在走路,没有走的动作感觉就是沿着道路在漂移,女主角也是一动不动的站那里。这样的游戏很没有乐趣,所以需要给这些游戏角色加入动作和表情,让人看去来他们是鲜活的,对这些角色进行一下简单的动画以及属性分析如下:
色狼大叔的动画:
1、&&&&&&&&& 静止动画:游戏刚开始处于静止状态
2、&&&&&&&&& 走路动画:沿着道路走
3、&&&&&&&&& 死亡动画:当子弹击中血量消耗完时死亡消失
色狼大叔的属性:
1、&&&&&&&&& 是否运动:色狼是否处于激活沿着道路行走
2、&&&&&&&&& 是否死亡:是否被炮塔打死
3、&&&&&&&&& 行走速度:不同色狼的行走速度不同
4、&&&&&&&&& 色狼血量:不同色狼血量不同
5、&&&&&&&&& 行走:沿着道路行走
女主角的动画:
1、&&&&&&&&& 静止动画:游戏刚开始处于静止状态
2、&&&&&&&&& 卖萌动画:不能像木头似的,就加点表情动作
3、&&&&&&&&& 死亡动画:当纯洁值被色狼玷污光了就死亡了
女主角的属性:
1、&&&&&&&&& 女主角贞洁值:相当于生命值
根据上面的分析我们把每个角色拆分成动画显示和业务属性逻辑两个部分,对色狼和女主角进行代码重构。
重构后大概结构如上图:
ActionSprite:属于CCSprite类,负责游戏角色精灵的动画显示,Luoli(萝莉)、DaShu(大叔)、JiaoShou(叫兽)等角色精灵均继承自ActionSprite,都属于动画显示类。
Luoli(萝莉):属ActionSprite的子类,负责女主角的动画效果展示。
DaShu(大叔):属ActionSprite的子类,负责大叔色狼的动画效果展示。
JiaoShou (叫兽):属ActionSprite的子类,负责叫兽色狼的动画效果展示。
Selang(色狼):属于CCNode类,负责色狼的行走、血量、速度、攻击等具体的业务,每个Selang都包含一个DaShu(大叔)或JiaoShou(叫兽)类的游戏精灵。并且具备最重要的行为实现沿着道路行走。
Girl(女孩):属于CCNode类,负责女主角的血量等具体的业务,每个Girl都包含一个Luoli类的游戏精灵。
l& 进行代码重构让色狼大叔和女主角生动鲜活起来
打开项目工程按照上面的思路重点对色狼和女主角的代码实现进行重构。
色狼大叔代码重构
新建ActionSprite.h、ActionSprite.cpp类(角色动画类),这个类继承自CCSprite负责游戏角色的动画效果显示,色狼和女孩都会是这个类的子类。
ActionSprite.h代码:
//声明一个动作状态的枚举类型
typedef enum _ActionState{
kActionStateNone = 0, //无状态
kActionStateIdle, //静止状态
kActionStateWalk, //行走状态
kActionStateDeath //死亡状态
class ActionSprite: public cocos2d::CCSprite
ActionSprite(void);
~ActionSprite(void);
void idle();
void death();
void walk();
CC_SYNTHESIZE(int,_price,Price);
CC_SYNTHESIZE(float,_hp,HP);
//静止状态动作
CC_SYNTHESIZE_RETAIN(cocos2d::Action*,_idleAction,IdleAction);
//死亡状态动作
CC_SYNTHESIZE_RETAIN(cocos2d::Action*,_deathAction,DeathAction);
//行走状态动作
CC_SYNTHESIZE_RETAIN(cocos2d::Action*,_walkAction,WalkAction);
//当前动作状态
CC_SYNTHESIZE(ActionState,_actionState,ActionState);
//行走速度
CC_SYNTHESIZE(float,_walkSpeed,WalkSpeed);
CC_SYNTHESIZE(float,_damage,Damage);
CC_SYNTHESIZE(float,_money,Money);
//是否有光环
CC_SYNTHESIZE(bool,_halo,Halo);
ActionSprite.cpp代码:
ActionSprite::ActionSprite(void)
_idleAction=NULL;
_walkAction=NULL;
_deathAction=NULL;
ActionSprite::~ActionSprite(void)
//释放内存
CC_SAFE_RELEASE_NULL(_idleAction);
CC_SAFE_RELEASE_NULL(_deathAction);
CC_SAFE_RELEASE_NULL(_walkAction);
//设置精灵为静止状态
void ActionSprite::idle()
if (_actionState != kActionStateIdle)
//先停止所有动作
this-&stopAllActions();
//运行静止动作
this-&runAction(_idleAction);
_actionState=kActionStateI
//设置精灵为行走状态
void ActionSprite::walk()
if (_actionState != kActionStateWalk)
//先停止所有动作
this-&stopAllActions();
//运行行走动作
this-&runAction(_walkAction);
_actionState=kActionStateW
//设置精灵为死亡状态
void ActionSprite::death()
//先停止所有动作
this-&stopAllActions();
this-&runAction(_deathAction);
_actionState=kActionStateD
素材准备,设计2张大叔不同动作的图片,交替显示模拟色狼行走动画,完成后把图片拷贝到Resources的iphonehd文件夹中,为了适应小分辨率的手机把这个2张图片按比例缩小一半并且拷贝到Resources的iphone文件夹中。
新建DaShu.h、DaShu.cpp类(色狼大叔动画类),这个类继承自上面的ActionSprite负责游戏色狼大叔的动画效果显示。
class DaShu : public ActionSprite
DaShu(void);
~DaShu(void);
CREATE_FUNC(DaShu);
//初始化方法
bool init();
//设置光环,拥有光环的色狼生命值加倍
void setHalo(bool halo);
DaShu.cpp:
bool DaShu::init()
bool bRet=false;
CC_BREAK_IF(!ActionSprite::initWithFile("dashu_2.png"));
//设置静止状态动作
Vector&SpriteFrame *& idleFrames(1);
SpriteFrame *frame1=SpriteFrame::create("dashu_2.png", Rect(0, 0, 60, 83));
idleFrames.pushBack(frame1);
Animation *idleAnimation=Animation::createWithSpriteFrames(idleFrames,float(6.0 / 12.0));
this-&setIdleAction(CCRepeatForever::create(CCAnimate::create(idleAnimation)));
//设置行走状态动作
Vector&SpriteFrame *& walkFrames(2);
for (i=0;i&2;i++)
SpriteFrame *frame2=SpriteFrame::create(CCString::createWithFormat("dashu_%d.png", i+1)-&getCString(), Rect(0, 0, 60, 83));
walkFrames.pushBack(frame2);
Animation *walkAnimation=Animation::createWithSpriteFrames(walkFrames,float(6.0 / 12.0));
this-&setWalkAction(CCRepeatForever::create(CCAnimate::create(walkAnimation)));
//设置死亡状态动作
Vector&SpriteFrame *& deathFrames(1);
SpriteFrame *frame3=SpriteFrame::create("dashu_2.png", Rect(0, 0, 60, 83));
deathFrames.pushBack(frame3);
Animation *deathAnimation=Animation::createWithSpriteFrames(deathFrames,float(6.0 / 12.0));
this-&setDeathAction(Animate::create(deathAnimation));
//设置攻击值
this-&setDamage(1);
//设置行走速度
this-&setWalkSpeed(0.4f);
//设置生命值
this-&setHP(18);
//设置金钱数
this-&setMoney(1.0f/10.0f);
bRet=true;
} while (0);
//设置光环
void DaShu::setHalo(bool halo)
//拥有光环后生命值加4倍
float h=this-&getHP()*4.0f;
this-&setHP(h);
新建Selang.h、Selang.cpp类(色狼类),这个类继承自CCNode游戏场景中的每一个色狼都有这个类产生,它肯定包含一个ActionSprite的色狼动画类,并且之前在MainScene.cpp的update方法中实现的色狼沿路行走代码也将转移到这个类的update方法中。
Selang.h:
#include "cocos2d.h"
#include "Waypoint.h"
#include "GameMediator.h"
#include "ActionSprite.h"
class Selang : public cocos2d::CCNode
Selang(void);
~Selang(void);
//根据提供的spriteIndex实例化成不同的色狼
static Selang* nodeWithType(int spriteIndex);
//初始化方法
bool initWithType(int spriteIndex,bool halo);
//激活色狼
void doActivate(float dt);
//获取精灵Rect
virtual cocos2d::Rect getRect();
//设置精灵是否激活
void setActive(bool active);
//是否死亡
void update(float delta);
//色狼精灵
CC_SYNTHESIZE_RETAIN(ActionSprite*,_mySprite,MySprite);
//精灵序号,为每种精灵编一个序号
int _spriteI
GameMediator*
//当前精灵的位置
cocos2d::Point myP
//走路速度
float walkingS
//开始路点
Waypoint *beginningW
//结束路点
Waypoint *destinationW
//是否激活
//色狼高度
//两个点的碰撞检测
bool collisionWithCircle(cocos2d::Point circlePoint,float radius,cocos2d::Point circlePointTwo, float radiusTwo);
Selang.cpp:
//根据提供的spriteIndex实例化成不同的色狼
Selang* Selang::nodeWithType(int spriteIndex)
Selang* pRet=new Selang();
bool b=false;
if (pRet && pRet-&initWithType(spriteIndex,b))
pRet-&autorelease();
pRet=NULL;
return NULL;
//初始化方法
bool Selang::initWithType(int spriteIndex,bool halo)
bool bRet=false;
//色狼类型index
_spriteIndex=spriteI
m = GameMediator::sharedMediator();
active=false;
//行走速度
walkingSpeed=0.2f;
ActionSprite* sprite=NULL;
if (spriteIndex==1)//如果类型是1初始化成大叔色狼
sprite=DaShu::create();
sprite-&setHalo(halo);
//设置速度
walkingSpeed=sprite-&getWalkSpeed();
this-&setMySprite(sprite);
//添加精灵到当前Selang中
this-&addChild(_mySprite);
//计算当前色狼精灵1/2高
myHeight=sprite-&getTextureRect().size.height/2.0f;
//获得路点集合中的最后一个点
Waypoint *waypoint=(Waypoint*)m-&getWayPoints().back();
//设置为色狼出发点
beginningWaypoint=
//获取出发点的下个点为色狼目标点
destinationWaypoint=waypoint-&getNextWaypoint();
//获得出发点坐标
Point pos=waypoint-&getMyPosition();
//对坐标进行校正提供半个身位高度
pos.add(Vec2(0,myHeight));
//记录位置坐标
myPosition=
//设置精灵的初始坐标
_mySprite-&setPosition(pos);
//设置初始不可见
this-&setVisible(false);
//把当前色狼添加到游戏的MainScene场景中显示
m-&getNowScene()-&addChild(this);
//启动定时器
this-&scheduleUpdate();
bRet=true;
} while (0);
void Selang::doActivate(float dt)
//激活色狼
active=true;
//设置色狼可见
this-&setVisible(true);
//获取精灵Rect
Rect Selang::getRect()
Rect rect =Rect(_mySprite-&getPosition().x - _mySprite-&getContentSize().width * 0.5f,
_mySprite-&getPosition().y - _mySprite-&getContentSize().height* 0.5f,
_mySprite-&getContentSize().width,
_mySprite-&getContentSize().height);
//设置精灵是否激活
void Selang::setActive(bool aactive)
this-&setVisible(true);
void Selang::update(float delta)
if (!active)
Point destinationPos=destinationWaypoint-&getMyPosition();
//提升色狼半个身位
destinationPos.add(Vec2(0,myHeight));
//是否拐弯
if (this-&collisionWithCircle(myPosition,1,destinationPos,1))
if (destinationWaypoint-&getNextWaypoint())
//设置新的出发点和目标点
beginningWaypoint=destinationW
destinationWaypoint=destinationWaypoint-&getNextWaypoint();
Point targetPoint=destinationWaypoint-&getMyPosition();
//提升色狼半个身位
targetPoint.add(Vec2(0,myHeight));
float movementSpeed=walkingS
//计算目标点的向量
Point normalized=Point(targetPoint.x-myPosition.x,targetPoint.y-myPosition.y).getNormalized();
//根据速度和向量分别计算x,y方式上的偏移值
float ox=normalized.x * walkingS
float oy=normalized.y *walkingS
//更新色狼移动后的位置
myPosition = Point(myPosition.x + ox, myPosition.y +oy);
_mySprite-&setPosition(myPosition);
//两个点的碰撞检测
bool Selang::collisionWithCircle(cocos2d::Point circlePoint,float radius,cocos2d::Point circlePointTwo, float radiusTwo)
float xdif = circlePoint.x - circlePointTwo.x;
float ydif = circlePoint.y - circlePointTwo.y;
//计算两点间的距离
float distance = sqrt(xdif * xdif + ydif * ydif);
if(distance &= radius + radiusTwo)
return true;
return false;
如果运行一下那么上面的代码中Waypoint *waypoint=(Waypoint*)m-&getWayPoints().back();这行应该会报错,因为GameMediator中没有提供getWayPoints()这个方法,所以我们要对GameMediator类进行修改加上这个方法,代码如下:
GameMediator::setWayPoints(cocos2d::Vector&Waypoint*& wayPoints)
_wayPoints=wayP
Vector&Waypoint*& GameMediator::getWayPoints()
return _wayP
在MainScene的init方法中把路点集合通过setWayPoints方法赋值给GameMediator,这样在Selang.cpp中就可以取到路点集合了:
this-&wayPositions.pushBack(waypoint12);
GameMediator::sharedMediator()-&setWayPoints(wayPositions);
测试这个Selang类具体效果,先给MainScene添加一个void startGame(float delta)的方法,用这个方法开始游戏。
//开始游戏
void MainScene::startGame(float delta)
//实例化一个大叔类型的色狼
Selang* selang=Selang::nodeWithType(1);
//激活这个色狼
selang-&setActive(true);
//设置色狼动画为行走动画
selang-&getMySprite()-&walk();
//取消定时器方法,保证startGame只执行一次
this-&unschedule(schedule_selector(MainScene::startGame));
我们在MainScene的init方法末尾处调用这个startGame的方法:
//0.5秒后调用startGame方法
this-&schedule(schedule_selector(MainScene::startGame),0.5f);
到这里,把第一篇中临时添加色狼的代码删除,就可以运行测试游戏了,会看到色狼大叔一扭一扭的沿着道路靠近女主角。效果非常好,我们成功的对色狼的代码进行了重构。
女主角代码重构
素材准备,设计4张萝莉不同动作的图片,交替显示模拟萝莉卖萌动画,完成后把图片拷贝到Resources的iphonehd文件夹中,为了适应小分辨率的手机把这个4张图片按比例缩小一半并且拷贝到Resources的iphone文件夹中。
新建Luoli.h、Luoli.cpp类(女主角动画类),这个类继承自上面的ActionSprite负责游戏女主角的动画效果显示。
class Luoli : public ActionSprite
Luoli(void);
~Luoli(void);
CREATE_FUNC(Luoli);
bool init();
Luoli.cpp:
bool Luoli::init()
bool bRet=false;
CC_BREAK_IF(!ActionSprite::initWithFile("girl1_1.png"));
//设置静止状态动作
Vector&SpriteFrame *& idleFrames(1);
SpriteFrame *frame1=SpriteFrame::create("girl1_1.png", Rect(0, 0, 100, 126));
idleFrames.pushBack(frame1);
Animation *idleAnimation=Animation::createWithSpriteFrames(idleFrames,float(6.0 / 12.0));
this-&setIdleAction(CCRepeatForever::create(CCAnimate::create(idleAnimation)));
//设置行走状态动作
Vector&SpriteFrame *& walkFrames(4);
for (i=0;i&4;i++)
SpriteFrame *frame1=SpriteFrame::create(CCString::createWithFormat("girl1_%d.png", i+1)-&getCString(), Rect(0, 0, 100, 126));
walkFrames.pushBack(frame1);
Animation *walkAnimation=Animation::createWithSpriteFrames(walkFrames,float(6.0 / 12.0));
this-&setWalkAction(CCRepeatForever::create(CCAnimate::create(walkAnimation)));
bRet=true;
} while (0);
新建Girl.h、Girl.cpp类(女孩类),这个类继承自CCNode游戏场景中的女主角由这个类产生,它肯定包含一个ActionSprite的萝莉动画类。
class Girl : public cocos2d::CCNode
Girl(void);
~Girl(void);
//根据提供的type实例化成不同的女主角
static Girl* nodeWithType(int type);
//初始化方法
bool initWithLocation(cocos2d::Point location);
//获取精灵Rect
cocos2d::Rect getRect();
//萝莉精灵
CC_SYNTHESIZE_RETAIN(ActionSprite*,_mySprite,MySprite);
Girl.cpp:
//根据提供的type实例化成不同的女主角
Girl* Girl::nodeWithType(int type)
Girl* pRet=new Girl();
GameMediator* m = GameMediator::sharedMediator();
Waypoint *waypoint=(Waypoint*)m-&getWayPoints().front();
Point pos=waypoint-&getMyPosition();
if (pRet && pRet-&initWithLocation(pos))
pRet-&autorelease();
pRet=NULL;
return false;
//初始化方法
bool Girl::initWithLocation(cocos2d::Point location)
bool bRet=false;
//实例化一个萝莉
ActionSprite *sprite= Luoli::create();
this-&setMySprite(sprite);
//添加精灵到当前Gril中
this-&addChild(sprite);
//设置为静止
sprite-&idle();
//计算当前萝莉精灵1/2高
int myHeight=sprite-&getTextureRect().size.height/2.0f;
//对坐标进行校正提供半个身位高度
location.add(Vec2(0,myHeight));
sprite-&setPosition(location);
//把当前女主角添加到游戏的MainScene场景中显示
GameMediator* m = GameMediator::sharedMediator();
m-&getNowScene()-&addChild(this,10000);
bRet=true;
while (0);
Rect Girl::getRect()
Rect rect = Rect(_mySprite-&getPosition().x - _mySprite-&getContentSize().width * 0.5f,
_mySprite-&getPosition().y - _mySprite-&getContentSize().height* 0.5f+20,
_mySprite-&getContentSize().width,
_mySprite-&getContentSize().height-40);
在MainScene的 startGame(float delta)的方法中加上初始化女主角的代码。
//初始一个女主角
Girl* girl=Girl::nodeWithType(1);
//设置女主角动画为卖萌动画
girl-&getMySprite()-&walk();
//取消定时器方法,保证startGame只执行一次
this-&unschedule(schedule_selector(MainScene::startGame));
到这里,把第一篇中临时添加女主角的代码删除,就可以运行测试游戏了,本篇的任务到此为止,本篇完成后android真机的运行效果如下:
这个塔防游戏系列已经写了3篇了,到现在为止还没有出现炮塔,说好的炮塔呢?请期待下一篇炮塔姑娘的保护神~
作者交流QQ:
& & & & & &邮箱:
阅读(...) 评论()你正在使用的浏览器版本过低,将不能正常浏览和使用知乎。7110人阅读
iPhone(316)
题记:对于技术,我们大可不必挖得那么深,但一定要具备可以挖得很深的能力
问题的由来
怎么样使用 Cocos2d-x 快速开发游戏,方法很简单,你可以看看其自带的例程,或者从网上搜索教程,运行起第一个&Scene HelloWorldScene,然后在 HelloWorldScene 里面写相关逻辑代码,添加我们的层、精灵等 ~ 我们并不一定需要知道 Cocos2d-x 是如何运行或者在各种平台之上运行,也不用知道
Cocos2d-x 的游戏是如何运行起来的,它又是如何渲染界面的 ~~~
我们只用知道 Cocos2d-x 的程序是由&AppDelegate&的方法&applicationDidFinishLaunching&开始,在其中做些必要的初始化,并创建运行第一个
CCScene&即可,正如我们第一次使用各种编程语言写&Hello World!&的程序一样,如 Python 打印:
我们可以不用关心其是怎么实现的,我们只要知道这样就能打印一句话就够了,这就是&封装所带来的好处&。
Cocos2d-x 自带的例程已经足够丰富,但是有些问题并不是看看例子,调用其方法就能明白的事情,在这里一叶遇到了如下问题:
此时我并不知道程序运行时,何时调用 AppDelegate 的构造函数,析构函数和程序入口函数,我们只要知道,程序在这里调用了其构造函数,然后进入入口函数执行其过程,最后再调用其析构函数即可。然而事与愿违,在实际执行的过程中,发现程序只调用其构造函数和入口函数,而直到程序结束运行,都 没有调用其析构函数。要验证此说法很简单,只要如上在析构函数中调用打印日志便可验证。
发生这样的情况,让我 在构造函数创建[资源],并且在析构函数中释放[资源] 的想法不能完成!!! 我们知道它是从哪里开始运行,但却不知道它在哪里结束!疑问,唯有疑问!
程序入口的概念是相对的,AppDelegate&作为跨平台程序入口,在这之上做了另一层的封装,封装了不同平台的不同实现,比如我们通常认为一个程序是由&main&函数开始运行,那我们就去找寻,我们看到了在
proj.linux 目录下存在&main.cpp&文件,这就是我们要看的内容,如下:
在这里我们看见了程序的真正入口,包含一个 main 函数,从此进入,执行 cocos2d-x 程序。
我们看到&main&就知道其是入口函数,那么没有 main 函数就没有入口了吗?显然不是,以 Android 平台启动 cocos2d-x 程序为例。我们找到 Android 平台与上面&等价&的入口点,proj.android/jni/hellocpp/main.cpp:
我们并没有看到所谓的 main 函数,这是由于不同的平台封装所以有着不同的实现,在 Android 平台,默认是使用 Java 开发,可以使用 Java 通过 Jni 调用 C++ 程序,而这里也正式如此。我们暂且只需知道,由 Android 启动一个应用,通过各种峰回路转,最终执行到了 Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit 函数,由此,变开始了我们 cocos2d-x Android 平台的程序入口处。对于跨平台的 cocos2d-x 来说,除非必要,否则可不必深究其理,比如想要使用
Android 平台固有的特性等,那就需要更多的了解 Jni 使用方法,以及 Android 操作系统的更多细节。
所以说程序的入口是相对的,正如博文开始的 print('Hello World') 一样,不同的语言,不同平台总有着不同的实现。
这里我们参考了两个不同平台的实现, Linux 和 Android 平台 cocos2d-x 程序入口 main.cpp的实现,那么其它平台呢,如 iOS ,Win32 等 ~~~ 殊途同归,其它平台程序的入口必然包含着其它平台的不同 封装实现 ,知道有等价在此两平台的程序入口即可。而通过这两个平台也足够解决我们的疑问,程序的开始与结束&~
问题的推测
我们就从 Linux 和 Android 这两个平台的入口函数开始,看看 cocos2d-x 的执行流程到底为何?何以发生只执行了 AppDelegate 的构造函数,而没有析构函数。在查看 cocos2d-x 程序代码时,我们只关注 必要的 内容,何谓 必要,只要能解决我们此时的疑问即可!在两个平台的入口函数,我们看到如下内容:
不同的平台,却实现相同操作,创建&AppDelegate&变量和执行&run&方法。下面将以 Linux 平台为例,来说明程序是如何开始与结束的,因为
Linux 的内部实现要简单一点,而 Android 平台的实现稍显麻烦,Jni 之间来回调用,对我们理解 cocos2d-x 的执行流程反而有所&阻碍,况且 cocos2d-x 本身就是跨平台的程序。不必拘泥于特有平台的专有特性。
程序的流程 (这里以 Linux 的实现为主,其它平台触类旁通即可)
AppDelegate 与 CCApplication
我们从 main.cpp 中&CCApplication::sharedApplication()-&run();&这一句看起,这一句标志着, cocos2d-x 程序正式开始运行,一点点开始分析,我们定位到&sharedApplication()&方法的实现,这里只给出
必要 的代码,具体看一自己直接看源码:
从上面的内容可以看出,从&sharedApplication()&方法,到&run()&方法,在这之前,我们需要调用到它的构造函数,否则不能运行,这就是为什么在&CCApplication::sharedApplication()-&run();&之前,我们首先使用了&AppDelegate
&创建 AppDelegate 变量的原因! 嗯 !!&AppDelegate 和 CCAppliation 是什么关系! 由 AppDelegate 的定义我们可以知道,它是 CCApplication 的子类,在创建子类对象的时候,调用其构造函数的同时,父类构造函数也会执行,然后就将 AppDelegate 的对象赋给了 CCApplication
的静态变量,而在 AppDelegate 之中我们实现了&applicationDidFinishLaunching 方法,所以在 CCApplication 中 run 方法的开始处调用的就是 AppDelegate 之中的实现。而我们在此方法中我们初始化了一些变量,创建了第一个 CCScene 场景等,之后的控制权,便全权交给了&CCDirector::sharedDirector()-&mainLoop();&方法了。
(这里的实现机制,不做详细说明,简单说来:applicationDidFinishLaunching&是由 CCApplicationProtocol 定义,CCApplication 继承, AppDelegate 实现的 ~)
比较重要的所在,for 循环并没有循环退出条件,所以 run 方法永远不会返回。那么是怎么结束的呢!要学会存疑!
从 CCApplication 到 CCDirector
cocos2d-x 程序已经运行起来了,我们继续下一步,mainLoop 函数:
游戏的运行以场景为基础,每时每刻都有一个场景正在运行,其内部有一个场景栈,遵循后进后出的原则,当我们显示的调用 end() 方法,或者弹出当前场景之时,其自动判断,如果没有场景存在,也会触发 end() 方法,以说明场景运行的结束,而游戏如果没有场景,就像演出没有了舞台,程序进入最后收尾的工作,通过修改变量&m_bPurgeDirecotorInNextLoop&促使在程序&mainLoop&方法之内调用&purgeDirector&方法。
CCEGLView 的收尾工作
purgeDirector 方法之内,通过猜测与排查,最终定位到&m_pobOpenGLView-&end();&方法,在这里结束了 cocos2d-x 游戏进程。而 m_pobOpenGLView 有时何时赋值,它的具体实现又在哪里呢?我们可以在 AppDelegate 的&applicationDidFinishLaunching&方法中找到如下代码:
我们终于走到最后一步,看 CCEGLView 是如果负责收尾工作的:
end()&方法很简单,只需要看到最后一句&exit(0);&就明白了。
cocos2d-x 程序的结束流程
程序运行时期,由&mainLoop&方法维持运行着游戏之内的各个逻辑,当在弹出最后一个场景,或者直接调用&CCDirector::end();&方法后,触发游戏的清理工作,执行&purgeDirector&方法,从而结束了
CCEGLView(不同平台不同封装,PC使用OpenGl封装,移动终端封装的为 OpenGl ES) 的运行,调用其&end()&方法,从而直接执行&exit(0);&退出程序进程,从而结束了整个程序的运行。(Android
平台的 end() 方法内部通过Jni 方法 terminateProcessJNI(); 调用 Java 实现的功能,其功能一样,直接结束了当前运行的进程)
从程序的 main 方法开始,再创建 AppDelegate 等对象,运行过程中确实通过 exit(0); 来退出程序。所以我们看到了 AppDelegate 构造函数被调用,而其析构函数没有被调用的现象。
exit(0);&的执行,意味着我们的程序完全结束,当然我们的进程资源也会被操作系统释放。但是注意,这里的&在构造函数创建[资源],并且在析构函数中释放[资源] 并非绝对意义上的程序进程资源,在程序退出的时候,程序所使用的资源当然会被系统回收,但是如果我在构造函数调用网络接口初始化,析构在调用一次通知,所影响到的类似这种的&非本地资源&逻辑上的处理,而留下隐患。而通过理解
cocos2d-x 的运行机制,可以减少这种可能存在的隐患。
cocos2d-x 的整体把握
在本文通过解决一个小疑问,而去分析 cocos2d-x 游戏的运行流程,当然其中很多细致末叶我们并没有深入下去。不去解决这个疑问也可以,知道没有调用析构函数,那我就不调用便是 (这也是简单的解决方法,也不用觉得这不可行 )。这里只是借着这个疑问,对 cocos2d-x 的流程稍作探寻而已。也没有贴一堆 cocos2d-x 源码去分析,其思路也有迹可循。
什么是 cocos2d-x ,它是 cocos2d 一个 C++ 的实现,除 C++ 之外,有 python ,Objective-C 等其它语言的实现,那该怎么去理解 cocos2d ,可以这么理解,cocos2d 是一个编写 2D 游戏的通用形框架,这种框架提供了一个通用模型,而这种模型或者说架构是 无关语言与平台 的,说 cocos2d-x 使用 C++ 编写,其跨平台能力很强,但它能跑在浏览器上么?cocos2d 还是有着 html5 的实现,当然平台决定着语言的选择,而 cocos2d 能够适应这么多不同的语言和平台,其良好的设计,清晰的结构功不可没。
而对不同语言,对相同功能有着不同的封装,正如在本文问题中,在不同平台(Linux 和 Android),对相同功能有着不同的封装异曲同工。那么封装到最后,我们对 cocos2d 的理解就只剩下了,我们要写游戏,那么需要导演,场景、层、精灵、动作等 ~~ 组织好这个中之间的关系即可 ~
&&相关文章推荐
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:727082次
积分:6873
积分:6873
排名:第3080名
原创:36篇
转载:387篇
评论:53条
壶天的语像 .cn/wallydai zcmky的家 /zcmky/archive//1703397.html pjk1129专栏:http://blog.csdn.net/pjk1129/article/details/6593264 OpenGL ES学习网址 /portal.php?mod=list&catid=1 雨松MOMO的程序世界专栏:http://blog.csdn.net/xys/article/list/1
Techotopia:/index.php/Preparing_an_iOS_5_iPhone_App_to_use_iCloud_Storage 易飞扬:http://www.yifeiyang.net/ 禚 的iphone开发专栏:http://blog.csdn.net/diyagoanyhacker/article/category/846338 Marshal's Blog:/page/2 XML解析:/725/how-to-read-and-write-xml-documents-with-gdataxml
http :/dream-2011/powerful-asihttprequest-library-c.html
(2)(1)(2)(1)(3)(2)(3)(2)(17)(2)(2)(1)(2)(7)(2)(31)(15)(16)(7)(7)(7)(2)(2)(6)(4)(8)(4)(1)(4)(4)(1)(10)(4)(1)(3)(8)(8)(7)(1)(2)(21)(78)(112)

我要回帖

更多关于 cocos环境搭建 的文章

 

随机推荐