Cocos2d-x 3.x学习笔记:猩先生带你打飞机(五)敌我碰撞处理、分数计算、音乐播放

Cocos2d-x 3.x学习笔记:猩先生带你打飞机(五)敌我碰撞处理、分数计算、音乐播放,第1张

概述下面先是介绍下这一节要使用到的相关cocos2d-x的技术 一、粒子特效 粒子特效是什么,这个就百度百度,我只理解到它就是个很酷炫的效果。在cocos2d-x中使用粒子特效很简单,其实他也就是个Node,创建和使用都跟精灵差不多。另外,粒子特效一般用一个plist来描述,就是一个plist做后缀的xml文件,他描述了粒子的特性,可以自定义粒子,创建粒子特效的时候,加载这个plist文件即可。 下面

下面先是介绍下这一节要使用到的相关cocos2d-x的技术
一、粒子特效
粒子特效是什么,这个就百度百度,我只理解到它就是个很酷炫的效果。在cocos2d-x中使用粒子特效很简单,其实他也就是个Node,创建和使用都跟精灵差不多。另外,粒子特效一般用一个pList来描述,就是一个pList做后缀的xml文件,他描述了粒子的特性,可以自定义粒子,创建粒子特效的时候,加载这个pList文件即可。 下面是代码:

auto * particleSystem = ParticleSystemQuad::create("particle_texture.pList");       //使用pList文件创建粒子特效particleSystem ->setposition(vec1);                        //设置粒子特效显示的位置this->addChild(particleSystem );                            //添加到当前的层

二、数据持久化
在cocos2d-x中,数据存储有很多种方式,一种是sqlit,轻量级的数据库,不过数据量小的话使用UserDefault是非常方便的,当然还有其他的方式,这里就不介绍了,我也不熟哈。UserDefault,在项目中我就是用他来存储用户的分数和最高分数的,存储一些游戏设置啊基本上都用他的。其实他也就是个map,只是用了xml文件来存储,使用方面跟map也是极其相似。当第一次调用UserDefault::getInstance(); 时将会在系统中创建一个UserDefault.xml文件,注意是系统中创建,也就是说用户可见,也是可以 *** 作的。其实用户的敏感数据放在这里是非常危险的,非常危险!比如现在的最高分,用户修改了那数据就是作假,这游戏追求高分就没意义了。但是我找了半天发现系统文件目录下并没有这个文件,不知道是不是cocos2d-x采用了些手段隐藏起来了,不过不影响我们使用,不可见本该是它的属性。 下面是使用代码。

UserDefault * userDefault = UserDefault::getInstance();        //第一次调用即创建UserDefualt.xml文件userDefault->setIntegerForKey("topscore",score);                  //存value,索引是key,每种类型都有对应的get、set方法,跟map一样,有一个key和valueuserDefault->getIntegerForKey("topscore");                            //根据key来拿value

三、播放音乐
播放音乐cocos2d-x也帮我们做了相关的工作,以至于我们想播放音乐时,只需一行代码,对没错,不要998,只要001!so,现在播放音乐这一块只剩下:我们该在where播放音乐,又是在where停止音乐。这个跟我们的游戏逻辑有相当大的联系。暂时还没踩到这个坑,这个只能在游戏中调试调试再调试了。注意:音乐最好是wav格式,我试着播放mp3格式,发现会延迟几秒钟才能播放音乐,所以最好是用工具转下格式。另外一个话题就是音乐缓冲,就是在我们还未开始游戏前,我们得把他缓冲好,要不然下次播放音乐的时候在加载音乐会很卡,小音乐就算了。所以一般的做法就是在游戏开始初始化的时候,即AppDelegate::applicationDIDFinishLaunching()中进行preload,预先读取。对了,写这些代码前要把#include “SimpleAudioEngine.h”,还有那些类的命名空间是CocosDenshion,不想每次都用命名空间去调用类就直接using namespace CocosDenshion吧。
下面看代码

SimpleAudioEngine::getInstance()->preloadBackgroundMusic("sounds/game_music.wav");            //预读背景音乐 SimpleAudioEngine::getInstance()->preloadEffect("sounds/game_over.wav");                                   //预读音效SimpleAudioEngine::getInstance()->playEffect("sounds/game_over.wav");                                         //播放音效,一次性,播完即止 SimpleAudioEngine::getInstance()->playBackgroundMusic("sounds/game_music.wav");                //播放背景音乐,循环播放SimpleAudioEngine::getInstance()->stopBackgroundMusic("sounds/game_music.wav");                //停止播放背景音乐

