一、用python创建一个cocos2d-x-2.2.1工程
打开cmd命令行cd 到cocos2d-x-2.2.1\tools\project-creator目录:
1 2 3 | e: cd E:\cocos2d-x-2.2.1\tools\project-creator python create_project.py -project MyDemo -package com.blogchen.mydemo -language cpp |
解释下python create_project.py -project MyDemo -package com.blogchen.mydemo -language cpp这句代码的参数。
需要我们关注的只有两个,一个是MyDemo,这个MyDemo就是你们的工程名,随便取,然后是com.blogchen.mydemo学过android的一眼就知道com.blogchen.mydemo的作用—包名,这个其实也是随便取的,但是一般来说是域名的倒置,当然你取x.o.x.o也是可以的,但是这个有个要注意的是,要保证唯一性,也就是你确定别人不会用这个名字,因为这个当编译为android包时,就代表了android应用的唯一标识,如果你的这个名字和别人的包名字相重,那么你的apk将无法和别人的apk共存在手机里面,加上现在的应用市场都有验证机器,也就代表你的apk无法发布到应用市场去。
命令执行成功后的信息:
1
2
3
4
5
6
7
8
9
10
11
12
|
proj.ios : Done!
proj.android : Done!
proj.win32 : Done!
proj.winrt : Done!
proj.wp8 : Done!
proj.mac : Done!
proj.blackberry : Done!
proj.linux : Done!
proj.marmalade : Done!
New project has been created in
this
path: E:\cocos2d-x-
2.2
.
1
\tools\project-crea
tor/../../projects/MyDemo
Have Fun!
|
那么在cocos2d-x-2.2.1\projects目录下就能找到你的工程了。进入cocos2d-x-2.2.1\projects\MyDemo\proj.win32
双击MyDemo.sln:
这个就是我们的工程了,Ctrl+F5试试:
嗬嗬嗬嗬,完毕,果然新版本配置越来越方便了。
然而,有朋友可能会抱怨:每次命令行建立工程太麻烦了啊。懒惰使人进步,于是就用批处理来解决吧。代码如下:
1
2
3
4
5
6
7
|
@echo
off
E:
cd E:\cocos2d-x-
2.2
.
1
\tools\project-creator
set /p var1=请输入工程名:
set /p var2=请输入包名:
python create_project.py -project %var1% -
package
%var2% -language cpp
pause
|
运行效果如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
请输入工程名: HelloCocos
请输入包名:com.blogchen.hello
proj.ios : Done!
proj.android : Done!
proj.win32 : Done!
proj.winrt : Done!
proj.wp8 : Done!
proj.mac : Done!
proj.blackberry : Done!
proj.linux : Done!
proj.marmalade : Done!
New project has been created in
this
path: E:\cocos2d-x-
2.2
.
1
\tools\project-crea
tor/../../projects/HelloCocos
Have Fun!
Press any key to
continue
. . .
|
大家自行建立xxx.cmd文件,然后把代码复制过去即可,路径根据自己的环境改变一下就可以。
二、游戏素材http://download.csdn.net/detail/akof1314/4857315在这个链接里可以下载到
三、游戏需要一个白色的背景,最简单的方法是使用CCLayerColor,将HelloWorldScene.h文件"HelloWorld"类改为如下:
1
|
class HelloWorld :
public cocos2d::CCLayerColor
|
首先添加玩家,让玩家位于左边屏幕中间,将HelloWorldScene.cpp文件的init函数,改为如下:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
bool HelloWorld::init()
{ bool bRet = false; do { CC_BREAK_IF(! CCLayerColor::initWithColor(ccc4( 255, 255, 255, 255))); CCSize winSize = CCDirector::sharedDirector()->getWinSize(); CCSprite *player = CCSprite::create( "player.png", CCRectMake( 0, 0, 27, 40)); player->setPosition(ccp(player->getContentSize().width / 2, winSize.height / 2)); this->addChild(player); bRet = true; } while ( 0); return bRet; } |
四、编译运行,可以看到玩家精灵在白色背景上,如下图所示:
6.接下来添加怪物,并且让怪物可以移动,我们在屏幕右边创建怪物,建立动作让它们向左移动,增加 addMonster方法,代码如下:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
void HelloWorld::addMonster()
{ CCSprite *monster = CCSprite::create( "monster.png"); CCSize winSize = CCDirector::sharedDirector()->getWinSize(); int minY = monster->getContentSize().height / 2; int maxY = winSize.height - monster->getContentSize().height / 2; int rangeY = maxY - minY; int actualY = (rand() % rangeY) + minY; monster->setPosition(ccp(winSize.width + monster->getContentSize().width / 2, actualY)); this->addChild(monster); int minDuration = 2. 0; int maxDuration = 4. 0; int rangeDuration = maxDuration - minDuration; int actualDuration = (rand() % rangeDuration) + minDuration; CCMoveTo *actionMove = CCMoveTo::create(actualDuration, ccp(-monster->getContentSize().width / 2, actualY)); CCCallFuncN *actionMoveDone = CCCallFuncN::create( this, callfuncN_selector(HelloWorld::spriteMoveFinished)); monster->runAction(CCSequence::create(actionMove, actionMoveDone, NULL)); } |
在右边屏幕以随机的位置添加怪物精灵,注意计算精灵的位置坐标,默认描点在中心,不要让怪物截断了。然后再以2~4秒的随机总时间,让怪物从右边移动到左边,移动出边界后,即回调函数spriteMoveFinished,进行删除精灵对象,增加的spriteMoveFinished方法如下:
1
2 3 4 5 |
void HelloWorld::spriteMoveFinished(CCNode *sender)
{ CCSprite *sprite = (CCSprite*)sender; this->removeChild(sprite, true); } |
1
|
this->schedule(schedule_selector(HelloWorld::gameLogic),
1.
0);
|
1
2 3 4 |
void HelloWorld::gameLogic(
float dt )
{ this->addMonster(); } |
8.接着让玩家可以射击子弹,当用户在屏幕点击时,就让玩家往点击的方向进行发送子弹,用户的屏幕点击点并不是子弹移动的最终地,借用原文的一张图片来说明:
要让层可以支持触摸,需要在 init方法,添加如下代码:
1
|
this->setTouchEnabled(
true);
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
void HelloWorld::ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent)
{ CCTouch *touch = (CCTouch*)pTouches->anyObject(); CCPoint location = this->convertTouchToNodeSpace(touch); CCSize winSize = CCDirector::sharedDirector()->getWinSize(); CCSprite *projectile = CCSprite::create( "projectile.png"); projectile->setPosition(ccp( 20, winSize.height / 2)); CCPoint offset = ccpSub(location, projectile->getPosition()); if (offset.x <= 0) { return; } this->addChild(projectile); int realX = winSize.width + projectile->getContentSize().width / 2; float ratio = ( float)offset.y / ( float)offset.x; int realY = realX * ratio + projectile->getPosition().y; CCPoint realDest = ccp(realX, realY); int offRealX = realX - projectile->getPosition().x; int offRealY = realY - projectile->getPosition().y; float length = sqrtf(offRealX * offRealX + offRealY * offRealY); float velocity = 480 / 1; float realMoveDuration = length / velocity; projectile->runAction(CCSequence::create(CCMoveTo::create(realMoveDuration, realDest), CCCallFuncN::create( this, callfuncN_selector(HelloWorld::spriteMoveFinished)), NULL)); } |
首先,得到触摸点,然后创建子弹精灵,算出触摸点与子弹初始位置之差,若触摸点在初始位置的前方(即玩家前方),则添加子弹到层上。以同比例方法,计算出子弹飞向屏幕右边的最终坐标。然后再用勾股定理计算飞行长度,假定速度为每秒480像素,则计算出飞行总时间。之后就是让子弹执行给定的飞行动作,以及之后的删除自身调用。
9.编译运行,往屏幕点击,可以看到子弹发射出去,如下图所示:
10.当子弹碰到怪物时,怪物被消灭,子弹消失,即碰撞检测。需要在场景中跟踪目标和子弹,在HelloWorldScene.h声明如下:
1
2 |
cocos2d::CCArray *_monsters;
cocos2d::CCArray *_projectiles; |
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
void HelloWorld::addMonster()
{ CCSprite *monster = CCSprite::create( "monster.png"); CCSize winSize = CCDirector::sharedDirector()->getWinSize(); int minY = monster->getContentSize().height / 2; int maxY = winSize.height - monster->getContentSize().height / 2; int rangeY = maxY - minY; int actualY = (rand() % rangeY) + minY; monster->setPosition(ccp(winSize.width + monster->getContentSize().width / 2, actualY)); this->addChild(monster); int minDuration = 2. 0; int maxDuration = 4. 0; int rangeDuration = maxDuration - minDuration; int actualDuration = (rand() % rangeDuration) + minDuration; CCMoveTo *actionMove = CCMoveTo::create(actualDuration, ccp(-monster->getContentSize().width / 2, actualY)); CCCallFuncN *actionMoveDone = CCCallFuncN::create( this, callfuncN_selector(HelloWorld::spriteMoveFinished)); monster->runAction(CCSequence::create(actionMove, actionMoveDone, NULL)); } |
在右边屏幕以随机的位置添加怪物精灵,注意计算精灵的位置坐标,默认描点在中心,不要让怪物截断了。然后再以2~4秒的随机总时间,让怪物从右边移动到左边,移动出边界后,即回调函数spriteMoveFinished,进行删除精灵对象,增加的spriteMoveFinished方法如下:
1
2 3 4 5 |
void HelloWorld::spriteMoveFinished(CCNode *sender)
{ CCSprite *sprite = (CCSprite*)sender; this->removeChild(sprite, true); } |
1
|
this->schedule(schedule_selector(HelloWorld::gameLogic),
1.
0);
|
1
2 3 4 |
void HelloWorld::gameLogic(
float dt )
{ this->addMonster(); } |
七、接着让玩家可以射击子弹,当用户在屏幕点击时,就让玩家往点击的方向进行发送子弹,用户的屏幕点击点并不是子弹移动的最终地,借用原文的一张图片来说明:
要让层可以支持触摸,需要在 init方法,添加如下代码:
1
|
this->setTouchEnabled(
true);
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
void HelloWorld::ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent)
{ CCTouch *touch = (CCTouch*)pTouches->anyObject(); CCPoint location = this->convertTouchToNodeSpace(touch); CCSize winSize = CCDirector::sharedDirector()->getWinSize(); CCSprite *projectile = CCSprite::create( "projectile.png"); projectile->setPosition(ccp( 20, winSize.height / 2)); CCPoint offset = ccpSub(location, projectile->getPosition()); if (offset.x <= 0) { return; } this->addChild(projectile); int realX = winSize.width + projectile->getContentSize().width / 2; float ratio = ( float)offset.y / ( float)offset.x; int realY = realX * ratio + projectile->getPosition().y; CCPoint realDest = ccp(realX, realY); int offRealX = realX - projectile->getPosition().x; int offRealY = realY - projectile->getPosition().y; float length = sqrtf(offRealX * offRealX + offRealY * offRealY); float velocity = 480 / 1; float realMoveDuration = length / velocity; projectile->runAction(CCSequence::create(CCMoveTo::create(realMoveDuration, realDest), CCCallFuncN::create( this, callfuncN_selector(HelloWorld::spriteMoveFinished)), NULL)); } |
首先,得到触摸点,然后创建子弹精灵,算出触摸点与子弹初始位置之差,若触摸点在初始位置的前方(即玩家前方),则添加子弹到层上。以同比例方法,计算出子弹飞向屏幕右边的最终坐标。然后再用勾股定理计算飞行长度,假定速度为每秒480像素,则计算出飞行总时间。之后就是让子弹执行给定的飞行动作,以及之后的删除自身调用。
八、编译运行,往屏幕点击,可以看到子弹发射出去,如下图所示:
九、当子弹碰到怪物时,怪物被消灭,子弹消失,即碰撞检测。需要在场景中跟踪目标和子弹,在HelloWorldScene.h声明如下:
1
2 |
cocos2d::CCArray *_monsters;
cocos2d::CCArray *_projectiles; |
在构造函数和析构函数,添加如下:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
HelloWorld::HelloWorld()
{ _monsters = NULL; _projectiles = NULL; } HelloWorld::~HelloWorld() { if (_monsters) { _monsters->release(); _monsters = NULL; } if (_projectiles) { _projectiles->release(); _projectiles = NULL; } } |
然后在init函数中初始化这两个数组:
1
2 3 4 |
this->_monsters = CCArray::create();
this->_monsters->retain(); this->_projectiles = CCArray::create(); this->_projectiles->retain(); |
修改addMonster函数,为怪物精灵添加标签,并加入到数组,代码如下:
1
2 |
monster->setTag(
1);
_monsters->addObject(monster); |
修改ccTouchesEnded函数,为子弹精灵添加标签,并加入到数组,代码如下:
1
2 |
projectile->setTag(
2);
_projectiles->addObject(projectile); |
然后修改spriteMoveFinished函数,增加如下代码:
1
2 3 4 5 6 7 8 |
if (sprite->getTag() ==
1)
{ _monsters->removeObject(sprite); } else if (sprite->getTag() == 2) { _projectiles->removeObject(sprite); } |
添加如下方法:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
void HelloWorld::update(
float dt)
{ CCArray *projectilesToDelete = CCArray::create(); CCObject *pObject = NULL; CCObject *pObject2 = NULL; CCARRAY_FOREACH(_projectiles, pObject) { CCSprite *projectile = (CCSprite*)pObject; CCArray *monstersToDelete = CCArray::create(); CCARRAY_FOREACH(_monsters, pObject2) { CCSprite *monster = (CCSprite*)pObject2; if( projectile->boundingBox().intersectsRect(monster->boundingBox())) // 此处与以前有修改
{
monstersToDelete->addObject(monster); } } CCARRAY_FOREACH(monstersToDelete, pObject2) { CCSprite *monster = (CCSprite*)pObject2; _monsters->removeObject(monster); this->removeChild(monster, true); } if (monstersToDelete->count() > 0) { projectilesToDelete->addObject(projectile); } monstersToDelete->release(); } CCARRAY_FOREACH(projectilesToDelete, pObject) { CCSprite *projectile = (CCSprite*)pObject; _projectiles->removeObject(projectile); this->removeChild(projectile, true); } projectilesToDelete->release(); } |
遍历子弹数组,计算每一个子弹所可能遇到的怪物,用它们各自的边界框进行交叉检测,检测到交叉,则将怪物对象放入ToDelete(待删除)数组,不能在遍历的时候删除一个对象。若是子弹遇到了怪物,也需要放入ToDelete(待删除)数组。然后从场景和数组中移动掉。同样,也在init函数,安装定时器,代码如下:
1
|
this->schedule(schedule_selector(HelloWorld::update));
|
十、编译运行,这时当子弹和怪物碰撞时,它们就会消失;
十一、添加音效,在init函数添加背景音乐,代码如下:
1
|
CocosDenshion::SimpleAudioEngine::sharedEngine()->playBackgroundMusic(
"background-music-aac.wav");
|
在ccTouchesEnded函数,添加子弹音效,代码如下:
1
|
CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect(
"pew-pew-lei.wav");
|
十二、接下来,创建一个新的场景,来指示"You Win"或者"You Lose"。右键 工程,"Add"→"Class..."→"C++"→"Add","Base class"为CCLayerColor,"Class name"为GameOverLayer,如下图所示:
GameOverLayer.h文件代码为:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#pragma once
#include "cocos2d.h" class GameOverLayer : public cocos2d::CCLayerColor { public: GameOverLayer( void); ~GameOverLayer( void); bool initWithWon( bool won); static cocos2d::CCScene* sceneWithWon( bool won); static GameOverLayer* createWithWon( bool won); void gameOverDone(); }; |
GameOverLayer.cpp文件代码为:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
#include
"GameOverLayer.h"
#include "HelloWorldScene.h" using namespace cocos2d; GameOverLayer::GameOverLayer( void) { } GameOverLayer::~GameOverLayer( void) { } GameOverLayer* GameOverLayer::createWithWon( bool won) { GameOverLayer *pRet = new GameOverLayer(); if (pRet && pRet->initWithWon(won)) { pRet->autorelease(); return pRet; } else { CC_SAFE_DELETE(pRet); return NULL; } } bool GameOverLayer::initWithWon( bool won) { bool bRet = false; do { CC_BREAK_IF(! CCLayerColor::initWithColor(ccc4( 255, 255, 255, 255))); char *message; if (won) { message = "You Won!"; } else { message = "You Lose :["; } CCSize winSize = CCDirector::sharedDirector()->getWinSize(); CCLabelTTF *label = CCLabelTTF::create(message, "Arial", 32); 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)); bRet = true; } while ( 0); return bRet; } cocos2d::CCScene* GameOverLayer::sceneWithWon( bool won) { CCScene * scene = NULL; do { scene = CCScene::create(); CC_BREAK_IF(! scene); GameOverLayer *layer = GameOverLayer::createWithWon(won); CC_BREAK_IF(! layer); scene->addChild(layer); } while ( 0); return scene; } void GameOverLayer::gameOverDone() { CCDirector::sharedDirector()->replaceScene(HelloWorld::scene()); } |
游戏结束时,切换到以上所建的场景,场景上的层显示一个文本,在3秒之后返回到HelloWorld场景中。
十三、最后,为游戏添加一些游戏逻辑。记录玩家消灭怪物的数量,进而决定该玩家输赢。在HelloWorldScene.h文件中,添加如下:
1
|
int _monstersDestroyed;
|
在HelloWorldScene.cpp文件,HelloWorld()构造函数,添加如下代码:
1
|
_monstersDestroyed =
0;
|
添加头文件引用:
1
|
#include
"GameOverLayer.h"
|
在update定时函数中,monstersToDelete循环removeChild(monster, true)的后面添加被消灭怪物的计数,并判断胜利条件,代码如下:
1
2 3 4 5 6 |
_monstersDestroyed++;
if (_monstersDestroyed > 30) { CCScene *gameOverScene = GameOverLayer::sceneWithWon( true); CCDirector::sharedDirector()->replaceScene(gameOverScene); } |
最后为玩家添加失败条件,规定只要有一只怪物跑到左边屏幕里,则玩家失败,在spriteMoveFinished函数里,sprite->getTag() == 1条件的后面,添加如下:
1
2 |
CCScene *gameOverScene = GameOverLayer::sceneWithWon(
false);
CCDirector::sharedDirector()->replaceScene(gameOverScene); |
十四、编译并运行,到此已完成了一个简单的游戏,包含音效,并带有胜利和失败的结束。游戏效果如下: