Cocos2D-X射击小游戏(七)编码5 碰撞检测

来源:互联网 发布:社交软件 英语 编辑:程序博客网 时间:2024/06/05 18:20

1、现在,已经实现了三个精灵在场景上的显示和运动,但是子弹打中敌人后,没有产生任何效果。下面就来实现一个子弹打中敌人,子弹和敌人同时消失的功能。最重要的一步就是碰撞检测,即子弹所在的矩形与敌人所在的矩形有重叠时,即为子弹击中敌人。


2、因为子弹何时击中敌人是不确定的,所以我们需要不断的进行碰撞检测,以便确定子弹是否击中敌人。因此,需要将碰撞检测的实现放在计时器中,不断地执行检测。


3、具体实现:定义两个数组,分别用于存储子弹和敌人,在定时器的回调函数中进行碰撞检测(运用intersectsRect函数)。在创建精灵时将其存入数组,数组是类的成员变量。当然,数组需要不断释放移出边界的精灵。


4、碰撞检测函数:

void ShooterLayer::bulletCrashTest(){CCArray * projectilesToDelete  = new CCArray;CCArray * targetsToDelete  = new CCArray;CCObject* it = NULL;CCObject* jt = NULL;CCARRAY_FOREACH(_projectiles, it){CCSprite *projectile = dynamic_cast<CCSprite *>(it);CCRect projectileRect = CCRectMake(projectile->getPosition().x - (projectile->getContentSize().width/2), projectile->getPosition().y - (projectile->getContentSize().height/2), projectile->getContentSize().width, projectile->getContentSize().height);CCARRAY_FOREACH(_targets, jt){CCSprite *target = dynamic_cast<CCSprite*>(jt);CCRect targetRect = CCRectMake(target->getPosition().x - (target->getContentSize().width/2),target->getPosition().y - (target->getContentSize().height/2),target->getContentSize().width, target->getContentSize().height);if (/*CCRect::CCRectIntersectsRect(projectileRect, targetRect)*/projectileRect.intersectsRect(targetRect)){targetsToDelete->addObject(target);projectilesToDelete->addObject(projectile);}}}CCARRAY_FOREACH(targetsToDelete, jt){CCSprite *target = dynamic_cast<CCSprite*>(jt);_targets->removeObject(target);this->removeChild(target, true);}CCARRAY_FOREACH(projectilesToDelete, it){CCSprite* projectile = dynamic_cast<CCSprite*>(it);_projectiles->removeObject(projectile);this->removeChild(projectile, true);}projectilesToDelete->release();targetsToDelete->release();}


5、完整ShooterLayer类代码:

ShooterLayer.h

#pragma once#include "cocos2d.h"class ShooterLayer : public cocos2d::CCLayerColor{public:ShooterLayer(void);~ShooterLayer(void);// 初始化函数bool init();// new一个对象,如果成功的话则调用初始化函数CREATE_FUNC(ShooterLayer);// 关闭菜单的回调函数void menuCloseCallback(CCObject *pObj);// 计时器的回调函数void update(float dt);// 随机创建敌方精灵void addTarget();// 敌方精灵飞出边界的回调函数void SpriteMoveFinished(CCNode *pObj);// 触摸操作(即Win32中的鼠标点击操作)响应函数void ccTouchesEnded(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent);// 保存射击精灵的大小cocos2d::CCSize _szPlayer;// 碰撞检测void bulletCrashTest();// 子弹精灵数组cocos2d::CCArray *_targets;// 敌人精灵数组cocos2d::CCArray *_projectiles;};

ShooterLayer.cpp

