作为一个菜鸟,就得从头学起。
cocos2d-x文件目录里面自带了很多例子,其中就有一个SimpleGame。它属于射击类的小小小游戏。
开始学吧
首先新建个cocos2d-x项目,打开终端进入project-creator目录,输入:
./create_project.py -project MySimpleGame -package xxx.com -language cpp
回车,打开刚才建好的MySimpleGame项目,先加入所需的资源:
这些资源直接从自带的SimpleGame工程里面copy过来。我这里加的是HD目录下的。
进到HelloWorldScene.h,添加偷懒的宏定义并修改我们HelloWorldScene类的父类为CCLayerColor:
USING_NS_CC;
class HelloWorld : public CCLayerColor
然后在HelloWorldScene.cpp的init(),保留最后的return语句,其他的删掉,为了把游戏的背景设为白色,添加代码:
if ( !CCLayerColor::initWithColor(ccc4(255, 255, 255, 255)) )
{
return false;
}
接着为类添加两个private变量:
private:
CCSize visibleSize;
CCPoint origin;
在init()中用这两个变量保存屏幕的尺寸和坐标,再添加一个玩家精灵:
visibleSize = CCDirector::sharedDirector()->getVisibleSize();
origin = CCDirector::sharedDirector()->getVisibleOrigin();
CCSprite *player = CCSprite::create("Player.png",CCRectMake(0, 0, 27*2, 40*2));
player->setPosition(ccp(origin.x + player->getContentSize().width/2,origin.y + visibleSize.height/2));
this->addChild(player);
关于屏幕的适配看这里
运行程序看看:
接下来,会随机出现一些幽灵,那么就建一个数组来保存它们,添加成员变量,再增加一个private方法addTarget生产幽灵:
CCArray *_targets;
void addTarget();
下一步,就是到HelloWorldScene.cpp中实现addTarget方法:
void HelloWorld::addTarget()
{
CCSprite *target = CCSprite::create("Target.png", CCRectMake(0,0,27*2,40*2));
//让target出现的高度随机,但不要超出边界
float minY = target->getContentSize().height/2;
float maxY = visibleSize.height - target->getContentSize().height/2;
int rangeY = (int)(maxY - minY);
int actual = (rand() % rangeY) + minY; //这就是随机产生出来的target位置高
target->setPosition(ccp(visibleSize.width + target->getContentSize().width/2,origin.y + actual));
this->addChild(target);
//产生target的速度
int minDuration = 2;
int maxDuration = 4;
int rangeDuration = maxDuration - minDuration;
int actualDuration = (rand() % rangeDuration) + minDuration;
//target在会执行的动作,其实在这里就是直线移动。
CCFiniteTimeAction *actionMove = CCMoveTo::create((float)actualDuration, ccp(-target->getContentSize().width/2, actual));
target->runAction(CCSequence::create(actionMove,CCCallFuncN::create(this,callfuncN_selector(HelloWorld::spriteMoveFinished))));
target->setTag(1);
_targets->addObject(target);
}
上面的方法中用到了spriteMoveFinished方法,这是一个回调,下面还得定义两个public方法:
void spriteMoveFinished(CCObject *pSender);
void gameLogic(float dt);
然后去实现它们:
void HelloWorld::gameLogic(float dt)
{
this->addTarget();
}
void HelloWorld::spriteMoveFinished(cocos2d::CCObject *pSender)
{
}
接着,我们得去init()方法中,为_targets分配内存,再添加一个定时器来执行gameLogic方法:
_targets = new CCArray();
this->schedule(schedule_selector(HelloWorld::gameLogic),1);
运行我们的程序,就能看到幽灵出来了:
我们得发射子弹了,那就得点击屏幕,就得有Touch事件发生。
添加一个private数组存放子弹,并在init()中为它分配空间:
CCArray *_projectiles;
_projectiles = new CCArray;
随后我们得定义两个与Touch有关的public方法:
void registerWithTouchDispatcher();
virtual void ccTouchesEnded(CCSet *touches,CCEvent *event);
分别再实现它们:
void HelloWorld::registerWithTouchDispatcher()
{
CCDirector::sharedDirector()->getTouchDispatcher()->addStandardDelegate(this, 0);
}
void HelloWorld::ccTouchesEnded(cocos2d::CCSet *touches, cocos2d::CCEvent *event)
{
//获取touch的坐标
CCTouch *touch = (CCTouch*)(touches->anyObject());
CCPoint location = touch->getLocation();
//产生子弹
CCSprite *projectile = CCSprite::create("Projectile.png", CCRectMake(0, 0, 20*2, 20*2));
projectile->setPosition( ccp(origin.x+20, origin.y+visibleSize.height/2) );
//子弹偏移
float offX = location.x - projectile->getPosition().x;
float offY = location.y - projectile->getPosition().y;
// 超边界,不发
if (offX <= 0) return;
this->addChild(projectile);
//确定子弹发射位置
float realX = origin.x+visibleSize.width + (projectile->getContentSize().width/2);
float ratio = offY / offX;
float realY = (realX * ratio) + projectile->getPosition().y;
CCPoint realDest = ccp(realX, realY);
//子弹能发射多远
float offRealX = realX - projectile->getPosition().x;
float offRealY = realY - projectile->getPosition().y;
float length = sqrtf((offRealX * offRealX) + (offRealY*offRealY));
float velocity = 480/1; // 480pixels/1sec
float realMoveDuration = length/velocity;
//执行动作
projectile->runAction( CCSequence::create(
CCMoveTo::create(realMoveDuration, realDest),
CCCallFuncN::create(this,
callfuncN_selector(HelloWorld::spriteMoveFinished)),
NULL) );
projectile->setTag(2);
_projectiles->addObject(projectile); //子弹加入数组
}
对于registerWithTouchDispatcher的用法可以看这篇博客
运行程序,touch屏幕我们就可发射子弹了:
我们会发现,现在子弹还不能消灭幽灵,let's do it!
添加一个public方法:
void updateGame(float dt);
然后实现:
void HelloWorld::updateGame(float dt)
{
CCArray *projectilesToDelete = new CCArray;
CCObject* it = NULL;
CCObject* jt = NULL;
CCARRAY_FOREACH(_projectiles, it)
{
//算出子弹框
CCSprite *projectile = dynamic_cast<CCSprite*>(it);
CCRect projectileRect = CCRectMake(
projectile->getPosition().x - (projectile->getContentSize().width/2),
projectile->getPosition().y - (projectile->getContentSize().height/2),
projectile->getContentSize().width,
projectile->getContentSize().height);
CCArray* targetsToDelete =new CCArray;
//算出打击的目标框
CCARRAY_FOREACH(_targets, jt)
{
CCSprite *target = dynamic_cast<CCSprite*>(jt);
CCRect targetRect = CCRectMake(
target->getPosition().x - (target->getContentSize().width/2),
target->getPosition().y - (target->getContentSize().height/2),
target->getContentSize().width,
target->getContentSize().height);
//表示打中了目标,把这些目标加入到数组中
if (projectileRect.intersectsRect(targetRect))
{
targetsToDelete->addObject(target);
}
}
//移除这些被打中的目标
CCARRAY_FOREACH(targetsToDelete, jt)
{
CCSprite *target = dynamic_cast<CCSprite*>(jt);
_targets->removeObject(target);
this->removeChild(target, true);
}
if (targetsToDelete->count() > 0)
{
projectilesToDelete->addObject(projectile);
}
targetsToDelete->release();
}
//移除打中目标的子弹
CCARRAY_FOREACH(projectilesToDelete, it)
{
CCSprite* projectile = dynamic_cast<CCSprite*>(it);
_projectiles->removeObject(projectile);
this->removeChild(projectile, true);
}
projectilesToDelete->release(); //释放
}
我写了点简单的注释,有助于理解。
运行程序以后,对准幽灵发射子弹吧。
我们就会发现,幽灵永远也打不完,这样无休止的打下去,是人都会疯了。
So,我们得有个规则来判断输赢。
win:消灭5个幽灵
lose:幽灵跑到了我们的后面
好,有了规则后,就来执行吧。
首先,新建一个C++类,文件名为GameOverScene,用下面的代码替换GameOverScene.h中的代码:
#ifndef __MySimpleGame__GameOverScene__
#define __MySimpleGame__GameOverScene__
#include "cocos2d.h"
USING_NS_CC;
class GameOverLayer : public CCLayerColor
{
public:
GameOverLayer():_label(NULL) {};
virtual ~GameOverLayer();
bool init();
CREATE_FUNC(GameOverLayer);
void gameOverDone();
CC_SYNTHESIZE_READONLY(CCLabelTTF*, _label, Label);
};
class GameOverScene : public CCScene
{
public:
GameOverScene():_layer(NULL) {};
~GameOverScene();
bool init();
CREATE_FUNC(GameOverScene);
CC_SYNTHESIZE_READONLY(GameOverLayer*, _layer, Layer);
};
#endif /* defined(__MySimpleGame__GameOverScene__) */
上面的代码,声明了一个布景类和一个场景类,用来显示咱们输赢后的结果。
用下来的代码替换GameoverScene.cpp中的代码:
#include "GameOverScene.h"
#include "HelloWorldScene.h"
bool GameOverScene::init()
{
if( CCScene::init() )
{
this->_layer = GameOverLayer::create();
this->_layer->retain();
this->addChild(_layer);
return true;
}
else
{
return false;
}
}
GameOverScene::~GameOverScene()
{
if (_layer)
{
_layer->release();
_layer = NULL;
}
}
bool GameOverLayer::init()
{
if ( CCLayerColor::initWithColor( ccc4(255,255,255,255) ) )
{
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
this->_label = CCLabelTTF::create("","Artial", 32);
_label->retain();
_label->setColor( ccc3(0, 0, 0) );
_label->setPosition( ccp(winSize.width/2, winSize.height/2) );
this->addChild(_label);
this->runAction( CCSequence::create(
CCDelayTime::create(3),
CCCallFunc::create(this,
callfunc_selector(GameOverLayer::gameOverDone)),
NULL));
return true;
}
else
{
return false;
}
}
void GameOverLayer::gameOverDone()
{
CCDirector::sharedDirector()->replaceScene( HelloWorld::scene() );
}
GameOverLayer::~GameOverLayer()
{
if (_label)
{
_label->release();
_label = NULL;
}
}
这里理解起来也没什么难度,所以我就直接用自带的代码了。
接下来,回到HelloWorldScene.h中,添加一个private变量,用来判断消灭了多少幽灵:
int _projectilesDestroyed;
然后到HelloWorldScene.cpp的开头添加头文件:
#include "GameOverScene.h"
在updateGame中找到下面的代码处:在其后面加上代码:
_projectilesDestroyed++;
if (_projectilesDestroyed >= 5) //移除的目标数目>5,You Win!
{
GameOverScene *gameOverScene = GameOverScene::create();
gameOverScene->getLayer()->getLabel()->setString("You Win!");
CCDirector::sharedDirector()->replaceScene(gameOverScene);
}
这段代码很明显,当我们消灭了5个幽灵以后,就切换到gameOverScene显示“You Win!”.
那“You Lose”去哪里了?
看一下我们的spriteMoveFinished方法,是空的,为其添加下面的代码:
CCSprite *sprite = (CCSprite *)pSender;
this->removeChild(sprite, true);
if (sprite->getTag() == 1) // target
{
_targets->removeObject(sprite);
GameOverScene *gameOverScene = GameOverScene::create();
gameOverScene->getLayer()->getLabel()->setString("You Lose");
CCDirector::sharedDirector()->replaceScene(gameOverScene);
}
else if (sprite->getTag() == 2) // projectile
{
_projectiles->removeObject(sprite);
}
早前我们分别给target和projectile精灵设置了tag值,现在就可以用这个值来判断传过来的精灵是哪一个了。
编译运行游戏:
Yes,I‘am win.
如果有需要可以点这里下载源码,当然还可以直接看Cocos2d-x自带的SimpleGame代码,几乎是一样的。