Cocos2d-x 3.0final 终结者系列教程16-《微信飞机大战》实现

2023-11-08 04:32

本文主要是介绍Cocos2d-x 3.0final 终结者系列教程16-《微信飞机大战》实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

看到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 修改菜单的回调方法MenuCallBack

 void 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);

}

。。。。。。
这里也使用了动作序列,先等待2秒,然后自动调用jumpToMenu方法跳转到主菜单

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》的开发。



 

这篇关于Cocos2d-x 3.0final 终结者系列教程16-《微信飞机大战》实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/367887

相关文章

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

W外链微信推广短连接怎么做?

制作微信推广链接的难点分析 一、内容创作难度 制作微信推广链接时,首先需要创作有吸引力的内容。这不仅要求内容本身有趣、有价值,还要能够激起人们的分享欲望。对于许多企业和个人来说,尤其是那些缺乏创意和写作能力的人来说,这是制作微信推广链接的一大难点。 二、精准定位难度 微信用户群体庞大,不同用户的需求和兴趣各异。因此,制作推广链接时需要精准定位目标受众,以便更有效地吸引他们点击并分享链接

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl