【cocos2d-x-3.2】【高仿微信打飞机系列二】【敌机 碰撞检测 爆炸管理】

【cocos2d-x-3.2】【高仿微信打飞机系列二】【敌机 碰撞检测 爆炸管理】,第1张

概述继续打飞机之旅,这一篇主要加入敌机类,和碰撞检测,以及爆炸效果管理器。写完他,基本的打飞机游戏就出来了,只要在这个架构上继续完善,加入其他功能,一个完整的游戏就可以出来。废话不多说,现在开始。 1.敌机类 这个其实主要从子d类那里copy过来,修改一下就可以了。因为他们的行为是类似的,所以不必重新构建。最终我们还要实现多种类型的敌机,现在只先实现一种类型的敌机,称之为EnemyNormal吧,代码

继续打飞机之旅,这一篇主要加入敌机类,和碰撞检测,以及爆炸效果管理器。写完他,基本的打飞机游戏就出来了,只要在这个架构上继续完善,加入其他功能,一个完整的游戏就可以出来。废话不多说,现在开始。

1.敌机类

这个其实主要从子d类那里copy过来,修改一下就可以了。因为他们的行为是类似的,所以不必重新构建。最终我们还要实现多种类型的敌机,现在只先实现一种类型的敌机,称之为Enemynormal吧,代码如下:

#ifndef _ENEMY_norMAL_H_#define _ENEMY_norMAL_H_#include "EnemyBase.h"class Enemynormal : public EnemyBase{public:	Enemynormal();	~Enemynormal();	//CREATE_FUNC(Enemynormal);	//virtual bool init();	static Enemynormal* create(Sprite* sprite);	bool init(Sprite* sprite);};#endif#include "Enemynormal.h"Enemynormal::Enemynormal(){	m_speed = SPEED_ENEMY_norMAL_DEFAulT;}Enemynormal::~Enemynormal(){}bool Enemynormal::init(Sprite* sprite){	bool ret = false;	bindSprite(sprite);	ret = true;	return ret;}Enemynormal* Enemynormal::create(Sprite* sprite){	Enemynormal* enemy = new Enemynormal();	if(enemy && enemy->init(sprite))	{		enemy->autorelease();	}	else	{		CC_SAFE_DELETE(enemy);	}	return enemy;}
这个没什么好说的,到时候需要什么其他属性,直接在这个类添加即可。

忘了EnemyBase这个基类了,把敌机的共同属性都放到这里,以后不同敌机直接继承他便可。

