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

时间:2023-02-07 18:30:27

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

今天我们来完成

1,场景替换

2,游戏背景无限滚动

3,添加可以移动的我机


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

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

飞机是我的一个好基友画的,不过他画的飞机居然没有喷火特效的,估计他的智商也就到这了~哈哈~,这图的效果是后面的背景自上往下无限循环,飞机可以用鼠标随意拖动,不过不能拖出屏幕之外。


二,工程目录

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

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


三,场景替换

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不是自上而下,我忘记是什么了,你们自己运行看看。
3.Director::getInstance()->replaceScene(pAnimateScene); 导演要求场景切换。如果你不想以某种形式切换场景,那就用

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);
}


1  this->setTouchEnabled(true);触摸机制在编译成的apk文件后,可以实现手指触屏。

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<Sprite*>(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<Sprite*>(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<planeSize.width/2)  
	{  
		location.x=planeSize.width/2;  
	}  
	if (location.x>winSize.width-planeSize.width/2)  
	{  
		location.x=winSize.width-planeSize.width/2;  
	}  
	if (location.y<planeSize.height/2)  
	{  
		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<Sprite*>(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<Sprite*>(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<planeSize.width/2)  
	{  
		location.x=planeSize.width/2;  
	}  
	if (location.x>winSize.width-planeSize.width/2)  
	{  
		location.x=winSize.width-planeSize.width/2;  
	}  
	if (location.y<planeSize.height/2)  
	{  
		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);  
}

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