和很多游戏引擎一样Cocos2dx有导演(CCDirector)、场景(CCScene)、层(CCLayer)、菜单(CCMenu)、精灵(CCSprite)这些概念。
这些东西都继承了节点类(CCNode)。他们都具有(addChild)方法能将某些场景加入另一个场景中。某些精灵加入某个精灵中。这是用树做的。因为整个游戏只有一个导演类。那么也就是说这是树的根。
然后这些节点能绑定事件。
CCNode::schedule
源码中这里用了适配模式。
void CCNode::schedule(SEL_SCHEDULE selector)
{
this->schedule(selector, 0.0f, kCCRepeatForever, 0.0f);
}
void CCNode::schedule(SEL_SCHEDULE selector, float interval)
{
this->schedule(selector, interval, kCCRepeatForever, 0.0f);
}
.......
Cocos2dx有自己的一套垃圾回收装置。算法是当类被引用时+1类没有被引用时-1当为0时自动回收。
但这只是对crate()出来的类。而是用new开辟出的空间我们可以用宏定义清除。
#define CC_SAFE_DELETE(p) do { if(p) { delete (p); (p) = 0; } } while(0)
#define CC_SAFE_DELETE_ARRAY(p) do { if(p) { delete[] (p); (p) = 0; } } while(0)
#define CC_SAFE_FREE(p) do { if(p) { free(p); (p) = 0; } } while(0)
#define CC_SAFE_RELEASE(p) do { if(p) { (p)->release(); } } while(0)
#define CC_SAFE_RELEASE_NULL(p) do { if(p) { (p)->release(); (p) = 0; } } while(0)
#define CC_SAFE_RETAIN(p) do { if(p) { (p)->retain(); } } while(0)
#define CC_BREAK_IF(cond) if(cond) break
以下是我简单做的代码中的一个核心类
#include "HelloWorldScene.h"
#include "SimpleAudioEngine.h"
#include "GameOverLayer.h"
USING_NS_CC;
CCScene* HelloWorld::scene()
{
// 'scene' is an autorelease object
CCScene *scene = CCScene::create();
// 'layer' is an autorelease object
HelloWorld *layer = HelloWorld::create();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
// on "init" you need to initialize your instance 初始化该类,C++是在构造函数中初始化
bool HelloWorld::init()
{
//
// 1. super init first
if ( !CCLayerColor::initWithColor(ccc4(0,255,0,255))) //红 绿 蓝 alpha(透明度)
{
return false;
}
#if 0
CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();
/
// 2. add a menu item with "X" image, which is clicked to quit the program
// you may modify it.
// add a "close" icon to exit the progress. it's an autorelease object
CCMenuItemImage *pCloseItem = CCMenuItemImage::create(
"CloseNormal.png",
"CloseSelected.png",
this,
menu_selector(HelloWorld::menuCloseCallback));
pCloseItem->setPosition(ccp(origin.x + visibleSize.width - pCloseItem->getContentSize().width/2 ,
origin.y + pCloseItem->getContentSize().height/2));
// create menu, it's an autorelease object
CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);
pMenu->setPosition(CCPointZero);
this->addChild(pMenu,1); //第一个参数表示层,第2个参数是z轴的位置,第二个参数越大那么就越靠前。
/
// 3. add your codes below...
// add a label shows "Hello World"
// create and initialize a label
CCLabelTTF* pLabel = CCLabelTTF::create("Hello World", "Arial", 24);
// position the label on the center of the screen
pLabel->setPosition(ccp(origin.x + visibleSize.width/2,
origin.y + visibleSize.height - pLabel->getContentSize().height));
// add the label as a child to this layer
this->addChild(pLabel, 1);
// add "HelloWorld" splash screen"
CCSprite* pSprite = CCSprite::create("HelloWorld.png");
// position the sprite on the center of the screen
pSprite->setPosition(ccp(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));
// add the sprite as a child to this layer
this->addChild(pSprite, 0);
#endif
CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize(); //获取长宽
CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin(); //获取原点坐标
CCSprite* pSprite = CCSprite::create("Player.png");
pSprite->setPosition(ccp(origin.x+20,origin.y+visibleSize.height/2));
this->addChild(pSprite,0); //第二个参数是显示优先级
#if 0
CCMenuItemImage *pMenuItem = CCMenuItemImage::create("button2.png",
"button2.png",
"button2.png",
this,
menu_selector(HelloWorld::responsFunc)
);
pMenuItem->setPosition(ccp(30,30));
CCMenu* pMenu = CCMenu::create(pMenuItem,NULL);
this->addChild(pMenu);
#endif
//Class::crate()不需要手动 new 需要手动释放
_projs = new CCArray; //设置飞镖
_targets = new CCArray; //设置目标
//添加一个精灵并且一开始就能移动.
srand(time(NULL));
this->schedule(schedule_selector(HelloWorld::gameLogic),2);
this->schedule(schedule_selector(HelloWorld::update));
//ps:this->schedule(schedule_selector(HelloWorld::gameLogic,2));会发生鬼畜
this->setTouchEnabled(true);
CocosDenshion::SimpleAudioEngine::sharedEngine()->playBackgroundMusic("background-music-aac.wav",true);
_successCount = 0;
return true;
}
void HelloWorld::update(float delta) //delta = 1.0/fps
{
CCArray *projToDelete = new CCArray;
CCArray *targetToDelete= new CCArray;
CCObject *itarget;
CCObject *iproj;
CCARRAY_FOREACH(_targets,itarget)
{
CCSprite *target = (CCSprite*)itarget; //设置当前目标转化为经理
CCRect targetZone = CCRectMake(target->getPositionX(), //获取目标的边界
target->getPositionY(),
target->getContentSize().width,
target->getContentSize().height);
CCARRAY_FOREACH(_projs,iproj) //循环判定是否有飞镖打中目标
{
CCSprite *proj = (CCSprite*)iproj;
CCRect projZone = CCRectMake(proj->getPositionX(), //获取飞镖边界
proj->getPositionY(),
proj->getContentSize().width,
proj->getContentSize().height);
if(projZone.intersectsRect(targetZone)) //如果有交集
{
if(++_successCount>=5)
{
CCScene *overScene = GameOverLayer::scene();
CCDirector::sharedDirector()->replaceScene(overScene); //跳转场景
}
projToDelete->addObject(proj); //将需要清除的飞镖和目标加入队列
targetToDelete->addObject(target);
}
} //end of iterate proj
} //end of iterate target
CCARRAY_FOREACH(projToDelete,iproj) //循环清除飞镖
{
_projs->removeObject(iproj);
CCSprite *proj = (CCSprite*)iproj;
proj->removeFromParentAndCleanup(true);
}
CCARRAY_FOREACH(targetToDelete,itarget) //循环清除目标
{
_targets->removeObject(itarget);
CCSprite *target = (CCSprite*)itarget;
target->removeFromParentAndCleanup(true);
}
CC_SAFE_RELEASE(targetToDelete);
CC_SAFE_RELEASE(projToDelete);
}
HelloWorld::~HelloWorld()
{
CC_SAFE_RELEASE(_projs);
CC_SAFE_RELEASE(_targets);
}
void HelloWorld::ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent)
{
CCTouch *touch =(CCTouch*)pTouches->anyObject(); //获取触摸点坐标
CCPoint locInView = touch->getLocationInView(); //获得触摸点UI坐标
CCPoint loc = CCDirector::sharedDirector()->convertToGL(locInView); //将UI坐标转换为GL坐标
if(loc.x < 30) return;
CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect("pew-pew-lei.wav");
CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
CCSprite *proj = CCSprite::create("Projectile.png");
proj->setPosition(ccp(30,visibleSize.height/2));
double ax = 30;
double ay = visibleSize.height/2;
double D = sqrt(visibleSize.width*visibleSize.width+visibleSize.height*visibleSize.height);
double d = sqrt((loc.x-ax)*(loc.x-ax)+(loc.y-ay)*(loc.y-ay));
double cx = (loc.x-ax)*D/d+ax;
double cy = (loc.y-ay)*D/d+ay;
CCMoveTo *move = CCMoveTo::create(D/320,ccp(cx,cy));
CCCallFuncN *dis = CCCallFuncN::create(this,callfuncN_selector(HelloWorld::disappear));
CCSequence *actions = CCSequence::create(move,dis,NULL); //如果CCSequence最后没加NULL编译能通过运行会弹对话框;
proj->runAction(actions);
this->addChild(proj); //将精灵加入层中
_projs->addObject(proj); //将精灵加入数组中
proj->setTag(2); //设置飞镖标记为2;
}
void HelloWorld::gameLogic(float t) // t就是上面的第2个参数 schedule(...,2) 是2 这么一个参数
{
this->crateTarget();
}
//
void HelloWorld::crateTarget()
{
CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
CCSprite *mytarget = CCSprite::create("Target.png");
int y = rand()%(int)(visibleSize.height);
mytarget->setPosition(ccp(visibleSize.width-30,y));
this->addChild(mytarget);
_targets->addObject(mytarget); //将怪兽加入数组
mytarget->setTag(1); //设置怪物标记为1
CCMoveTo *move = CCMoveTo::create(2,ccp(30,y)); //第一个参数是运动时间,第二个参数是运动方向点
CCCallFuncN *selfDefineAction = CCCallFuncN::create(this,callfuncN_selector(HelloWorld::disappear));
CCSequence *actions = CCSequence::create(move,selfDefineAction,NULL);
mytarget->runAction(actions);
}
void HelloWorld::responsFunc(CCObject *obj)
{
//CCLog("click");
CCMoveTo *move = CCMoveTo::create(2,ccp(30,40)); //第一个参数是运动时间,第二个参数是运动方向点
CCCallFuncN *selfDefineAction = CCCallFuncN::create(this,callfuncN_selector(HelloWorld::disappear));
CCSequence *action = CCSequence::create(move,selfDefineAction,NULL);
target->runAction(action);
}
void HelloWorld::disappear(CCNode *who)
{
//who->setPosition(ccp(20,20));
//who->setScale(2); //放大两倍
int tag = who->getTag();
if(1 == tag)
{
CCLog("mylog-----------------target disappear\n");
_targets->removeObject(who);
CCScene *overScene = GameOverLayer::scene();
CCLog("mylog-----------------get GameOverLayer::scene\n");
GameOverLayer *layer =(GameOverLayer*)overScene->getChildByTag(100);
CCLog("mylog-----------------get layer by Tag\n");
/*CCLabelTTF *tmp = layer->_label;
if(tmp==NULL) CCLog("mylog-----------------tmp==null\n");
CCLog("mylog-----------------get _label\n");
tmp->getString();
CCLog("mylog-----------------getString()\n");
tmp->setString("You lose");
CCLog("mylog-----------------set _label=You lose\n");*/
CCDirector::sharedDirector()->replaceScene(overScene);
CCLog("mylog-----------------success Change Scene\n");
}
else if(2 == tag)
{
_projs->removeObject(who);
}
who->removeFromParentAndCleanup(true);
}
void HelloWorld::menuCloseCallback(CCObject* pSender)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) || (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)
CCMessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");
#else
CCDirector::sharedDirector()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
exit(0);
#endif
#endif
}