cocos2dx3的官方demo游戏c++实现(Kill Bugs)
最近一直在研究cocos2dx引擎,由于之前没有接触过,所以算是从小白入门,在官网找了下demo,但是是lua实现,没学过。所以只能自己一步步的搞,现在基本有个原型了,其他就是细节的方面。
1.效果图
开始界面
游戏界面
死亡画面
可以看到bug的死亡方向有点奇怪,这主要是因为官方给的资源里面bug的死亡图与存活图的头部朝向不一致,所以不太好根据死亡的位置去设置旋转。
2.代码
2.1蚂蚁bug
AntSptite.h
#ifndef _ANT_SPRITE_H
#define _ANT_SPTITE_H
#include"cocos2d.h"
#include<string>
using namespace std;
USING_NS_CC;
class Ant :public cocos2d::Sprite
{
public:
static Ant* createAnt(string filename,Rect rect);
virtual bool init()override;
//添加点击事件
bool onTouchBegan(Touch* touch,Event* event);
void onTouchEnded(Touch* touch,Event* event);
//设置点击事件
bool setListener();
CREATE_FUNC(Ant);
};
#endif
AntSprite.cpp
#include"AntSprite.h"
#include"string"
USING_NS_CC;
using namespace std;
Ant* Ant::createAnt(string filename,Rect rect)
{
Ant* sprite = new Ant();
if (sprite && sprite->initWithFile(filename,rect))
{
sprite->autorelease();
return sprite;
}
CC_SAFE_DELETE(sprite);
return nullptr;
}
bool Ant::init()
{
if (!Sprite::init())
{
return false;
}
return true;
}
bool Ant::onTouchBegan(Touch* touch,Event* event)
{
auto target = static_cast<Sprite*>(event->getCurrentTarget());
int tag = target->getTag();
auto pos = target->convertTouchToNodeSpace(touch);
auto size = target->getContentSize();
auto rect = Rect(0, 0, size.width, size.height);
if (rect.containsPoint(pos))
{
auto sprite = this->createAnt("BugAnt.png", Rect(480, 0, 240, 240));
sprite->setTag(3);
sprite->setPosition(this->getPosition());
this->getParent()->addChild(sprite);
this->getParent()->removeChild(this);
return true;
}
return false;
}
void Ant::onTouchEnded(Touch* touch,Event* event)
{
log("touchended");
}
bool Ant::setListener()
{
auto listener = EventListenerTouchOneByOne::create();
listener->onTouchBegan = CC_CALLBACK_2(Ant::onTouchBegan, this);
listener->onTouchEnded = CC_CALLBACK_2(Ant::onTouchEnded, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
return true;
}
2.2蜘蛛bug
SpiderSprite.h
#ifndef _SPIDER_SPRITE_H
#define _SPIDER_SPRITE_H
#include"cocos2d.h"
#include<string>
using namespace std;
USING_NS_CC;
class Spider:public cocos2d::Sprite
{
public:
CREATE_FUNC(Spider);
static Spider* createSpider(string filename, cocos2d::Rect rect);
virtual bool init();
//添加点击事件
bool onTouchBegan(Touch* touch, Event* event);
void onTouchEnded(Touch* touch, Event* event);
//设置点击事件
bool setListener();
};
#endif // !_SPIDER_SPRITE_H
SpiderSprite.cpp
#include"SpiderSprite.h"
Spider* Spider::createSpider(string filename, Rect rect)
{
Spider* sprite = new Spider();
if (sprite && sprite->initWithFile(filename, rect))
{
sprite->autorelease();
return sprite;
}
CC_SAFE_DELETE(sprite);
return nullptr;
}
bool Spider::init()
{
if (!Sprite::init())
{
return false;
}
return true;
}
bool Spider::onTouchBegan(Touch* touch, Event* event)
{
auto target = static_cast<Sprite*>(event->getCurrentTarget());
int tag = target->getTag();
auto pos = target->convertTouchToNodeSpace(touch);
auto size = target->getContentSize();
auto rect = Rect(0, 0, size.width, size.height);
if (rect.containsPoint(pos))
{
auto sprite = this->createSpider("BugSpider.png", Rect(320, 0, 160, 160));
sprite->setTag(4);
sprite->setPosition(this->getPosition());
this->getParent()->addChild(sprite);
this->getParent()->removeChild(this);
return true;
}
return false;
}
void Spider::onTouchEnded(Touch* touch, Event* event)
{
log("touchended");
}
bool Spider::setListener()
{
auto listener = EventListenerTouchOneByOne::create();
listener->onTouchBegan = CC_CALLBACK_2(Spider::onTouchBegan, this);
listener->onTouchEnded = CC_CALLBACK_2(Spider::onTouchEnded, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
return true;
}
3.开始场景
MainScene.h
#ifndef __MAIN_SCENE_H__
#define __MAIN_SCENE_H__
#include"cocos2d.h"
#include"extensions/cocos-ext.h"
USING_NS_CC_EXT;
//开始类声明
class GameStart :public cocos2d::Scene
{
public:
int flag = 0;
static cocos2d::Scene* createScene();
bool init()override;
//点击开始按钮事件
void startClicked(cocos2d::Ref* sender,Control::EventType event);
void loadSouce();
CREATE_FUNC(GameStart);
};
#endif
MainScene.cpp
#include "MainScene.h"
#include "PlayScene.h"
USING_NS_CC;
Scene* GameStart::createScene()
{
return GameStart::create();
}
bool GameStart::init()
{
if (!Scene::init())
{
return false;
}
auto director = Director::getInstance();
auto size = director->getVisibleSize();
//添加背景
auto bgsprite = Sprite::create("MainSceneBg.png");
if (bgsprite == nullptr)
{
log("No such file path");
}
else
{
bgsprite->setPosition(Vec2(size.width/2,size.height/2));
this->addChild(bgsprite, -1);
}
auto statrtSprite = Scale9Sprite::create("PlayButton.png");
auto startButton = ControlButton::create(statrtSprite);
if (startButton == nullptr)
{
log("No such file path");
}
startButton->setPosition(Vec2(415,30));
startButton->setAnchorPoint(Vec2::ZERO);
startButton->addTargetWithActionForControlEvents(this, cccontrol_selector(GameStart::startClicked), Control::EventType::TOUCH_DOWN);
this->addChild(startButton);
loadSouce();
return true;
}
void GameStart::startClicked(Ref* sender,Control::EventType event)
{
auto playScene = Play::createScene();
Director::getInstance()->replaceScene(TransitionFlipX::create(1.0f,playScene));
}
void GameStart::loadSouce()
{
SimpleAudioEngine::getInstance()->setEffectsVolume(1.0f);
SimpleAudioEngine::getInstance()->preloadEffect("music/BugDead.wav");
SimpleAudioEngine::getInstance()->preloadEffect("music/BugEnterHole.wav");
flag++;
}
4.游戏界面
PlayScene.h
#ifndef _PLAY_SCENE_H
#define _PLAY_SCENE_H
#include"cocos2d.h"
#include"SimpleAudioEngine.h"
#include<math.h>
using namespace CocosDenshion;
USING_NS_CC;
class Play : public cocos2d::Scene
{
public:
static cocos2d::Scene* createScene();
CREATE_FUNC(Play);
bool init()override;
//设置生成怪物类型
bool flag = true;
//血量
int health = 10;
//怪物随机生成
void monstergenerated(float dt);
//怪物的点击监听器
cocos2d::EventListenerTouchOneByOne listener;
//怪物点击事件
bool onTouchBegan(Touch* touch, Event* event);
void onTouchEnded(Touch* touch, Event* event);
//移除进入洞中且未被点击的精灵
void isEnterHole(float dt);
//移除死亡图像
void removeDeadSprite(float dt);
//计算旋转角度
float calculateAngel(float x, float y);
};
#endif
PlayScene.cpp
#include"PlayScene.h"
#include<string>
#include"AntSprite.h"
#include"SpiderSprite.h"
#include<time.h>
#include<vector>
using namespace std;
Scene* Play::createScene()
{
return Play::create();
}
bool Play::init()
{
if (!Scene::init())
{
return false;
}
//获取导演及屏幕尺寸
auto director = Director::getInstance();
auto size = director->getVisibleSize();
auto bgSptite = Sprite::create("PlaySceneBg.png");
bgSptite->setPosition(Vec2(size.width/2,size.height/2));
bgSptite->setTag(0);
addChild(bgSptite, -1);
//绘制血量显示
auto starSprite = Sprite::create("Star.png");
if (starSprite == nullptr)
{
log("No sunch file path");
}
else
{
starSprite->setTag(0);
starSprite->setAnchorPoint(Vec2(0,0));
starSprite->setPosition(Vec2(0,size.height-starSprite->getContentSize().height));
this->addChild(starSprite);
}
//绘制血量数值
auto healthSprite = Label::createWithTTF(to_string(health), "fonts/Marker Felt.ttf",24);
if (healthSprite == nullptr)
{
log("No such file path");
}
else
{
healthSprite->setTag(0);
healthSprite->setAnchorPoint(Vec2(0,0));
healthSprite->setPosition(starSprite->getContentSize().width,starSprite->getPosition().y+10);
this->addChild(healthSprite);
}
listener.onTouchBegan = CC_CALLBACK_2(Play::onTouchBegan, this);
listener.onTouchEnded = CC_CALLBACK_2(Play::onTouchEnded, this);
schedule(schedule_selector(Play::monstergenerated),3);
schedule(schedule_selector(Play::isEnterHole));
schedule(schedule_selector(Play::removeDeadSprite), 1);
return true;
}
//怪物生成
void Play::monstergenerated(float dt)
{
//设置随机性
int randnum = time(nullptr);
srand(randnum);
//flag==true,生成Ant
if (flag)
{
Ant* sprite = Ant::createAnt("BugAnt.png", Rect(0, 0, 240, 240));
int x = rand() % 1377 - 120;
//根据随机位置进行X坐标的修正
if (x < 120)
{
x = -120;
}
if (x > 1016)
{
x = 1256;
}
//修正X坐标后设置Y坐标并进行旋转
//精灵位于背景的左侧
if (x == -120)
{
int y = rand() % 401 + 120;
sprite->setPosition(Vec2(x, y));
float angle = calculateAngel(x, y);
if (y > 250)
{
sprite->setRotation(angle);
}
if (y < 250)
{
sprite->setRotation(-angle);
}
}
//精灵位于背景的右侧
else if (x==1256)
{
int y = rand() % 401 + 120;
sprite->setPosition(Vec2(x, y));
float angle = calculateAngel(x, y);
if (y > 250)
{
sprite->setRotation(180-angle);
}
else if (y < 250)
{
sprite->setRotation(-(180-angle));
}
else
{
sprite->setRotation(180);
}
}
//精灵位于背景的中央
else
{
//随机决定精灵位于上侧还是下侧
int direction = rand() % 2;
//位于上侧
if (direction == 0)
{
sprite->setPosition(Vec2(x, 760));
float angel = calculateAngel(x, 760);
if (x < 535)
{
sprite->setRotation(angel);
}
else if (x>535)
{
sprite->setRotation(180-angel);
}
else
{
sprite->setRotation(90);
}
}
//位于下侧
else
{
sprite->setPosition(Vec2(x,-120));
if (x < 535)
{
sprite->setRotation(-calculateAngel(x,-120));
}
else if (x>535)
{
sprite->setRotation(-(180-calculateAngel(x,-120)));
}
else
{
sprite->setRotation(-90);
}
}
}
sprite->setListener();
sprite->setTag(1);
this->addChild(sprite);
}
//flag==false,生成Spider
else
{
Spider* sprite = Spider::createSpider("BugSpider.png", Rect(0, 0, 160, 160));
int x = rand() % 1297 - 80;
if (x < 80)
{
x = -80;
}
if (x > 1056)
{
x = 1216;
}
//左侧
if (x == -80)
{
int y = rand() % 481 + 80;//y的范围为[80,560]
sprite->setPosition(Vec2(x, y));
float angle = calculateAngel(x, y);
if (y > 250)
{
sprite->setRotation(angle);
}
if (y < 250)
{
sprite->setRotation(-angle);
}
}
//右侧
else if (x == 1216)
{
int y = rand() % 481+80;
sprite->setPosition(Vec2(x, y));
float angle = calculateAngel(x, y);
if (y > 250)
{
sprite->setRotation(180 - angle);
}
else if (y < 250)
{
sprite->setRotation(-(180 - angle));
}
else
{
sprite->setRotation(180);
}
}
//上下侧
else
{
int direction = rand() % 2;
//上侧
if (direction == 0)
{
sprite->setPosition(Vec2(x, 720));
float angel = calculateAngel(x, 720);
if (x < 535)
{
sprite->setRotation(angel);
}
else if (x > 535)
{
sprite->setRotation(180 - angel);
}
else
{
sprite->setRotation(90);
}
}
//下侧
else
{
sprite->setPosition(Vec2(x, -80));
if (x < 535)
{
sprite->setRotation(-calculateAngel(x, -80));
}
else if (x > 535)
{
sprite->setRotation(-(180 - calculateAngel(x, -80)));
}
else
{
sprite->setRotation(-90);
}
}
}
sprite->setListener();
sprite->setTag(2);
this->addChild(sprite);
}
flag = !flag;
}
//触摸事件开始
bool Play::onTouchBegan(Touch* touch,Event* event)
{
auto target = static_cast<Sprite*>(event->getCurrentTarget());
auto pos = target->convertTouchToNodeSpace(touch);
//获取大小
Size size = target->getContentSize();
Rect rect = Rect(0, 0, size.width / 2, size.height / 2);
int tag=0;
if (rect.containsPoint(pos))
{
Vec2 point;
if (target)
{
point = target->getPosition();
tag = target->getTag();
}
Sprite* sprite = nullptr;
if (tag == 1)
{
sprite = Ant::createAnt("BugAnt.png", Rect(480, 0, 240, 240));
}
else
{
sprite = Spider::createSpider("BugSpider.png", Rect(320, 0, 160, 160));
}
if (sprite)
{
sprite->setScale(0.5);
sprite->setPosition(point);
this->removeChild(target);
this->addChild(sprite);
}
log("true");
return true;
}
log("false");
return false;
}
//触摸事件结束
void Play::onTouchEnded(Touch* touch, Event* event)
{
log("end");
}
//判断是否进入虫洞
void Play::isEnterHole(float dt)
{
auto spriteVector = this->getChildren();
auto length = spriteVector.size();
for (int i = 4; i < length; i++)
{
auto sprite = spriteVector.at(i);
int tag = sprite->getTag();
float x = sprite->getPositionX();
float y = sprite->getPositionY();
if (tag != 0)
{
if (tag <= 2)
{
float distance = sqrt(pow((x - 535), 2) + pow((y - 250), 2));
if (distance < 10)
{
this->removeChild(sprite);
}
else
{
if (x != 535)
{
float k = (y - 250) / (x - 535);
float b = y - k * x;
if (x > 535)
{
sprite->setPosition(x - 1, k * (x - 1) + b);
}
else
{
sprite->setPosition(x + 1, k * (x + 1) + b);
}
}
else
{
if (y > 250)
{
sprite->setPosition(x, y - 0.2);
}
else
{
sprite->setPosition(x, y + 0.2);
}
}
}
}
}
}
}
//移除怪物的死亡画面
void Play::removeDeadSprite(float dt)
{
auto spriteVector = this->getChildren();
int length = spriteVector.size();
if (length > 0)
{
for (int i = 0; i < length; i++)
{
auto sprite = spriteVector.at(i);
int tag = sprite->getTag();
if (tag > 2)
{
this->removeChild(sprite);
}
}
}
}
//计算旋转角度
float Play::calculateAngel(float x, float y)
{
//洞中心的坐标为(535,250)
if (x == 535)
{
return 0;
}
float k = fabs((y - 250.0) / (x - 535));
float angel = atan(k);
return angel*57.3;
}