0
点赞
收藏
分享

微信扫一扫

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


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、运行结果:

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


7、待续




举报

相关推荐

0 条评论