四、游戏逻辑的实现
好吧,下面就开始我们打飞机的正题。
经过之前的一番啪啪啪(敲代码的声音,别想歪了),现在我们已经可以捕捉到碰撞的事件了。这时我们只要在捕捉函数里面做工作就好了,就是万事俱备只差碰撞处理了。
处理,我们该处理些什么呢?
首先子d与敌机碰撞时,播放敌机被击爆的音乐,计算所得的分数,引爆敌机,就是播放一个敌机爆炸的动画,再移除动画。然后移除Vector中的敌机和子d,最后从层中移除两者。
然后是我机与敌机碰撞,先播放我机被击爆的音乐,修改游戏状态(游戏已经结束),停止所有的定时器,造成全屏停止的效果,再播放两者爆炸效果,再从层中移除敌机和我机,存储游戏的分数并刷新最高纪录,这里使用到的cocos2d的UserDefualt类,等下介绍如何使用。最后就是跳转到游戏结束场景。
下面来实现这些逻辑。
先声明一切用到的变量和函数。
在GameScene.h中声明如下代码:

int score;         //游戏所得分数virtual voID onEnter();     //层进入时调用的方法,碰撞事件监听在此处声明定义voID planeBomb(cocos2d::Vec2 vec,int tag);    //飞机爆炸动画voID bombRemove(Node * sprite);                         //飞机爆炸动画播放完之后的回调函数voID stopAllSchedule();         //停止所有的定时器voID gameOver();                     //游戏结束逻辑

下面是碰撞事件的处理,具体的逻辑是当两个可以互相碰撞的实体碰撞后,触发onContactBegin事件,然后通过捕捉的参数PhysicsContact类获取到相关的信息。碰撞一般是两个实体进行碰撞的,我们可以通过contact.getShapeA()->getbody()->getNode();和contact.getShapeA()->getbody()->getNode();来获取两个碰撞的实体(就是一个节点啦,游戏里是我机、敌机或子d精灵)。然后就是判断是哪种碰撞,是我机和敌机,或者是敌机和子d,然后进行不同的处理。
敌机和子d碰撞处理:
先是判断碰撞的是哪种飞机,有大的小的,加分不同。

//层进入的时候会调用该函数,进行物理世界的碰撞监听voID GameScene::onEnter(){ Layer::onEnter();            //注意层的生命周期相关的函数一定要先调用父类的,否则会无效。 auto Listener = EventListenerPhysicsContact::create();                //创建一个监听器 Listener -> onContactBegin = [=](PhysicsContact& contact)        //这里使用了个lambda,可以理解为匿名函数,具体的用法去百度吧,(>_<) {  auto spriteA = (Sprite *)contact.getShapeA()->getbody()->getNode();                //获取到节点是我们最关心的事,获取到了他们就任我们宰割了,嘿嘿  auto spriteB = (Sprite *)contact.getShapeB()->getbody()->getNode();  int tag1 = spriteA->getTag();  int tag2 = spriteB->getTag();  Vec2 vec1 = spriteA->getposition();  Vec2 vec2 = spriteB->getposition();  //敌机和子d碰撞碰撞  if(tag1 + tag2 == 210 || tag1 + tag2 == 211)  //敌机105104 子d106 我机103  {    SimpleAudioEngine::getInstance()->playEffect("sounds/use_bomb.wav");   //加分,如果是104则是小敌机500分,105是大敌机1000if(tag1 == 104 || tag2 == 104)   {    score += 500;   }   else   {    score += 1000;   }   auto scoreSpire = (Label *)this->getChildByTag(100);                                            //根据tag获取分数Node,并修改其显示的分数    scoreSpire->setString(String::createWithFormat("分数:%d",score)->_string); //启动粒子特效 //auto * system = ParticleSystemQuad::create("particle_texture.pList"); //使用自定义的粒子特效,就一个以plict为后缀的xml文件 //auto system = ParticleExplosion::create(); //使用cocos2d自带的粒子特效 if(tag1 == 104 || tag1 == 105) { //移除敌机和子d enemyList.eraSEObject(spriteA); bulletList.eraSEObject(spriteB); system->setposition(vec1);    //启动动画    this->planeBomb(vec1,tag1);   }   else   {    enemyList.eraSEObject(spriteB);    bulletList.eraSEObject(spriteA);    //启动动画    this->planeBomb(vec2,tag2);    system->setposition(vec2);   }   //粒子特效加入层中   //this->addChild(system);  }  //敌机与我机碰撞  else if(tag1 + tag2 == 207 || tag1+tag2 == 208)  {   SimpleAudioEngine::getInstance()->playEffect("sounds/game_over.wav");   //修改游戏状态为结束状态3   status = 3;   stopAllSchedule();     //停止所有的定时器   if(tag1 == 103)        //游戏结束逻辑   {    this->planeBomb(vec2,tag2);    this->planeBomb(vec1,tag1);   }   else   {    this->planeBomb(vec1,tag1);    this->planeBomb(vec2,tag2);   }   //使用UserDefault存储些用户数据分数,用法比较简单,map的使用方法,   UserDefault * userDefault = UserDefault::getInstance();   int topscore = userDefault->getIntegerForKey("topscore");   if(topscore < score)   {    userDefault->setIntegerForKey("topscore",score);   }   else    userDefault->setIntegerForKey("topscore",topscore);   userDefault->setIntegerForKey("currentscore",score);  }  else{}        //这里处理了敌机和敌机碰撞的BUG  return true; }; //注册监听器 Eventdispatcher * eventdispatcher = Director::getInstance()->getEventdispatcher(); eventdispatcher ->addEventListenerWithSceneGraPHPriority(Listener,this);}

