看到cocos2d-x推出了3.1版本,真是每月一次新版本,速度,
還有一個好消息就是http://cn.cocos2d-x.org/上線了,祝賀!啥時候把我的視頻和教程放上去呢?!!!
視頻下載地址:http://pan.baidu.com/s/1jGiLOG2
本文介紹一款縱版射擊遊戲的實現,開發環境:
win7
vs2012
cocos2d-x3.0final
android adt
android ndk r9
首先看下最後的效果:
(圖1,微信飛機大戰運行效果)
源碼下載地址:http://download.csdn.net/detail/sdhjob/7513863
一、遊戲資源準備
menu.png 首頁的菜單背景 |
|
about.png 關於界面 |
|
help.png 幫助界面 |
|
background3.png 遊戲場景的 |
|
end.png | |
bullet.png aaa.png ccc.png | 子彈和敵機文件 |
爆炸效果 (被CSDN的博客加上水印,就這樣了,大家還是下源碼吧) |
二、Cocos2d-x3.0項目創建和VS2012編譯
2.1進入命令提示符輸入:
cocos new -p com.xdl.game -d c:/users/administrator/desktop/game2014 -l cpp planegame
2.2 然後進入桌面/game2014/planegame/proj.win32
2.3使用vs2012打開
planegame.sln
2.4 按F5編譯運行項目,將會出現HelloWorld的界面
2.5.把所有的資源拷貝到 桌面/game2014/planegame/Resources目錄下(處理圖片還有3個聲音文件)
三、場景跳轉和主菜單實現
3.1.修改HelloWorldScene,在init方法中添加3個菜單條目:
auto gameItem=MenuItemFont::create("StartGame",CC_CALLBACK_1(HelloWorld::menuCloseCallback,this));
auto helpItem=MenuItemFont::create("Help",CC_CALLBACK_1(HelloWorld::menuCloseCallback,this));
auto aboutItem=MenuItemFont::create("About",CC_CALLBACK_1(HelloWorld::menuCloseCallback,this));
gameItem->setPosition(Point(origin.x + visibleSize.width/2 - closeItem->getContentSize().width/2,200 ));
helpItem->setPosition(Point(origin.x + visibleSize.width/2 - closeItem->getContentSize().width/2,150 ));
aboutItem->setPosition(Point(origin.x + visibleSize.width/2 - closeItem->getContentSize().width/2,100 ));
gameItem->setColor(Color3B::BLACK);
helpItem->setColor(Color3B::BLACK);
aboutItem->setColor(Color3B::BLACK);
gameItem->setTag(11);
helpItem->setTag(12);
aboutItem->setTag(13);
3.2 修改菜單的回調方法MenuCallBackvoid HelloWorld::menuCloseCallback(Ref* pSender)
{ MenuItem * nowItem=(MenuItem *)pSender;
SimpleAudioEngine::getInstance()->playEffect("select.wav"); //播放音樂
switch(nowItem->getTag())
{
case 10:
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
MessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");
return;
#endif
Director::getInstance()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
exit(0);
#endif
break;
case11://game
Director::getInstance()->replaceScene(GameScene::createScene());
break;
case12://help
Director::getInstance()->replaceScene( TransitionFlipY::create(1,HelpScene::createScene()));
break;
case13://about
Director::getInstance()->replaceScene( TransitionFlipY::create(1,AboutScene::createScene()));
break;
}
}
這樣通過導演對象實現場景跳轉。
3.3 在幫助,關於場景實現跳轉回來
需要在項目中添加3個.h文件和3個.cpp文件,保存到Classes目錄下(注意目錄,不要保存錯了)
HelpScene.h
HelpScene.cpp
GameScene.h
GameScene.cpp
AboutScene.h
AboutScene.cpp
若想在幫助和關於場景跳轉回來需要加入觸摸消息處理,見HelpScene的init方法:
bool HelpScene::init(){
if(!Layer::init())
{
return false;
}
auto spbk=Sprite::create("help.png");
spbk->setPosition(Point::ZERO);
spbk->setAnchorPoint(Point::ZERO);
this->addChild(spbk);
EventListenerTouchOneByOne * touch=EventListenerTouchOneByOne::create();
touch->onTouchBegan=[](Touch * touch,Event * event){
return true;
};
touch->onTouchMoved=[](Touch * touch,Event * event){
Director::getInstance()->replaceScene( HelloWorld::createScene());
};
_eventDispatcher->addEventListenerWithSceneGraphPriority(touch,this);
return true;
}
四、遊戲場景背景滾動
4.1首先在GameScene的init方法添加背景層,代碼如下:
auto spbk=Sprite::create("background4.png");
spbk->setAnchorPoint(Point::ZERO);
spbk->setPosition(Point::ZERO);
this->addChild(spbk);
spbk->setTag(10);
auto spbk02=Sprite::create("background4.png");
spbk02->setAnchorPoint(Point::ZERO);
spbk02->setPosition(Point::ZERO);
spbk02->setPositionY(spbk->getPositionY()+680);
this->addChild(spbk02);
spbk02->setTag(11);
爲什麼要添加2遍呢?因爲要實現循環的貼圖效果,4.2 在init方法計劃任務
this->schedule(schedule_selector(GameScene::moveBackground),0.01);
4.3 處理計劃任務void GameScene::moveBackground(float t)
{
auto spbk=this->getChildByTag(10);
auto spbk02=this->getChildByTag(11);
spbk->setPositionY(spbk->getPositionY()-1);
if(spbk->getPositionY()<-680)
{
spbk->setPositionY(0);
}
spbk02->setPositionY(spbk->getPositionY()+680);
}
這樣就形成了循環貼圖的效果,遊戲遊戲是橫版的,還有將這種循環貼圖通過多層實現場景縱深效果(近處圖層移動快,遠處移動慢)當背景相對屏幕向下移動,飛機相對屏幕不懂,但飛機相對背景則向上飛行(好多遊戲的主角其實一直在屏幕中間)
五、飛機動畫和觸摸控制
5.1 在init方法創建飛機動畫
auto spPlane=Sprite::create();
spPlane->setTag(110);
spPlane->setPosition(Point(160,240));
this->addChild(spPlane);
Vector<SpriteFrame*> allframe;//保存動畫的每一幀
for(int i=0;i<4;i++)
{
SpriteFrame * sf=SpriteFrame::create("player.png",Rect(i*47,0,47,56));
allframe.pushBack(sf);
}
Animation * ani=Animation::createWithSpriteFrames(allframe,0.1);
spPlane->runAction(RepeatForever::create(Animate::create(ani)));
5.2 通過觸摸控制飛機移動EventListenerTouchOneByOne * event=EventListenerTouchOneByOne::create();
event->setSwallowTouches(true);
event->onTouchBegan=CC_CALLBACK_2(GameScene::onTouchBegan,this);
event->onTouchMoved=CC_CALLBACK_2(GameScene::onTouchMoved,this);
event->onTouchEnded=CC_CALLBACK_2(GameScene::onTouchEnded,this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(event,this);
-------在GameScene中添加以下方法
bool GameScene::onTouchBegan(Touch *touch, Event *unused_event){
px=touch->getLocation().x;
py=touch->getLocation().y;
return true;
}
void GameScene::onTouchMoved(Touch *touch, Event *unused_event){
int mx=(touch->getLocation().x-px);
int my=(touch->getLocation().y-py);
auto spPlane=this->getChildByTag(110);
spPlane->runAction(MoveBy::create(0,Point(mx,my)));
px=touch->getLocation().x;
py=touch->getLocation().y;
}
void GameScene::onTouchEnded(Touch *touch, Event *unused_event){
}
這樣就實現了在屏幕滑動改變飛機座標。
六、子彈發射
6.1 在GameScene中添加成員Vector用來保存所有的子彈層
Vector<Sprite *> allBullet;
6.2 計劃任務,定時產生子彈和移動子彈
this->schedule(schedule_selector(GameScene::newBullet),0.5);
this->schedule(schedule_selector(GameScene::moveBullet),0.01
6.3 實現產生子彈的方法和移動子彈的方法void GameScene::newBullet(float t){
auto spPlane=this->getChildByTag(110);
Sprite * bullet=Sprite::create("bullet3.png");
bullet->setPosition(spPlane->getPosition());
this->addChild(bullet);
this->allBullet.pushBack(bullet);
}
void GameScene::moveBullet(float t){
for(int i=0;i<allBullet.size();i++)
{ auto nowbullet=allBullet.at(i);
nowbullet->setPositionY(nowbullet->getPositionY()+3);
if(nowbullet->getPositionY()>Director::getInstance()->getWinSize().height)
{
nowbullet->removeFromParent();
allBullet.eraseObject(nowbullet);
i--;
}
}
}
七、敵機實現
敵機實現與子彈實現類似,只不過一個是向上飛,一個是向下飛。
7.1 在GameScene中添加成員Vector用來保存所有的子彈層
Vector<Sprite *> allEnemy;
7.2 添加產生敵機的任務
this->schedule(schedule_selector(GameScene::newEnemy),0.5);
this->schedule(schedule_selector(GameScene::moveEnemy),0.01)
7.3 實現敵機任務方法,這裏產生2種不同類型的敵機
void GameScene::newEnemy(float t){
Sprite * enemy=nullptr;
int num=rand()%10;//隨機數0-9
if(num>=3)
{
enemy=Sprite::create("aaa.png");
enemy->setTag(1000);
}
else
{ enemy=Sprite::create("ccc.png");
enemy->setTag(2000);
}
enemy->setPosition(Point(rand()%300+10,500));
this->addChild(enemy);
this->allEnemy.pushBack(enemy);
}
void GameScene::moveEnemy(float t){
for(int i=0;i<allEnemy.size();i++)
{ auto nowenemy=allEnemy.at(i);
nowenemy->setPositionY(nowenemy->getPositionY()-3);
if(nowenemy->getPositionY()<0)
{
nowenemy->removeFromParent();
allEnemy.eraseObject(nowenemy);
i--;
}
}
}
八、碰撞檢測和加分
8.1 添加和引擎主線程fps一致的任務處理方法update
this->scheduleUpdate();
8.2 實現碰撞檢測遊戲邏輯void GameScene::update(float t){
auto spPlane=this->getChildByTag(110);
Rect rp(spPlane->getPositionX(),spPlane->getPositionY(),47,56);
for(int i=0;i<allEnemy.size();i++)
{ auto nowenemy=allEnemy.at(i);
Rect er(nowenemy->getPositionX(),nowenemy->getPositionY(),40,50);
if(rp.intersectsRect(er))
{ //爆炸
newBomb(spPlane->getPositionX(),spPlane->getPositionY());
//移除敵機
nowenemy->removeFromParent();
allEnemy.eraseObject(nowenemy);
i--;
//播放音樂
SimpleAudioEngine::getInstance()->playEffect("explo.wav");
//停止所有任務和動作
//Director::getInstance()->getActionManager()->pauseAllRunningActions();
this->pauseSchedulerAndActions();
auto spover=Sprite::create("end.png");
spover->setPosition(Point::ZERO);
spover->setAnchorPoint(Point::ZERO);
this->addChild(spover);
auto act=Sequence::create(
DelayTime::create(2), //等待2秒
CallFunc::create(this,callfunc_selector(GameScene::jumpToMenu)),//執行跳轉方法
NULL
);
this->runAction(act);
}
//敵機和子彈碰撞檢測
for(int j=0;j<allBullet.size();j++)
{ auto nowbullet=allBullet.at(j);
Rect br(nowbullet->getPositionX(),nowbullet->getPositionY(),20,20);
if(er.intersectsRect(br))
{//修改分數
Label * labScore=(Label*)this->getChildByTag(120);
score+=nowenemy->getTag();
//爆炸效果
newBomb(nowbullet->getPositionX(),nowbullet->getPositionY());
//粒子效果
auto ps=ParticleSystemQuad::create("bomb.plist");
ps->setPosition(Point(nowbullet->getPositionX(),nowbullet->getPositionY()));
this->addChild(ps);
labScore->setString(String::createWithFormat("score:%d",score)->_string);
//移除子彈層
nowbullet->removeFromParent();
allBullet.eraseObject(nowbullet);
//移除敵機層
nowenemy->removeFromParent();
allEnemy.eraseObject(nowenemy);
i--;
//音效
SimpleAudioEngine::getInstance()->playEffect("explo.wav");
break;
}
}
}
}
九、爆炸效果
當碰撞檢測到,在飛機位置產生一個新的爆炸效果層,播放動畫,動畫播放完成自動刪除自己。
void GameScene::newBomb(int x,int y)
{
Vector<SpriteFrame*> allframe;
for(int i=0;i<7;i++)
{
SpriteFrame * sf=SpriteFrame::create("boom.png",Rect(i*44,0,44,47));
allframe.pushBack(sf);
}
Animation * ani=Animation::createWithSpriteFrames(allframe,0.03);
auto sprite=Sprite::create();
Action * act=Sequence::create(
Animate::create(ani), //動畫
CCCallFuncN::create(sprite,callfuncN_selector(GameScene::killMe)),//調用自刪除方法
NULL);
this->addChild(sprite);
sprite->setPosition(Point(x,y));
sprite->runAction(act);
}
void GameScene::killMe(Node * pSender)//自刪除 pSender就是sprite這裏是CallFunN,會傳遞節點過來
{
pSender->removeFromParentAndCleanup(true);
}
十、粒子特效和音樂播放
10.1 首先使用粒子編輯器編輯粒子文件bomb.plist(詳見源碼)
10.2 載入粒子層
auto ps=ParticleSystemQuad::create("bomb.plist");
ps->setPosition(Point(nowbullet->getPositionX(),nowbullet->getPositionY()));
this->addChild(ps);
(如果粒子層也需要自刪除,可以參考爆炸效果)10.3 播放音樂和音效
首先要引入聲音處理頭文件和命名空間
#include "SimpleAudioEngine.h"
using namespace CocosDenshion;
然後就可以使用1條語句來播放音樂和音效了SimpleAudioEngine::getInstance()->playBackgroundMusic("game.mp3",true); //播放背景音樂
SimpleAudioEngine::getInstance()->playEffect("explo.wav"); //播放音效
十一、判定死亡
在Update方法中,目前只加入了當敵機和飛機碰撞則死亡,實際遊戲中可能有多有條件
如:敵機子彈和飛機碰撞、時間計數等,
void GameScene::update(float t){
auto spPlane=this->getChildByTag(110);
Rect rp(spPlane->getPositionX(),spPlane->getPositionY(),47,56);
for(int i=0;i<allEnemy.size();i++)
{ auto nowenemy=allEnemy.at(i);
Rect er(nowenemy->getPositionX(),nowenemy->getPositionY(),40,50);
if(rp.intersectsRect(er))
{ //爆炸
newBomb(spPlane->getPositionX(),spPlane->getPositionY());
//移除敵機
nowenemy->removeFromParent();
allEnemy.eraseObject(nowenemy);
i--;
//播放音樂
SimpleAudioEngine::getInstance()->playEffect("explo.wav");
//停止所有任務和動作
//Director::getInstance()->getActionManager()->pauseAllRunningActions();
this->pauseSchedulerAndActions();
auto spover=Sprite::create("end.png");
spover->setPosition(Point::ZERO);
spover->setAnchorPoint(Point::ZERO);
this->addChild(spover);
auto act=Sequence::create(
DelayTime::create(2), //等待2秒
CallFunc::create(this,callfunc_selector(GameScene::jumpToMenu)),//執行跳轉方法
NULL
);
this->runAction(act);
}
void GameScene::jumpToMenu()//ï◊™µΩ÷˜≤Àµ•
{
SimpleAudioEngine::getInstance()->stopBackgroundMusic();
Director::getInstance()->replaceScene(HelloWorld::createScene());
}
十二、移植到Android平臺
12.1 eclipse導入項目
在VS2012中開發好項目之後,使用adt工具(ecplise)導入項目,import
桌面\game2014\plangame\proj.android
12.2 修改jni/android.mk文件
添加編譯的文件
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := cocos2dcpp_shared
LOCAL_MODULE_FILENAME := libcocos2dcpp
LOCAL_SRC_FILES := hellocpp/main.cpp \
../../Classes/AppDelegate.cpp \
../../Classes/GameScene.cpp \
../../Classes/HelpScene.cpp \
../../Classes/HelloWorldScene.cpp \
../../Classes/AboutScene.cpp
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes
LOCAL_WHOLE_STATIC_LIBRARIES := cocos2dx_static
LOCAL_WHOLE_STATIC_LIBRARIES += cocosdenshion_static
LOCAL_WHOLE_STATIC_LIBRARIES += box2d_static
include $(BUILD_SHARED_LIBRARY)
$(call import-module,2d)
$(call import-module,audio/android)
$(call import-module,Box2D)
12.3 進入cmd命令提示符
進入項目目錄
cd c:/Users/Administrator/Desktop/game2014/planegame
編譯當前項目
cocos compile -p android
(等吧。。。最後會在c:/Users/Administrator/Desktop/game2014/planegame/proj.android/libs/armsabi/生成一個.so文件, 成功了!)
12.4 拷貝Cocos2d-x android庫文件
到 c:/Users/Administrator/Desktop/game2014/planegame/cocos/2d/platform/android/java/src/ 拷貝org文件夾到
c:/Users/Administrator/Desktop/game2014/planegame/proj.android/src 目錄
在adt中刷新項目(這時候項目的錯誤會消除)
12.5 打包項目
使用手機數據線連接電腦,開啓調試模式
可以直接通過run,來把該項目安裝到手機,
之後使用android打包嚮導打包生成apk。
大功告成,大家不妨投入半天時間做個《微信飛機大戰》,下節課講《2048》的開發。