cocos2d-x 3.2 |碰撞与分数
前情提要:飞机大战第五篇 实现碰撞与分数
思路:游戏里物体与物体的碰撞每帧都会检测 这里我们利用前面讲过的贪吃蛇移动原理 利用update方法来实时检测
如下:
新建类----->Game
第一步:Game类(实现主要的游戏逻辑模块)
Game.h
//引入需要用到的类
#include <stdio.h>
#include "cocos2d.h"
#include "cocos-ext.h"
#include "cocosGUI.h"
#include "Bullet.h"
#include "Enemy.h"
#include "Boom.h"
#include "Tool.h"
USING_NS_CC;
using namespace cocos2d;
class Game:Layer
{
public:
Vector<Bullet *> allBullet;//集合:子弹
float startX,startY;
CREATE_FUNC(Game);
static Scene * CreateScene();
bool init();
virtual bool onTouchBegan(Touch *touch, Event *unused_event);//触摸检测 按下
virtual void onTouchMoved(Touch *touch, Event *unused_event);<span style="font-family: Arial, Helvetica, sans-serif;">//触摸检测 移动</span>
void newBullet(float t);//产生子弹
void moveBullet(float t);//移动子弹
Vector<Enemy *> allEnemy;//<span style="font-family: Arial, Helvetica, sans-serif;">集合:</span><span style="font-family: Arial, Helvetica, sans-serif;">敌机</span>
void newEnemy(float t);//产生敌机
void moveEnemy(float t);//移动敌机
void update(float t);//游戏逻辑 碰撞检测
int m_score;
void reCallBack(Ref * obj);
Vector<Tool *> allTool;//集合:道具
};
Game.cpp
#include "Game.h"
#include "BackGround.h"
#include "Plane.h"
#include "MainMenu.h"
#include "SimpleAudioEngine.h"
#include "cocosGUI.h"
#include "GameOver.h"
#include "Tool.h"
#include "Enemy.h"
using namespace ui;
using namespace CocosDenshion;
USING_NS_CC;
Scene * Game::CreateScene()
{
auto scene=Scene::create();
auto layer=Game::create();
scene->addChild(layer);
return scene;
}
bool Game::init()
{
if (!Layer::init())
{
return false;
}
//创建 返回 按钮
auto menurt=MenuItemLabel::create(Label::createWithSystemFont("返回", "", 32),CC_CALLBACK_1(Game::reCallBack, this));
menurt->setAnchorPoint(Vec2::ZERO);
menurt->setPosition(600-30,Director::getInstance()->getWinSize().height-36);
menurt->setColor(Color3B::GREEN);
//创建菜单
auto menu=Menu::create(menurt,nullptr);
menu->setPosition(Vec2::ZERO);
this->addChild(menu,2);
//添加背景
auto bk=BackGround::create();
this->addChild(bk);
//添加飞机
auto fly1=Plane::create();
this->addChild(fly1,1);
fly1->moveTo(100,100);
fly1->setTag(10);
//处理飞机的HP
for (int i=0; i<fly1->hp; i++)
{
auto sphp=Sprite::create("hp_1.png");
sphp->setTag(1000+i);
this->addChild(sphp);
sphp->setAnchorPoint(Vec2(0,1));
sphp->setPosition(Vec2(i*sphp->getContentSize().width+3*i,Director::getInstance()->getWinSize().height));
}
//控制飞机飞行
auto listener=EventListenerTouchOneByOne::create();//创建侦听
listener->onTouchBegan=CC_CALLBACK_2(Game::onTouchBegan, this);//定义侦听的回调
listener->onTouchMoved=CC_CALLBACK_2(Game::onTouchMoved, this);
Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, this);//将侦听添加到事件分发器中
//产生子弹 计划任务
this->schedule(schedule_selector(Game::newBullet),0.2);//每隔200毫秒产生一次子弹
this->schedule(schedule_selector(Game::moveBullet),0.01);
//产生敌机
this->schedule(schedule_selector(Game::newEnemy),1);
this->schedule(schedule_selector(Game::moveEnemy),0.01);
//实现游戏逻辑
this->scheduleUpdate();
//分数显示器1
this->m_score=0;
auto tscore=TextAtlas::create("0000", "img_num_dis.png",17 , 22, "0");
this->addChild(tscore,12);
tscore->setTag(210);
tscore->setPosition(Vec2(Director::getInstance()->getWinSize().width/2,
Director::getInstance()->getWinSize().height-64));
//分数显示2
// auto scoreLb = Label::createWithSystemFont(StringUtils::format("分数:%d",score), "", 32);
// scoreLb->setAnchorPoint(Vec2::ZERO);
// scoreLb->setColor(Color3B::GREEN);
// scoreLb->setPosition(0,Director::getInstance()->getWinSize().height-36);
// scoreLb->setTag(123);
// this->addChild(scoreLb,2);
return true;
}
//返回主菜单
void Game::reCallBack(Ref * obj)
{
auto scene=MainMenu::CreateScene();
Director::getInstance()->replaceScene(scene);
}
//按下
bool Game::onTouchBegan(Touch *touch, Event *unused_event)
{
this->startX=touch->getLocation().x;
this->startY=touch->getLocation().y;
return true;
}
//移动
void Game::onTouchMoved(Touch *touch, Event *unused_event)
{
float mx=touch->getLocation().x-startX;
float my=touch->getLocation().y-startY;
auto fly1=(Plane *)this->getChildByTag(10);
fly1->moveTo(fly1->px+mx, fly1->py+my);
this->startX=touch->getLocation().x;
this->startY=touch->getLocation().y;
}
void Game::newBullet(float t)//产生子弹
{
auto fly1=(Plane *)this->getChildByTag(10);
Bullet * bt=Bullet::newBullet(1, 0,fly1->px,fly1->py);
allBullet.pushBack(bt);
this->addChild(bt);
//子弹音效
SimpleAudioEngine::getInstance()->playEffect("launch_1.wav");
}
void Game::moveBullet(float t)//移动子弹
{
for (int i=0;i<allBullet.size();i++)
{
Bullet * nowB=allBullet.at(i);
nowB->moveTo(nowB->px, nowB->py+15);
if (nowB->py>Director::getInstance()->getWinSize().height)
{
allBullet.erase(i);
this->removeChild(nowB);
i--;
}
}
}
void Game::newEnemy(float t)
{
int type=random()%10;
if (type < 3)
{
type = 1;
}
else if (type > 8)
{
type = 2;
}else
{
type = 1;
}
int ex=random()%(int)Director::getInstance()->getWinSize().width;
Enemy * news=Enemy::createEnemy(type, ex, Director::getInstance()->getWinSize().height+200);
allEnemy.pushBack(news);//将新产生的敌机添加到集合
this->addChild(news); //在当前GAME图层添加敌机层
}
void Game::moveEnemy(float t)
{
for (int i=0; i<allEnemy.size(); i++)
{
//获取第i架敌机
Enemy * nowE=allEnemy.at(i);
nowE->moveTo(nowE->ex, nowE->ey-5);
if (nowE->ey<-nowE->eSprite->getContentSize().height)
{
allEnemy.erase(i);
this->removeChild(nowE);
i--;
}
}
}
void Game::update(float t)
{
//创建一个Label层 获取计数器标签
//auto scoreLb = (Label *)this->getChildByTag(123);
//碰撞检测
if (allEnemy.size()==0 || allBullet.size()==0)
{
return;
}
auto fly1=(Plane *)this->getChildByTag(10);
//判断飞机和道具
for (int j = 0; j<allTool.size(); j++)
{
//得到第j架敌机
Tool * nowTool=allTool.at(j);
Rect br(fly1->px,
fly1->py,
fly1->getChildByTag(10)->getContentSize().width,
fly1->getChildByTag(10)->getContentSize().height);
//敌机的矩形大小
Rect er(nowTool->tx,
nowTool->ty,
nowTool->sp->getContentSize().width,
nowTool->sp->getContentSize().height);
if (br.intersectsRect(er))
{//碰撞检测到两个矩形相交
//判断吃到哪种道具
switch (nowTool->type) {
case 1://hp
{
fly1->hp++;
int i=fly1->hp-1;
auto sphp=Sprite::create("hp_1.png");
sphp->setTag(1000+i);
this->addChild(sphp);
sphp->setAnchorPoint(Vec2(0,1));
sphp->setPosition(Vec2(i*sphp->getContentSize().width+3*i,Director::getInstance()->getWinSize().height));
}
break;
case 2://炸雷
{
//所有敌机都销毁
while (allEnemy.size()>0)
{
Enemy * nowEnemy=allEnemy.at(0);
Boom * boom=Boom::createBoom(2, nowEnemy->ex, nowEnemy->ey);
this->addChild(boom,10);
//爆炸一次 总增加分数
this->m_score+=300;
allEnemy.eraseObject(nowEnemy);
nowEnemy->removeFromParentAndCleanup(true);
}
//播放音效
SimpleAudioEngine::getInstance()->playEffect("launch_1.wav");
//播放爆炸粒子
Boom * boom=Boom::createBoom(2,
Director::getInstance()->getWinSize().width/2,
Director::getInstance()->getWinSize().height/2);
this->addChild(boom,15);
}
break;
case 3://激光
break;
case 4://散弹
break;
}
//敌机消失
nowTool->unscheduleAllSelectors();
nowTool->removeFromParentAndCleanup(true);
allTool.eraseObject(nowTool);
j--;
}
}
for (int j = 0; j<allEnemy.size(); j++)
{
//得到第j架敌机
Enemy * nowEnemy=allEnemy.at(j);
//子弹的矩形大小
Rect br(fly1->px,
fly1->py,
fly1->getChildByTag(10)->getContentSize().width,
fly1->getChildByTag(10)->getContentSize().height);
//敌机的矩形大小
Rect er(nowEnemy->ex,
nowEnemy->ey,
nowEnemy->eSprite->getContentSize().width,
nowEnemy->eSprite->getContentSize().height);
if (br.intersectsRect(er))
{//碰撞检测到两个矩形相交
//敌机消失
allEnemy.eraseObject(nowEnemy);
nowEnemy->removeFromParentAndCleanup(true);
j--;
//掉血音效
SimpleAudioEngine::getInstance()->playEffect("skill_1.wav");
//我方Hp--
if (fly1->hp>0)
{
this->removeChildByTag(1000+fly1->hp-1);
fly1->hp=fly1->hp-1;
}
if(fly1->hp<=0)
{//Game Over
//创建一个场景
auto scene=GameOver::createScene();
//将场景覆盖到Game Over 并释放之前场景
Director::getInstance()->replaceScene(scene);
}
}
}
//判断子弹 是否碰到敌机
for (int i=0; i<allBullet.size(); i++)
{
//得到第i颗子弹
Bullet * nowBullet=allBullet.at(i);
for (int j = 0; j<allEnemy.size(); j++)
{
//得到第j架敌机
Enemy * nowEnemy=allEnemy.at(j);
//子弹的矩形大小
Rect br(nowBullet->px,
nowBullet->py,
nowBullet->bt->getContentSize().width,
nowBullet->bt->getContentSize().height);
//敌机的矩形大小
Rect er(nowEnemy->ex,
nowEnemy->ey,
nowEnemy->eSprite->getContentSize().width,
nowEnemy->eSprite->getContentSize().height);
if (br.intersectsRect(er))
{
//检测到两个矩形相交 子弹消失
allBullet.eraseObject(nowBullet);
nowBullet->removeFromParentAndCleanup(true);
i--;
nowEnemy->hp=nowEnemy->hp-1;
if(nowEnemy->hp<=0)
{
//爆炸
if(nowEnemy->type==1)
{
Boom * boom=Boom::createBoom(1, nowEnemy->ex, nowEnemy->ey);
this->addChild(boom);
//scoreLb->setString(StringUtils::format("分数:%d",score+=40));
//增加分数
this->m_score+=40;
}
else
{
Boom * boom=Boom::createBoom(2, nowEnemy->ex, nowEnemy->ey);
this->addChild(boom);
//scoreLb->setString(StringUtils::format("分数:%d",score+=60));
this->m_score+=60;
}
//分数增加器
auto score1=(TextAtlas *)this->getChildByTag(210);
score1->setString(StringUtils::format("%d",m_score));
//爆炸音效
SimpleAudioEngine::getInstance()->playEffect("launch_2.wav");
//道具处理
if (nowEnemy->toolID>0) {
//掉落道具
auto tool=Tool::newTool(nowEnemy->toolID,nowEnemy->ex,nowEnemy->ey);
this->addChild(tool);
allTool.pushBack(tool);
}
allEnemy.eraseObject(nowEnemy);
nowEnemy->removeFromParentAndCleanup(true);
j--;
}
break;//退出这次循环
}
}
}
}
总结:至此利用5个篇章简单实现了一下飞机大战的主要核心内容,希望对读者有帮
后期还有两个番外篇:游戏分数保存+安卓导出调试(因为安卓实在是让人蛋疼)
ps:游戏中用到的素材与音效请自行替换。