#ifndef _ENEMY_BASE_H_#define _ENEMY_BASE_H_#include "Entity.h"#define SPEED_DEFAulT 10#define SPEED_norMAL 5#define SPEED_ENEMY_norMAL_DEFAulT 10class EnemyBase:public Entity{public:	EnemyBase();	~EnemyBase();	bool getEnemyOutScreen();	voID setEnemyOutScreen(bool out);	bool getEnemyUsed();	voID setEnemyUsed(bool used);	int getEnemySpeed();	voID setEnemySpeed(int speed);	//virtual voID bombDead();private:	bool m_isOutScreen;	bool m_isUsed;protected:	int m_speed;};#endif#include "EnemyBase.h"EnemyBase::EnemyBase(){}EnemyBase::~EnemyBase(){}bool EnemyBase::getEnemyOutScreen(){	return m_isOutScreen;}voID EnemyBase::setEnemyOutScreen(bool out){	m_isOutScreen = out;}bool EnemyBase::getEnemyUsed(){	return m_isUsed;}voID EnemyBase::setEnemyUsed(bool use){	m_isUsed = use;}int EnemyBase::getEnemySpeed(){	return m_speed;}voID EnemyBase::setEnemySpeed(int speed){	m_speed = speed;}
接着,我们敌机造出来了,那么怎么源源不断的生成飞机呢,我们先把敌机生成,然后在PlaneGameScene不断生成。所以,现在先生成敌机吧,简称敌机管理器:
#ifndef _ENEMY_MANAGER_H_#define _ENEMY_MANAGER_H_#include "cocos2d.h"USING_NS_CC;#define ENEMY_norMAL_NUM 20class EnemyBase;class PlaneHero;class EnemyManager : public Node{public:	EnemyManager();	~EnemyManager();	//获取未用的子d	EnemyBase* getUnsedEnemy();	virtual bool init();	static EnemyManager* create();		//获取敌机列表	Vector<EnemyBase*> getEnemyList();	//注入英雄飞机	voID setHeroPlane(PlaneHero* hero);	PlaneHero* getHeroPlane();private:	Vector<EnemyBase*> m_enemyList;//敌机列表	voID createEnemy();	voID EnemyLogicCheck(float dt);	voID receiveMessge(Ref* pSender);private:	PlaneHero* hero_plane;//持有英雄飞机	bool isGameOver;};#endif#include "EnemyManager.h"#include "Enemynormal.h"#include "PlaneHero.h"#include "BombManager.h"EnemyManager::EnemyManager(){	hero_plane = NulL;	isGameOver = false;}EnemyManager::~EnemyManager(){}EnemyBase* EnemyManager::getUnsedEnemy(){	for(auto enemy : m_enemyList)	{		if(enemy->getEnemyUsed() == false)		{			enemy->setEnemyUsed(true);			enemy->setEnemyOutScreen(false);			return enemy;		}	}	log("no bullet unused");	return NulL;}bool EnemyManager::init(){	//创建敌机列表	createEnemy();	//循环检测子d列表	this->schedule(schedule_selector(EnemyManager::EnemyLogicCheck),0.01f);	NotificationCenter::getInstance()->addobserver(this,callfuncO_selector(EnemyManager::receiveMessge),"gameover",NulL);	return true;}EnemyManager* EnemyManager::create(){	EnemyManager* eMgr = new EnemyManager();	if(eMgr && eMgr->init())	{		eMgr->autorelease();	}	else	{		CC_SAFE_DELETE(eMgr);	}	return eMgr;}voID EnemyManager::createEnemy(){	EnemyBase* enemy = NulL;	for(int i = 0; i < ENEMY_norMAL_NUM; i++)	{		auto enemy_sprite = Sprite::create("enemy1.png");		enemy = Enemynormal::create(enemy_sprite);		enemy->setEnemyUsed(false);		enemy->setEnemyOutScreen(false);		enemy->setAnchorPoint(Point(0.2,0));		m_enemyList.pushBack(enemy);		this->addChild(enemy);	}	log("m_enemyList size() = %d",m_enemyList.size());}voID EnemyManager::EnemyLogicCheck(float dt){	if(isGameOver == true)	{		return;	}	//auto visibleSize = Director::getInstance()->getVisibleSize();	for(auto enemy : m_enemyList)	{		if(enemy->getEnemyUsed() == true)		{			//敌机运行			Point pos = enemy->getposition();			pos.y -= SPEED_DEFAulT;			enemy->setpositionY(pos.y);			//out of screen			if(pos.y <= 0)			{				enemy->setEnemyOutScreen(true);				enemy->setEnemyUsed(false);			}			//敌机运行			Point pos_enemy = enemy->getposition();			//英雄位置			Point pos_hero = hero_plane->getposition();				Rect enemyRect = enemy->getBoundingBox();			Rect heroRect = hero_plane->getBoundingBox();			enemyRect.size.wIDth *= 0.8;			enemyRect.size.height *= 0.8;			heroRect.size.wIDth *= 0.5;			heroRect.size.height *= 0.5;			//if(enemyRect.containsPoint(pos_hero) || heroRect.containsPoint(pos_enemy))			if(enemyRect.intersectsRect(heroRect))			{				auto enemy_size = enemy->getContentSize();				auto hero_size = hero_plane->getContentSize();				//用于测试位置				log("enemyRect x = %f,y = %f,wIDth = %f,height = %f",enemyRect.origin.x,enemyRect.origin.y,enemyRect.size.wIDth,enemyRect.size.height);				log("heroRect x = %f,heroRect.origin.x,heroRect.origin.y,heroRect.size.wIDth,heroRect.size.height);				log("enemy_size wIDth = %f,enemy_size.wIDth,enemy_size.height);				log("hero_size wIDth = %f,hero_size.wIDth,hero_size.height);				log("pos_enemy x = %f,y = %f",pos_enemy.x,pos_enemy.y);				log("pos_hero x = %f,pos_hero.x,pos_hero.y);				BombManager::getInstance()->bombHeroPlane(pos_hero);				NotificationCenter::getInstance()->postNotification("gameover",NulL);				//hero_plane->removeFromParentAndCleanup(true);				//enemy->setEnemyUsed(false);				//enemy->setpositionY(-105);				break;			}		}	}}Vector<EnemyBase*> EnemyManager::getEnemyList(){	return m_enemyList;}voID EnemyManager::setHeroPlane(PlaneHero* hero){	hero_plane = hero;}PlaneHero* EnemyManager::getHeroPlane(){	return hero_plane;}voID EnemyManager::receiveMessge(Ref* pSender){	isGameOver = true;	log("EnemyManager::receiveMessge()");}

