【二】仿微信飞机大战cocos2d-x3.0rc1

发布于:2021-11-29 00:36:07

上一篇:【一】仿微信飞机大战的cocos2d-x3.0rc1


?


今天我们来完成


1,场景替换


2,游戏背景无限滚动


3,添加可以移动的我机


?


一,首先是完成后的效果展示



飞机是我大学舍长设计的。这图的效果是后面的背景自上往下无限循环,飞机可以用鼠标随意拖动,不过不能拖出屏幕之外。


?


?


二,工程目录


相对【一】的目录,我们多出了四个文件



?


三,场景替换


GameScene的两个文件,是用来承载整个我机打敌机。还记得HelloWorldScene文件中的void HelloWorld::loadingDone( Node* pNode )吗?


这就是用了替换场景的,由游戏的开始场景,替换为游戏场景,替换场景的具体代码如下:


?


void HelloWorld::loadingDone( Node* pNode )
{
auto scene = GameLayer::createScene();
TransitionCrossFade *pAnimateScene = TransitionCrossFade::create(1, scene);
Director::getInstance()->replaceScene(pAnimateScene);
}

1.我们先创建游戏场景?auto scene = GameLayer::createScene(); ?GameLayer是GameScene文件中的类


?


2.TransitionCrossFade *pAnimateScene = TransitionCrossFade::create(1, scene); 创建一个以某种形式进入的场景。在一秒内,scene以自上而下形式替换前场景。TransitionCrossFade不是自上而下。




Director::getInstance()->replaceScene(scene);直接场景替换。


这样替换场景就解决了,下面让我们说下GameScene类类文件中的实现吧。


?


四,游戏开始之后,背景图的无限循环


我们先创建GameScene.h文件


?


#ifndef __GAME_SCENE_H__
#define __GAME_SCENE_H__
#include "cocos2d.h"
#include "PlaneLayer.h"

USING_NS_CC;

enum EnBackground
{
e_BackgroundA = 1, // 背景1
e_BackgroundB = 2, // 背景2 与背景一样,只是用来循环用
};

class GameLayer : public Layer
{
public:
static cocos2d::Scene* createScene();

virtual bool init();

CREATE_FUNC(GameLayer);

public:
void backgroundMove(float dt); // 背景移动

public:
PlaneLayer *planeLayer;
};
#endif // __GAME_SCENE_H__

?


结构和HelloWorldScene.h文件差不多,可以参考HelloWorldScene文件。PlaneLayer是创建飞机layer的,等下会说,可以注释掉,先实现背景循环移动效果。


?


和HelloWorldScene一样,我们也是在GameLayer::init()函数中加入背景


?


bool GameLayer::init()
{
if (!Layer::init())
{
return false;
}

// 启动触摸机制
this->setTouchEnabled(true);

// 背景无限滚动
auto backgroundA = Sprite::create("ui/shoot_background/background.png");
backgroundA->setTag(e_BackgroundA);
backgroundA->setAnchorPoint(Point::ZERO);
backgroundA->setPosition(Point::ZERO);
this->addChild(backgroundA);

auto backgroundB = Sprite::create("ui/shoot_background/background.png");
backgroundB->setTag(e_BackgroundB);
backgroundB->setAnchorPoint(Point::ZERO);
backgroundB->setPosition(Point::ZERO);
this->addChild(backgroundB);

// 每帧都调用的函数
this->schedule(schedule_selector(GameLayer::backgroundMove));

// 加入飞机
planeLayer = PlaneLayer::create();
this->addChild(planeLayer);
}

?




?


2 backgroundA - > setTag(e_BackgroundA);设置标志,这样的话,在本场景scene中就可以通过这个标志找到这个背景精灵?


如:this- > getChildByTag(EnBackground :: e_BackgroundA);


3 backgroundA->setAnchorPoint(Point::ZERO);设置描点,就是设置物体的中心,可以查下描点的定义。


4 this->schedule(schedule_selector(GameLayer::backgroundMove));如果你想要时时检测东西,就可以用这个。它每帧都调用GameLayer::backgroundMove函数。如果你要2秒调用一次GameLayer::backgroundMove,就这样写:


this->schedule(schedule_selector(GameLayer::backgroundMove,2));


因为GameScene是主游戏场景,所以把所有的Layer元素放在进来,我机就是其中之一。不过在这里我们可以先把我机的部分屏蔽掉。等写完


PlaneLayer文件再打开。


本节最重要的部分:如何让背景无限循环~让我们实现这个每帧都被调用的GameLayer::backgroundMove


?


void GameLayer::backgroundMove(float dt)
{
Sprite *pBackgroundA = (Sprite*)this->getChildByTag(EnBackground::e_BackgroundA);
Sprite *pBackgroundB = (Sprite*)this->getChildByTag(EnBackground::e_BackgroundB);


pBackgroundA->setPositionY(pBackgroundA->getPositionY() - 2);
pBackgroundB->setPositionY(pBackgroundA->getPositionY() + pBackgroundA->getContentSize().height);
int a = pBackgroundA->getPositionY();
int b = pBackgroundB->getPositionY();
if (0 == pBackgroundB->getPositionY())
{
pBackgroundA->setPositionY(0);
}
}

?


?


通过刚才的标志,我们可以找到场景里面的背景A和背景B。backgroundMove(一帧调用一次,60帧是一秒,director->setAnimationInterval(1.0 / 60))。


我们通过资源resource路径找到ui/shoot_background/background.png图片,右键查看图片信息,发现背景图高度是842像素,背景高度每次-2,这样就可以达到0。因为一开始背景A的PositionY = 0 - 2 (图片下拉2个像素),那么背景B的PositionY = 842 +(-2)= 840(图片向上拉840像素),刚好无缝连接。还是不懂得同学,好好想一下,或者固定背景位置,看下效果就懂了。当背景B的图片位置到0了,这时候把背景A的再次设置为0,重复之前的过程。大家现在可以去试下背景无限循环的效果了~


GameScene.cpp文件代码:


?


#include "GameScene.h"

cocos2d::Scene* GameLayer::createScene()
{
auto scene = Scene::create();

auto layer = GameLayer::create();

scene->addChild(layer);

return scene;
}

bool GameLayer::init()
{
if (!Layer::init())
{
return false;
}

// 启动触摸机制
this->setTouchEnabled(true);

// 背景无限滚动
auto backgroundA = Sprite::create("ui/shoot_background/background.png");
backgroundA->setTag(e_BackgroundA);
backgroundA->setAnchorPoint(Point::ZERO);
backgroundA->setPosition(Point::ZERO);
this->addChild(backgroundA);

auto backgroundB = Sprite::create("ui/shoot_background/background.png");
backgroundB->setTag(e_BackgroundB);
backgroundB->setAnchorPoint(Point::ZERO);
backgroundB->setPosition(Point::ZERO);
this->addChild(backgroundB);

// 每帧都调用的函数
this->schedule(schedule_selector(GameLayer::backgroundMove));

// 加入飞机
planeLayer = PlaneLayer::create();
this->addChild(planeLayer);
}

void GameLayer::backgroundMove(float dt)
{
Sprite *pBackgroundA = (Sprite*)this->getChildByTag(EnBackground::e_BackgroundA);
Sprite *pBackgroundB = (Sprite*)this->getChildByTag(EnBackground::e_BackgroundB);


pBackgroundA->setPositionY(pBackgroundA->getPositionY() - 2);
pBackgroundB->setPositionY(pBackgroundA->getPositionY() + pBackgroundA->getContentSize().height);
int a = pBackgroundA->getPositionY();
int b = pBackgroundB->getPositionY();
if (0 == pBackgroundB->getPositionY())
{
pBackgroundA->setPositionY(0);
}
}

?


?


五,场景内加入可以移动的我机


老规矩看下PlaneLayer.h文件


?


#include "cocos2d.h"
USING_NS_CC;

enum Enum_Plane
{
AIRPLANE = 1,
};

class PlaneLayer : public Layer
{
public:
PlaneLayer();

~PlaneLayer();

virtual bool init();

CREATE_FUNC(PlaneLayer);

public:
void checkBorder(float dt); // 边界检测

public:
bool isAlive; // 飞机是否活着
};

?


和之前的GameScene.h文件比,少了什么呢?没错,少了static cocos2d::Scene* createScene();场景创建。因为我们的主场景就是GameScene,现在需要的是往主场景中加入Layer、sprite等等元素。因此我们只要实现layer就可以了。


?


还是那句话,老规矩?我们先在PlaneLayer::init()中加入我机:


?


// 我机
Size winSize = Director::getInstance()->getWinSize();
auto sprite = Sprite::create("ui/shoot/hero1.png");
sprite->setPosition(Point(winSize.width/2,sprite->getContentSize().height/2));
sprite->setTag(AIRPLANE);
this->addChild(sprite);

?


我方飞机的位置是底部正中央。


?


加完飞机,我们需要处理什么呢?想想~~1.可以触摸拖动~~2.不能跑到屏幕外面去~~


1,拖动实现也是在PlaneLayer::init()中实现:


?


// 我机触摸
auto listener = EventListenerTouchOneByOne::create();
listener->setSwallowTouches(true);

listener->onTouchBegan = [](Touch* touch, Event *event){
auto target = static_cast(event->getCurrentTarget());

Point locationInNode = target->convertToNodeSpace(touch->getLocation());
Size s = target->getContentSize();
Rect rect = Rect(0,0,s.width,s.height);

if (rect.containsPoint(locationInNode))
{
return true;
}
else
{
return false;
}
};

listener->onTouchMoved =[](Touch* touch, Event *event){
auto target = static_cast(event->getCurrentTarget());
target->setPosition(target->getPosition() + touch->getDelta());
};


listener->onTouchEnded = [=](Touch* touch, Event* event){
};

?


以上就是触摸机制的实现,以后有空给你们解释一下,或者你们自己看看网上资*蓗


?


之后就是把我们的飞机加入到触摸机制中去(在PlaneLayer::init()中):


?


//将触摸监听添加到eventDispacher中去
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, sprite);

?


?


2,时时检测飞机是否飞出天外天?,大家还记得这个函数吗?


?


// 每帧都调用的函数
this->schedule(schedule_selector(PlaneLayer::checkBorder));

1秒内调用60次PlaneLayer :: checkBorder。


?


?


void PlaneLayer::checkBorder( float dt )
{
//进行边界判断,不可超出屏幕
Point location = this->getChildByTag(AIRPLANE)->getPosition();
Size winSize=Director::sharedDirector()->getWinSize(); // 获取opengl视图窗口大小

Size planeSize=this->getChildByTag(AIRPLANE)->getContentSize(); // 返回的就是这个矩形的大小,只是是逻辑尺寸, 而不是像素的
if (location.x {
location.x=planeSize.width/2;
}
if (location.x>winSize.width-planeSize.width/2)
{
location.x=winSize.width-planeSize.width/2;
}
if (location.y {
location.y=planeSize.height/2;
}
if (location.y>winSize.height-planeSize.height/2)
{
location.y=winSize.height-planeSize.height/2;
}
this->getChildByTag(AIRPLANE)->setPosition(location);
}

?


这里的位置检测就是你的数学逻辑了,你可以设置下飞机的描点为0,0,看看会有什么效果,描点默认为0.5,0.5。


?


PlaneLayer.cpp文件


?


#include "PlaneLayer.h"

PlaneLayer::PlaneLayer()
{
isAlive = true;
}

PlaneLayer::~PlaneLayer()
{

}

bool PlaneLayer::init()
{
if (!Layer::init())
{
return false;
}

// 我机
Size winSize = Director::getInstance()->getWinSize();
auto sprite = Sprite::create("ui/shoot/hero1.png");
sprite->setPosition(Point(winSize.width/2,sprite->getContentSize().height/2));
sprite->setTag(AIRPLANE);
this->addChild(sprite);

// 我机触摸
auto listener = EventListenerTouchOneByOne::create();
listener->setSwallowTouches(true);

listener->onTouchBegan = [](Touch* touch, Event *event){
auto target = static_cast(event->getCurrentTarget());

Point locationInNode = target->convertToNodeSpace(touch->getLocation());
Size s = target->getContentSize();
Rect rect = Rect(0,0,s.width,s.height);

if (rect.containsPoint(locationInNode))
{
return true;
}
else
{
return false;
}
};

listener->onTouchMoved =[](Touch* touch, Event *event){
auto target = static_cast(event->getCurrentTarget());
target->setPosition(target->getPosition() + touch->getDelta());
};


listener->onTouchEnded = [=](Touch* touch, Event* event){
};

//将触摸监听添加到eventDispacher中去
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, sprite);

// 每帧都调用的函数
this->schedule(schedule_selector(PlaneLayer::checkBorder));

return true;
}

void PlaneLayer::checkBorder( float dt )
{
//进行边界判断,不可超出屏幕
Point location = this->getChildByTag(AIRPLANE)->getPosition();
Size winSize=Director::sharedDirector()->getWinSize(); // 获取opengl视图窗口大小

Size planeSize=this->getChildByTag(AIRPLANE)->getContentSize(); // 返回的就是这个矩形的大小,只是是逻辑尺寸, 而不是像素的
if (location.x {
location.x=planeSize.width/2;
}
if (location.x>winSize.width-planeSize.width/2)
{
location.x=winSize.width-planeSize.width/2;
}
if (location.y {
location.y=planeSize.height/2;
}
if (location.y>winSize.height-planeSize.height/2)
{
location.y=winSize.height-planeSize.height/2;
}
this->getChildByTag(AIRPLANE)->setPosition(location);
}

?


到这里,就拥有了一个无限循环的背景图 加 一个可以随意移动的飞机。


?


?


?


?


?


?


?


?


?


?


?

相关推荐

最新更新

猜你喜欢