游戏碰撞处理完。
下面就是处理里面调用了一些自定义的函数

//飞机爆动画 ,只需要知道是哪个飞机,和位置,即可voID GameScene::planeBomb(Vec2 vec,int tag)//爆炸效果{ float timeDelay = 0.1; Vector<SpriteFrame*> animationframe; if(tag == 104)  //小敌机动画帧 {  for(int i=1;i<5;i++)  {   auto string = cocos2d::__String::createWithFormat("enemy1_down%d.png",i);   SpriteFrame * sf=SpriteFrame::create(string->getCString(),Rect(0,0,57,43));   animationframe.pushBack(sf);  } } else if(tag == 105)        //大飞机 {   for(int i=1;i<5;i++)  {   auto string = cocos2d::__String::createWithFormat("enemy2_down%d.png",69,95));   animationframe.pushBack(sf);  } } else            //我机爆炸就游戏结束了,给个潇洒的特写,将动画延迟到0.5秒一帧 {  timeDelay = 0.5;   for(int i=1;i<5;i++)  {   auto string = cocos2d::__String::createWithFormat("hero_blowup_n%d.png",102,126));   animationframe.pushBack(sf);  } } Animation * ani=Animation::createWithSpriteFrames(animationframe,timeDelay); auto blanksprite=Sprite::create(); blanksprite->setTag(tag);    //参数中的回调函数会在动画播放完后调用 Action * act=Sequence::create(Animate::create(ani),CCCallFuncN::create(blanksprite,callfuncN_selector(GameScene::bombRemove)),NulL); this->addChild(blanksprite); blanksprite->setposition(vec); blanksprite->runAction(act);}//移除动画voID GameScene::bombRemove(Node * sprite)//删除自己{ sprite->removeFromParentAndCleanup(true); if (sprite->getTag() == 103)            //当移除了我机爆炸的动画,那就是游戏结束了。 {  SimpleAudioEngine::getInstance()->stopBackgroundMusic("sounds/game_music.wav");  gameOver();         //游戏结束逻辑 }}

好,下面看看效果

游戏结束后,应该是跳到显示分数和最高分,还有继续游戏,退出游戏的场景,下一节就实现他。完结篇了哇。
源码下载:源码3

总结

以上是内存溢出为你收集整理的Cocos2d-x 3.x学习笔记:猩先生带你打飞机(五)敌我碰撞处理、分数计算、音乐播放全部内容,希望文章能够帮你解决Cocos2d-x 3.x学习笔记:猩先生带你打飞机(五)敌我碰撞处理、分数计算、音乐播放所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1045430.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-24
下一篇 2022-05-24

发表评论

登录后才能评论

评论列表(0条)

保存