最后,源源不断的生成敌机和生成子d是类似的,在PlaneGameScene这里生成:

voID PlayGameScene::makeBulletAndEnemy(float dt){	if(isGameOver == true)	{		return;	}	//Size visibleSize = Director::getInstance()->getVisibleSize();	makeBullet();	makeEnemy();}//生成子dvoID PlayGameScene::makeBullet(){	auto hero_plane = this->getChildByTag(HERO_PLANE);	Point pos = hero_plane->getposition();	BulletBase* bullet = bMgr->getUnusedBullet();	//BulletBase* bullet = NulL;	if(bullet == NulL)	{		return;	}	bullet->setposition(pos);}//生成敌机voID PlayGameScene::makeEnemy(){	Size visibleSize = Director::getInstance()->getVisibleSize();	int posX = rand() % (int)(visibleSize.wIDth);	EnemyBase* enemy = eMgr->getUnsedEnemy();	if(enemy == NulL)	{		return;	}	enemy->setposition(Point(posX,(int)(visibleSize.height)));}
2.碰撞检测

碰撞检测还是不那么精确,只能通过一步一步慢慢调,上面代码加了log大部分就是为了看那个位置。至今仍然未找到比较好的方法来检测碰撞。

首先是子d与敌机的碰撞检测,在子d管理器进行处理:

//检测子dvoID BulletManager::bulletLogicCheck(float dt){	if(isGameOver == true)	{		return;	}	auto visibleSize = Director::getInstance()->getVisibleSize();	for(auto bullet : m_bulletList)	{		if(bullet->isUsed() == true)		{			//子d运行			Point pos_bullet = bullet->getposition();			pos_bullet.y += SPEED_DEFAulT;			bullet->setpositionY(pos_bullet.y);			//碰撞处理			for(auto enemy : eMgr->getEnemyList())			{				if(enemy->getEnemyUsed() == true)				{					//敌机运行					Point pos_enemy = enemy->getposition();					Point pos_bullet = bullet->getposition();					Rect enemyRect = enemy->getBoundingBox();					Rect bulletRect = bullet->getBoundingBox();					auto enemy_size = enemy->getContentSize();					auto bullet_size = bullet->getContentSize();					if(enemyRect.intersectsRect(bulletRect))					//if(bulletRect.containsPoint(pos_enemy))					{						log("enemyRect x = %f,enemyRect.size.height);						log("bulletRect x = %f,bulletRect.origin.x,bulletRect.origin.y,bulletRect.size.wIDth,bulletRect.size.height);						log("enemy_size wIDth = %f,enemy_size.height);						log("bullet_size wIDth = %f,bullet_size.wIDth,bullet_size.height);						log("pos_enemy x = %f,pos_enemy.y);						log("pos_bullet x = %f,pos_bullet.x,pos_bullet.y);						bullet->setUsed(false);						bullet->setpositionY(visibleSize.height * 10);						BombManager::getInstance()->bombnormalEnemy(pos_enemy);						enemy->setEnemyUsed(false);						enemy->setpositionY(-105);						continue;					}				}			}						//out of screen			if(pos_bullet.y >= visibleSize.height)			{				bullet->setIsMoveOutScreen(true);				bullet->setUsed(false);			}		}	}}
其次,是敌机与英雄飞机的碰撞检测,在敌机管理器里面处理,其实和子d管理器差不多,敌机管理器需要持有英雄飞机的引用,才能实现碰撞检测。通过注入英雄飞机即可实现。
//碰撞检测voID EnemyManager::EnemyLogicCheck(float dt){	if(isGameOver == true)	{		return;	}	//auto visibleSize = Director::getInstance()->getVisibleSize();	for(auto enemy : m_enemyList)	{		if(enemy->getEnemyUsed() == true)		{			//敌机运行			Point pos = enemy->getposition();			pos.y -= SPEED_DEFAulT;			enemy->setpositionY(pos.y);			//out of screen			if(pos.y <= 0)			{				enemy->setEnemyOutScreen(true);				enemy->setEnemyUsed(false);			}			//敌机运行			Point pos_enemy = enemy->getposition();			//英雄位置			Point pos_hero = hero_plane->getposition();				Rect enemyRect = enemy->getBoundingBox();			Rect heroRect = hero_plane->getBoundingBox();			enemyRect.size.wIDth *= 0.8;			enemyRect.size.height *= 0.8;			heroRect.size.wIDth *= 0.5;			heroRect.size.height *= 0.5;			//是否碰撞			if(enemyRect.intersectsRect(heroRect))			{				auto enemy_size = enemy->getContentSize();				auto hero_size = hero_plane->getContentSize();				//用于测试位置				log("enemyRect x = %f,pos_hero.y);				//爆炸效果				BombManager::getInstance()->bombHeroPlane(pos_hero);				//发出游戏结束的通知				NotificationCenter::getInstance()->postNotification("gameover",NulL);				break;			}		}	}}
3.爆炸效果管理器

发现爆炸效果的代码还是挺多的,以后不同类型的敌机效果还要处理,所以就单独提取出来,放在一个类,称之为爆炸效果管理器。我们需要那种类型的爆炸效果,直接通过这个单例类获取就可以了。很是方便,易于管理。

#ifndef _BOMB_MANAGER_H_#define _BOMB_MANAGER_H_#include "cocos2d.h"class BombManager : public cocos2d::Node{public:	BombManager();	~BombManager();	//单例模式,获取实例	static BombManager* getInstance();	//普通飞机的爆炸效果	voID bombnormalEnemy(cocos2d::Point pos);	//主飞机的爆炸效果	voID bombHeroPlane(cocos2d::Point pos);	//初始化各个爆炸的animation	voID inite();	//爆炸后的回调,清除爆炸的痕迹,通用	voID bombDone(Node* sender);private:	static BombManager* _instance;//单例};#endif#include "BombManager.h"USING_NS_CC;BombManager* BombManager::_instance = NulL;BombManager::BombManager(){}BombManager::~BombManager(){}voID BombManager::inite(){	//添加普通敌机爆炸效果	auto spriteFrameCache = SpriteFrameCache::getInstance();	Vector<SpriteFrame*> frameList;	for(int i = 1; i <=4; i++)	{		SpriteFrame* sf = SpriteFrame::create(String::createWithFormat("enemy1_down%d.png",i)->_string,Rect(0,57,51));		frameList.pushBack(sf);		spriteFrameCache->addSpriteFrame(sf,String::createWithFormat("enemy1_down%d.png",i)->_string);	}		Animation* normal_enemy_animation = Animation::createWithSpriteFrames(frameList,0.1f);	AnimationCache::getInstance()->addAnimation(normal_enemy_animation,"normal_enemy_bomb");	//添加英雄飞机爆炸效果	frameList.clear();	for(int i = 1; i <=4; i++)	{		SpriteFrame* sf = SpriteFrame::create(String::createWithFormat("hero_blowup_n%d.png",102,126));		frameList.pushBack(sf);		spriteFrameCache->addSpriteFrame(sf,String::createWithFormat("hero_blowup_n%d.png",i)->_string);	}	Animation* hero_plane_animation = Animation::createWithSpriteFrames(frameList,0.3f);	AnimationCache::getInstance()->addAnimation(hero_plane_animation,"hero_plane_bomb");	//add other bomb}//普通敌机爆炸效果voID BombManager::bombnormalEnemy(Point pos){	auto animate = Animate::create(AnimationCache::getInstance()->getAnimation("normal_enemy_bomb"));	auto repeat = Repeat::create(animate,1);	auto sprite = Sprite::create();	sprite->setposition(pos);	this->addChild(sprite);	//回调函数	auto callback = CallFunc::create(CC_CALLBACK_0(BombManager::bombDone,this,sprite));	auto sequence = Sequence::create(repeat,callback,NulL);	sprite->runAction(sequence);}//英雄飞机爆炸效果voID BombManager::bombHeroPlane(cocos2d::Point pos){	auto animate = Animate::create(AnimationCache::getInstance()->getAnimation("hero_plane_bomb"));	auto repeat = Repeat::create(animate,NulL);	sprite->runAction(sequence);}BombManager* BombManager::getInstance(){	if(_instance == NulL)	{		_instance = new BombManager();		if(_instance)		{			//初始化			_instance->inite();		}	}	return _instance;}//爆炸后清除自己的痕迹voID BombManager::bombDone(Node* sender){	sender->removeFromParentAndCleanup(true);}
4.修改游戏界面

以上实现后,最后还是要把上面的东西加入游戏界面,那么需要把上面的节点加入到PlaneGameScene中。在这个类的init函数里,加入以下代码:

	bMgr = BulletManager::create();	//由于忘记添加进层里,导致bMgr->getUnusedBullet()一直出错	this->addChild(bMgr,1);	//生成敌机管理器	eMgr = EnemyManager::create();	this->addChild(eMgr,1);	//注入敌机管理器	bMgr->setEnemyManager(eMgr);	//注入爆炸管理器	this->addChild(BombManager::getInstance(),1);	//add plane hero 	Sprite* hero = Sprite::create("hero1.png");	PlaneHero* hero_plane = PlaneHero::create(hero);	hero_plane->setposition(Point(visibleSize.wIDth / 2,visibleSize.height / 2));	hero_plane->setTag(HERO_PLANE);	hero_plane->setAnchorPoint(Point(0,0));	this->addChild(hero_plane,1);	//注入英雄飞机给敌机管理器,做检测碰撞使用	eMgr->setHeroPlane(hero_plane);
拖动飞机的时候,点击感觉也不是很精确,换种方式实现touchevent,感觉精确度提高了不少。

	// 添加监听器,监听主飞机	_eventdispatcher->addEventListenerWithSceneGraPHPriority(touchListener,hero_plane);	//_eventdispatcher->addEventListenerWithSceneGraPHPriority(touchListener,enemy_plane);//touch event handlerbool PlayGameScene::ontouchBegan(touch *touch,Event* event){	if(isGameOver == true)	{		return true;	}	// 获取事件所绑定的 target 	auto target = static_cast<Layer*>(event->getCurrentTarget());	if(target == NulL)	{		log("target = NulL");		return true;	}	btouchPlane = false;	// 获取当前点击点所在相对按钮的位置坐标    // getLocation得到的是openGL坐标系,也就是世界坐标系	Point touchPoint = touch->getLocation();	Point locationInNode = target->convertToNodeSpace(touchPoint);	Size target_size = target->getContentSize();	Rect target_rect = Rect(0,target_size.wIDth,target_size.height);	//auto hero_plane = this->getChildByTag(HERO_PLANE);	//Point hero_pos = hero_plane->getposition();	//Size hero_size = hero_plane->getContentSize();	//log("hero_pos x = %f,hero_pos.x,hero_pos.y);	log("touchPoint x = %f,touchPoint.x,touchPoint.y);	log("locationInNode x = %f,locationInNode.x,locationInNode.y);	log("target_size wIDth = %f,target_size.height);	log("target_rect x = %f,target_rect.origin.x,target_rect.origin.y,target_rect.size.wIDth,target_rect.size.height);	//log("hero_size wIDth = %f,hero_size.height);	//if(touchPoint.x >= hero_pos.x && touchPoint.x <= (hero_pos.x + hero_size.wIDth) && touchPoint.y >= hero_pos.y && touchPoint.y <= (touchPoint.y + hero_size.height))	if(target_rect.containsPoint(locationInNode))	{		//touch the plane,mark this flag for use		btouchPlane = true;	}	return true;}

不明觉厉,这个方法还有待研究一下。

好了,这篇到此结束,第三篇后续会更新上来,纯属想到哪写到哪。

效果图如下:

总结

以上是内存溢出为你收集整理的【cocos2d-x-3.2】【高仿微信打飞机系列二】【敌机 碰撞检测 爆炸管理】全部内容,希望文章能够帮你解决【cocos2d-x-3.2】【高仿微信打飞机系列二】【敌机 碰撞检测 爆炸管理】所遇到的程序开发问题。

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

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

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

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

发表评论

登录后才能评论

评论列表(0条)

保存