#include "ShooterLayer.h"USING_NS_CC;// 标记精灵enum{TARGET,PROJECT};ShooterLayer::ShooterLayer(void){_targets = NULL;_projectiles = NULL;}ShooterLayer::~ShooterLayer(void){if (_targets){delete _targets;_targets = NULL;}if (_projectiles){delete _projectiles;_projectiles = NULL;}}bool ShooterLayer::init(){bool bRct = false;// 初始化数组_targets = new CCArray;_projectiles = new CCArray;do {// 1、初始化布景CC_BREAK_IF(!CCLayerColor::initWithColor(ccc4(255, 227, 132, 255)));// 2、创建窗口右下角的关闭菜单// 创建菜单项CCMenuItemImage *pCloseItem = NULL;pCloseItem = CCMenuItemImage::create("CloseNormal.png","CloseSelected.png",this,menu_selector(ShooterLayer::menuCloseCallback)); // 回调函数// 检测创建是否成功CC_BREAK_IF(!pCloseItem);  // create失败则返回// 设置菜单项位置pCloseItem->setPosition(CCDirector::sharedDirector()->getWinSize().width - 20, 20);// 创建菜单CCMenu *pMenu = CCMenu::create(pCloseItem, NULL);// 设置菜单位置pMenu->setPosition(CCPointZero);// 将菜单添加至布景this->addChild(pMenu);//////////////////////////////////////////////////////////////////////////// 创建精灵CCSprite *pSprite = CCSprite::create("Player.png");// 获取窗口大小CCSize sz = CCDirector::sharedDirector()->getWinSize();// 设置精灵位置pSprite->setPosition(CCPointMake(pSprite->getContentSize().width/2, sz.height/2));// 将精灵添加至布景this->addChild(pSprite);// 保存精灵大小_szPlayer = pSprite->getContentSize();//////////////////////////////////////////////////////////////////////////// 设置计时器this->scheduleUpdate();//////////////////////////////////////////////////////////////////////////// 允许触摸(注意:很重要)this->setTouchEnabled(true);//////////////////////////////////////////////////////////////////////////bRct = true;} while (0);return bRct;}void ShooterLayer::menuCloseCallback(CCObject *pObj){// 退出程序CCDirector::sharedDirector()->end();}void ShooterLayer::update(float dt){static int tmpTimes = 0;static int tmpCount = 20;if (tmpTimes++ > tmpCount){addTarget();tmpCount = rand() % 60 + 20;tmpTimes = 0;}bulletCrashTest();}void ShooterLayer::addTarget(){// 创建精灵CCSprite *target = CCSprite::create("Target.png");// 计算敌方精灵可能出现的位置范围CCSize sz = CCDirector::sharedDirector()->getWinSize();int x = sz.width + target->getContentSize().width/2;int nMax = sz.height - target->getContentSize().height/2;int nMin = target->getContentSize().height/2;// 产生随机数int f = rand() % (nMax - nMin);int y = nMin + f;// 根据随机数,设置起始精灵位置target->setPosition(CCPointMake(x, y));// 利用计时器确定执行序列动作的速度float nDurMin = 2.0;float nDurMax = 4.0;float nDur = float(rand() % 100) / 100.0 + nDurMin;nDur = nDur > nDurMax ? nDurMax : nDur;// 定义两个动作(平移动作, 以及移出边界的响应)CCFiniteTimeAction *action = CCMoveTo::create(nDur, ccp(-target->getContentSize().width/2, y));CCFiniteTimeAction *actionDone = CCCallFuncN::create(this,callfuncN_selector(ShooterLayer::SpriteMoveFinished));  // 这里需要一个移出边界的响应函数// 添加序列动作CCAction *pseq = CCSequence::create(action, actionDone, NULL); // 将序列动作添加至精灵,使其执行target->runAction(pseq);// 将精灵添加至布景this->addChild(target);//////////////////////////////////////////////////////////////////////////// 加入数组_targets->addObject(target);// 设置标记target->setTag(TARGET);}void ShooterLayer::SpriteMoveFinished(CCNode *pObj){// 获取移出精灵对象指针CCSprite *pSprite = (CCSprite*)pObj;// 清除this->removeChild(pSprite, true);}void ShooterLayer::ccTouchesEnded(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent){// 获取CCTouch指针对象CCTouch *pTouch = (CCTouch*)pTouches->anyObject();// 获取视图位置CCPoint location = pTouch->getLocationInView();// 转化为OpenGL坐标location = CCDirector::sharedDirector()->convertToGL(location); // 创建子弹精灵CCSprite *project = CCSprite::create("Projectile.png");// 窗口大小CCSize sz = CCDirector::sharedDirector()->getWinSize(); // 子弹起点CCPoint pt = ccp(_szPlayer.width + project->getContentSize().width/2, sz.height/2);// 设置子弹起点project->setPosition(pt); // 添加精灵至布景this->addChild(project);  //////////////////////////////////////////////////////////////////////////// 添加至数组_projectiles->addObject(project);// 添加标记project->setTag(PROJECT);//////////////////////////////////////////////////////////////////////////// 求出子弹终点坐标int x = sz.width + project->getContentSize().width/2;float yDistance = (location.y - pt.y) / (location.x - pt.x) * (sz.width - _szPlayer.width);// 子弹动作CCFiniteTimeAction *action = CCMoveTo::create(1.0, ccp(x, yDistance + sz.height/2));CCFiniteTimeAction *actionDone = CCCallFuncN::create(this, callfuncN_selector(ShooterLayer::SpriteMoveFinished));project->runAction(CCSequence::create(action, actionDone, NULL));}void ShooterLayer::bulletCrashTest(){// 定义两个数组用于存储待删除的精灵CCArray * projectilesToDelete  = new CCArray;CCArray * targetsToDelete  = new CCArray;CCObject* it = NULL;CCObject* jt = NULL;CCARRAY_FOREACH(_projectiles, it){CCSprite *projectile = dynamic_cast<CCSprite *>(it);CCRect projectileRect = CCRectMake(projectile->getPosition().x - (projectile->getContentSize().width/2), projectile->getPosition().y - (projectile->getContentSize().height/2), projectile->getContentSize().width, projectile->getContentSize().height);CCARRAY_FOREACH(_targets, jt){CCSprite *target = dynamic_cast<CCSprite*>(jt);CCRect targetRect = CCRectMake(target->getPosition().x - (target->getContentSize().width/2),target->getPosition().y - (target->getContentSize().height/2),target->getContentSize().width, target->getContentSize().height);// 碰撞检测if (/*CCRect::CCRectIntersectsRect(projectileRect, targetRect)*/projectileRect.intersectsRect(targetRect)){targetsToDelete->addObject(target);projectilesToDelete->addObject(projectile);}}}// 释放资源CCARRAY_FOREACH(targetsToDelete, jt){CCSprite *target = dynamic_cast<CCSprite*>(jt);_targets->removeObject(target);this->removeChild(target, true);}CCARRAY_FOREACH(projectilesToDelete, it){CCSprite* projectile = dynamic_cast<CCSprite*>(it);_projectiles->removeObject(projectile);this->removeChild(projectile, true);}projectilesToDelete->release();targetsToDelete->release();}


6、运行结果:


7、待续




0 0
原创粉丝点击