cocos2d 全民飞机大战子弹图怎么实现子弹追踪

1579人阅读
cocos2d-x-3.x(27)
graphics(26)
原文同步发布于我的wiki,查看原文或更新请移步:
先回答拓展思考里的问题,'物理引擎可否用来做碰撞检测?',答案是肯定的,具体见下面
子弹如何杀伤敌人在上面的系列中已经实现。本节要实现的功能点是,继续利用碰撞检测实现飞机大战里炸弹的全屏范围攻击
基于cocos2d-x-3.4final完整代码way4&
注册了touch事件监听和碰撞事件监听前4次touch事件会分别在触碰点产生一架飞机,分别从右向左的一个固定点飞行过去。
若在飞行过程中用户没有第5次触摸屏幕,这4架飞机将顺利飞到预定点若在飞行过程中用户触发了第5次touch事件,则会'引爆全屏爆炸的炸弹',飞机全部播放爆炸动画,动画结束后飞机将会被移除场景
实现全屏爆炸的思路(利用物理引擎),我想到了两点
产生一个覆盖整个屏幕的PhysicalBody,让他和屏幕中所有的能产生碰撞的对象做碰撞,从而实现'全屏爆炸'或'范围攻击'。概括为一个大型的PhysicalBody和范围内每个可碰撞的PhysicalBody进行碰撞。本文采用这种思路实现。真实生活中的爆炸是会在一个点瞬间产生许多弹片,快速射向四周,对射程范围内遇到的物体造成杀伤。那第2种方案的思路就是在触摸点产生N个小的PhysicalBode并向四周移动,这些小的'弹片'遇到可碰撞的物体就对其造成杀伤。保卫萝卜的游戏里面有很多全屏攻击的子弹类型,貌似可以采用这种思路。感兴趣的同学可尝试实验。
基于物理碰撞结合碰撞过滤,见文首链接定义了一个Role的接口,超级子弹类和敌机都实现了该接口
class Role {
virtual ~Role() {
// 主动撞击目标,一般会造成目标损坏
virtual void hit(Role* target) = 0;
// 被撞击等,遭到损坏
virtual void gotDamage(int damage)= 0;
// HP为0了,倒下
virtual void down()= 0;
方法virtual
void hit(Role* target) = 0;是一切故事的起源
代码见场景里的物理碰撞回调
log(&onContactBegin&);
Role* a = dynamic_cast&Role * &(contact.getShapeA()-&getBody()-&getNode());
Role* b = dynamic_cast&Role * &(contact.getShapeB()-&getBody()-&getNode());
if(a && b) {
log(&onContactBegin,牛顿说: 力的作用是相互的&);
a-&hit(b);
b-&hit(a);
超级子弹和敌机类都类似,实现Role接口,继承自精灵
采用两段构造,构造出精灵的过程中设置好物理引擎相关参数hit方法一般会导致掉血,当血掉为0时(DEMO中没体现,gotDamage里加个if(hp&=0) down就好:)),目标挂掉,播挂掉的动画
在超级子弹的实现中用了一个小技巧,&body-&setMass(0.000001f);将这个超级子弹的重量设的很小,这样对话,碰撞的时候不会把飞机撞的到处乱漂,从而看起来飞机还是沿原来的线路在动关于监听器注册,物理碰撞和碰撞过滤同前面章节的例子
/cheyiliu/All-in-One/raw/master/res/cocos2d/CollisionDetection-way4-use-physics-engine-filter-%E8%8C%83%E5%9B%B4%E6%94%BB%E5%87%BB.gif
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:96729次
积分:2456
积分:2456
排名:第11398名
原创:107篇
评论:28条
文章:40篇
阅读:40761
文章:27篇
阅读:27054
(2)(2)(1)(2)(1)(2)(2)(1)(2)(1)(2)(2)(2)(2)(2)(4)(4)(4)(3)(8)(12)(10)(22)(9)(13)在飞机大战游戏开发中遇到的问题和解决方法:
1.在添加菜单时,我要添加一个有背景的菜单,需要在菜单pMenu中添加一个图片精灵,结果编译过了但是运行出错,如下图:
查了很多资料,调试了很长时间,整个人都要崩溃了。
最后发现引擎中CCMenu::itemForTouch函数中有遍历子节点的行为,但是循环中没有判断子节点类型是否为CCMenuItem。如图:码,这样一来,加入到pMenu中的图片精灵被当作菜单项取了出来使用,导致报错。老版本的果然又不完善的地方,整个人都不好了...果断修改引擎里的源只要在遍历中使用子节点之前判断一下是否为CCMenuItem类型即可,如图:
2.在开发的时候,难免要用到键盘消息来测试程序功能,但是找了很久发现引擎中没有为我们传出键盘消息。所以...果断修改源码。
步骤一:在CCLayer类声明中public下添加virtual
processWin32KeyPress( UINT
message, WPARAM
wParam, LPARAM
lParam) {}步骤二:在CCEGLView类声明中private下添加变量CCLayer *m_pLayWin32K在public下添加函数void
SetWin32KeyLayer(CCLayer *pLayer){m_pLayWin32Key = pL}步骤三:在CCEGLView构造函数中初始化CCLayer(NULL);WindowProc函数最开始添加if (NULL != m_pLayWin32Key){m_pLayWin32Key-&processWin32KeyPress(message, wParam, lParam);}步骤四:重新生成libcocos2d;步骤五:在继承于CCLayer类的子类的构造或者初始化函数中添加CCDirector::sharedDirector()-&getOpenGLView()-&SetWin32KeyLayer( this );步骤六:在子类中重写processWin32KeyPress函数处理键盘消息;步骤七:子类的析构或析构之前的函数中添加CCDirector::sharedDirector()-&getOpenGLView()-&SetWin32KeyLayer( NULL)。这样我们就可以随心所欲地处理消息了。
3.在用键盘方向键控制飞机移动时,发现总有些卡顿。其实是这种机制有问题。解决方法:不要再处理消息时移动飞机,而是在处理消息时仅仅设置运动方式,在回扫刷新函数中,根据飞机的运动方式去移动飞机。
阅读(...) 评论()【cocos2d-x入门实战】微信飞机大战之九:碰撞检测
【cocos2d-x入门实战】微信飞机大战之九:碰撞检测
原创作品,转载请标明:
碰撞检测是整个游戏的重头戏,没有它,子弹和敌机只能是路人。。。虽然很重要,但实现起来确是很简单。
1.update函数
每个从CCObject继承的类都包含了一个update函数,它是一个内联虚函数,执行频率为每帧调用一次。
[cpp] virtual&CCObject::update(float&dt);&&
开启方式:
[cpp] this-&scheduleUpdate();&&
关闭方式:
[cpp] this-&unscheduleUpdate();&&
有了这个update函数,我们就可以在GameLayer中对它进行重载,把我们每帧内要执行的动作放到update中,进行调用就可以了。
2.碰撞检测原理
那我们每帧内要做什么事呢?
我们先看一下游戏是什么?动画?其实不过是一张张快速变换的图片。比如我们设置60FPS,那么游戏就是一秒钟闪过60张图片,由于人眼的视觉残留效应导致看起来像是动画,因此游戏中的每一个动作我们可以认为是高速变化的静态的图片,而这个图片是以帧为单位。
所以我们可以在每一帧内进行碰撞检测。
主角飞机是一个精灵,也就是一张带alpha通道的PNG图,子弹也是,敌机同样也是,它们都是一块矩形区域,即便有的地方是透明的。所以碰撞检测就是在每一帧内判断多个不同类型矩形区域是否有相交,有即碰撞。
3.碰撞检测示例
这里以生命值最大的Enemy3来做示例。而敌机和主角的碰撞是一样的道理。主角的爆炸效果也是采用帧动画,和敌机爆炸是一致的,但是要注意,主角飞机一旦爆炸,要记得StopShoot。
[cpp] CCArray*&bulletsToDelete=CCArray::create();//创建一个CCArray,用以存放待删除的子弹,也就是此帧中被检测到碰撞的子弹&&bulletsToDelete-&retain();//必须调用retain,CCArray内部调用了autoRelease&&CCObject*&bt,*&&&&//enemy3&&&bullet&CheckCollosion&&CCARRAY_FOREACH(this-&bulletLayer-&m_pAllBullet,bt)//遍历所有子弹&&{&&&&&&CCSprite*&bullet=(CCSprite*)&&&&&&&&CCArray*&enemy3sToDelete=CCArray::create();//创建一个CCArray,用以存放待删除的敌机,也就是此子弹击中的敌机&&&&&&enemy3sToDelete-&retain();//调用retain&&&&&&CCARRAY_FOREACH(this-&enemy3Layer-&m_pAllEnemy3,et)//遍历所有敌机&&&&&&{&&&&&&&&&&Enemy3Sprite*&enemy3=(Enemy3Sprite*)&&&&&&&&&&if&(CCRect::CCRectIntersectsRect(bullet-&boundingBox(),enemy3-&boundingBox()))//检测碰撞,即矩形区域是否相交&&&&&&&&&&{&&&&&&&&&&&&&&//如果life&1,移除bullet&&&&&&&&&&&&&&if&(enemy3-&life&1)//因为Enemy3设置了生命值为5&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&enemy3-&life--;&&&&&&&&&&&&&&&&&&bulletsToDelete-&addObject(bullet);//把待删除子弹放入CCArray&&&&&&&&&&&&&&}&&&&&&&&&&&&&&//如果life==1,移除enemy3&&&&&&&&&&&&&&else&if(enemy3-&life==1)//只剩一条命的时候,再碰撞就挂掉了&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&enemy3-&life--;&&&&&&&&&&&&&&&&&&bulletsToDelete-&addObject(bullet);//把待删除子弹放入CCArray&&&&&&&&&&&&&&&&&&enemy3sToDelete-&addObject(enemy3);//把待删除敌机放入CCArray&&&&&&&&&&&&&&}&&&&&&&&&&&&&&//此时处在敌机爆炸动画阶段,敌机未消失,子弹还有打到的机会,所以不进行检测&&&&&&&&&&&&&&else&;&&&&&&&&&&}&&&&&&}&&&&&&CCARRAY_FOREACH(enemy3sToDelete,et)//遍历所有此帧中碰撞死亡的敌机,必须是死亡&&&&&&{&&&&&&&&&&Enemy3Sprite*&enemy3=(Enemy3Sprite*)&&&&&&&&&&this-&enemy3Layer-&enemy3Blowup(enemy3);//执行爆炸&&&&&&}&&&&&&enemy3sToDelete-&release();//release&&}&&CCARRAY_FOREACH(bulletsToDelete,bt)//遍历所有此帧中碰撞的子弹&&{&&&&&&CCSprite*&bullet=(CCSprite*)&&&&&&this-&bulletLayer-&RemoveBullet(bullet);//执行移除&&}&&bulletsToDelete-&release();//release&&
不过要注意的是,实际游戏如果只是简单的检测矩形区域,那么可能会出现子弹从敌机身边掠过,而敌机却挂了的情况,这不科学啊!这是因为敌机两侧的透明区域过大了,碰撞检测的是整个PNG图的大小,不知道这个图上哪些点有代表着飞机。
所以要根据游戏的实际情况来调整精灵矩形区域的大小以达到较好的游戏体验。
发表评论:
TA的最新馆藏[转]&[转]&[转]&飞机大战03之飞机发射子弹,添加敌人 - 博客频道 - CSDN.NET
分类:飞机大战cocos2d-3.x
飞机发射子弹:
弹幕,是雷电游戏的精华。这就需要对子弹的运动轨迹进行控制。
先做一个最简单的子弹发射,后面再添加各种弹幕(实际上主要是研究弹幕)
说是最简单,其实也是最普通的子弹发射,产生一个颗子弹移动就OK了。
方法:做一个子弹发射的计时器,产生子弹,子弹做MoveBy动作就OK了。
GameLayer.cpp
void GameLayer::fireSchedule(float dt)
Size screenSize = Director::getInstance()-&getWinSize() ;
Vec2 crePos = m_pPlayerPlane-&getPosition() ;//子弹的初始位置
float flyTime = 1.0
Sprite * pBullet = Sprite::create(&bullet1.png&) ;
pBullet-&setPosition(crePos) ;
addChild(pBullet,ZORDER_BULLET) ;
flyTime = ((screenSize.height - crePos.y) / screenSize.height)*flyT//移动的时间跟,发射的距离相关
pBullet-&runAction(
Sequence::create(
MoveBy::create(flyTime,Vec2(0,screenSize.height - crePos.y)),
RemoveSelf::create(true),nullptr)
敌人新建了一个类,因为,到后面敌人可能还需要有一些自己的属性。
EnermySprite.h
#ifndef _ENERMY_SPRITE_H_
#define _ENERMY_SPRITE_H_
#include &cocos2d.h&
USING_NS_CC ;
typedef enum
kEnermyTypeNone = 0,
kEnermyType1,
kEnermyType2,
kEnermyType3,
kEnermyType4,
class EnermySprite : public Sprite
static EnermySprite * createByType(EnermyType type);
static const char * getImageNameByType(EnermyType type);
EnermySprite();
~EnermySprite();
EnermySprite.cpp
#include &EnermySprite.h&
EnermySprite * EnermySprite::createByType(EnermyType type)
const char * pImage = getImageNameByType(type) ;
EnermySprite * pRet = new EnermySprite() ;
pRet-&initWithFile(pImage) ;
pRet-&autorelease() ;
const char * EnermySprite::getImageNameByType(EnermyType type)
const char* pImageName =
switch (type)
case kEnermyType1:
pImageName = &enemy1.png& ;
case kEnermyType2:
pImageName = &enemy2.png& ;
case kEnermyType3:
pImageName = &enemy3.png& ;
case kEnermyType4:
pImageName = &enemy4.png& ;
return pImageN
EnermySprite::EnermySprite()
EnermySprite::~EnermySprite()
添加到游戏中:
GameLayer.h
void GameLayer::createEneSchedule(float dt)
int ran = CCRANDOM_0_1() * 4 + 1 ;
switch (ran)
type = kEnermyType1;
type = kEnermyType2;
type = kEnermyType3;
type = kEnermyType4;
auto pEne = EnermySprite::createByType(type) ;
float x = CCRANDOM_0_1()*(Director::getInstance()-&getWinSize().width - pEne-&getBoundingBox().size.width / 2) +
pEne-&getBoundingBox().size.width / 2;
float y = Director::getInstance()-&getWinSize().height + pEne-&getBoundingBox().size.height / 2 ;
float flyTime = 2.0
pEne-&runAction(
Sequence::create(
MoveBy::create(flyTime,Vec2(0,-(Director::getInstance()-&getWinSize().height + pEne-&getBoundingBox().size.height))),
CallFuncN::create(CC_CALLBACK_1(GameLayer::enermyMoveEndCallback,this)),
RemoveSelf::create(true),nullptr
addChild(pEne) ;
pEne-&setPosition(x,y) ;
m_pEnermyVec.pushBack(pEne) ;
void GameLayer::enermyMoveEndCallback(Node * pNode)
EnermySprite * pEnermy = dynamic_cast&EnermySprite*&(pNode) ;
m_pEnermyVec.eraseObject(pEnermy);
又是一个计时器,记得要添加一个敌人的vector来存放敌人。
排名:第19358名
(9)(1)(13)(4)(6)(7)(26)(1)(1)(5)(8)(39)(4)(1)(1)(5)(10)(6)(1)【cocos2d-x入门实战】微信飞机大战之六:子弹层的处理
【cocos2d-x入门实战】微信飞机大战之六:子弹层的处理
原创作品,转载请标明:
这一篇将会处理完子弹层的其他要点。
1.子弹的初始位置
子弹的初始位置在飞机的机头位置,因为飞机在游戏的过程中会随着玩家的触摸而改变其位置,所以,子弹的初始位置只能以当前飞机位置为基准进行添加。
[cpp] CCPoint&planePosition=PlaneLayer::sharedPlane-&getChildByTag(AIRPLANE)-&getPosition();&&CCPoint&bulletPosition=ccp(planePosition.x,planePosition.y+PlaneLayer::sharedPlane-&getChildByTag(AIRPLANE)-&getContentSize().height/2);&&bullet-&setPosition(bulletPosition);&&
还记得当时给飞机加的tag(AIRPLANE)么?通过sharedPlane的getChildByTag就能获取到飞机精灵,然后计算出子弹初始的位置,添加到子弹层。
其实更为严谨的方式是设计一个子弹管理器,然后在管理器中添加子弹,这里简单的处理,会比较好理解,虽然会影响到编程风格。
2.子弹的飞行效果
子弹的飞行效果,很简单,就是往Y方向移动,但是X方向不能改变。所以要注意,已发射的子弹不能随着飞机的移动而跟着移动,一旦这颗子弹发射了,它就是一个独立的个体,不管飞机移动或者爆炸了,它只会按照自己的规则进行运动而不受干扰。
因为子弹的初始Y位置是不固定的,如果固定死一个时间会导致不同子弹的移动速度不同,所以必须先把每颗子弹的运动时间计算出来。
[cpp] float&length=CCDirector::sharedDirector()-&getWinSize().height+bullet-&getContentSize().height/2-bulletPosition.y;//飞行距离,超出屏幕即结束&&float&velocity=420/1;//飞行速度:420pixel/sec&&float&realMoveDuration=length///飞行时间&&&&CCFiniteTimeAction*&actionMove=CCMoveTo::create(realMoveDuration,ccp(bulletPosition.x,CCDirector::sharedDirector()-&getWinSize().height+bullet-&getContentSize().height/2));&&CCFiniteTimeAction*&actionDone=CCCallFuncN::create(this,callfuncN_selector(BulletLayer::bulletMoveFinished));//回调一个子弹结束处理函数&&&&CCSequence*&sequence=CCSequence::create(actionMove,actionDone);&&bullet-&runAction(sequence);&&
3.子弹的管理和回收
cocos2d-x提供了一个很好用的数组类CCArray,它相当于一个容器。我们可以把一些创建出来的精灵放在里面进行管理,在不需要的时候,从中删除它并且从屏幕上删除它(有时候看不见不代表它们已经从屏幕上删除了)。
因为CCArray::create函数调用了autoRelease,所以我们必须在调用创建后手动进行retain,以免超出使用范围后被释放,同时在析构函数中再进行release防止内存泄漏。
(1)创建成员变量指针
[cpp] CCArray*&m_pAllB&&
(2)子弹层的构造函数和析构函数
[cpp] BulletLayer::BulletLayer(void)&&{&&&&&&m_pAllBullet=CCArray::create();&&&&&&m_pAllBullet-&retain();&&}&&&&BulletLayer::~BulletLayer(void)&&{&&&&&&m_pAllBullet-&release();&&&&&&m_pAllBullet=NULL;&&}&&
(3)子弹飞出屏幕后(即子弹运动结束后,自然消失而不是和敌机碰撞)的调用函数
[cpp] void&BulletLayer::bulletMoveFinished(CCNode*&pSender)&&{&&&&&&CCSprite*&bullet=(CCSprite*)pS&&&&&&m_pAllBullet-&removeObject(bullet);//移除CCArray&&&&&&this-&removeChild(bullet,true);//移除屏幕&&}&&
4.子弹层其他接口
(1)开始发射子弹
[cpp] void&BulletLayer::StartShoot(float&delay)//这里使用的是一个缺省函数,为什么这么用,后面会解释到。&&{&&&&&&this-&schedule(schedule_selector(BulletLayer::AddBullet),0.01f,kCCRepeatForever,delay);&&}&&
(2)停止发射子弹
[cpp] void&BulletLayer::StopShoot()//卸载任务执行器&&{&&&&&&this-&unschedule(schedule_selector(BulletLayer::AddBullet));&&}&&
(3)删除某颗子弹
[cpp] void&BulletLayer::RemoveBullet(CCSprite*&bullet)//一旦子弹和敌机碰撞,我们就要删掉这个子弹&&{&&&&&&if&(bullet!=NULL)&&&&&&{&&&&&&&&&&this-&m_pAllBullet-&removeObject(bullet);&&&&&&&&&&this-&removeChild(bullet,true);&&&&&&}&&}&&
好吧,到此为止,子弹层就创建完毕了,我们把它加入GameLayer层的init函数中,并执行开始发射子弹,看一下飞机是不是可以发射子弹了。
[cpp] //加入bulletLayer&&this-&bulletLayer=BulletLayer::create();&&this-&addChild(bulletLayer);&&this-&bulletLayer-&StartShoot();&&
发表评论:
TA的最新馆藏[转]&[转]&[转]&}

我要回帖

更多关于 全民飞机大战无子弹版 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信