Cocos2d-x 3.0final 终结者系列教程16-《微信飞机大战》实现
视频下载地址:http://pan.baidu.com/s/1jGiLOG2 本文介绍一款纵版射击游戏的实现,开发环境: win7 vs2012 cocos2d-x3.0final android adt android ndk r9 首先看下最后的效果: (图1,微信飞机大战运行效果) 源码下载地址:http://download.csdn.net/detail/sdhjob/7513863 一、游戏资源准备
二、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",this)); auto aboutItem=MenuItemFont::create("About",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(),//执行跳转方法 NULL ); this->runAction(act); }
。。。。。。
这里也使用了动作序列,先等待2秒,然后自动调用jumpToMenu方法跳转到主菜单
void GameScene::jumpToMenu()//?ˉ??μΩ÷?≤àμ? {
SimpleAudioEngine::getInstance()->stopBackgroundMusic(); Director::getInstance()->replaceScene(HelloWorld::createScene()); } 十二、移植到Android平台 12.1 eclipse导入项目 在VS2012中开发好项目之后,使用adt工具(ecplise)导入项目,import 桌面game2014plangameproj.android 12.2 修改jni/android.mk文件 添加编译的文件 LOCAL_PATH := $(call my-dir) LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes 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。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |