继续打飞机之旅,这一篇主要加入敌机类,和碰撞检测,以及爆炸效果管理器。写完他,基本的打飞机游戏就出来了,只要在这个架构上继续完善,加入其他功能,一个完整的游戏就可以出来。废话不多说,现在开始。
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】【高仿微信打飞机系列二】【敌机 碰撞检测 爆炸管理】所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)