[Cocos2d塔防遊戲開發]Cocos2dx-3.X完成塔防遊戲《王國保衛戰》--地圖(二)

接上文,添加地圖,在地圖層直接添加即可,我是將AnchorPoint設置在(0,0),方便計算座標

mapSprite = Sprite::createWithSpriteFrameName(String::createWithFormat("Stage_%d.png",level+1)->getCString());
mapSprite->setAnchorPoint(Point(0,0));
mapSprite->setPosition(Point(0,0));
addChild(mapSprite);

本章節主要介紹兩個固定技能和商店技能的實現


首先是兩個固定技能,以隕石爲例

首先添加按鍵圖片精靈

stoneSprite = Sprite::createWithSpriteFrameName("power_portrait_fireball_0001.png");
stoneSprite->setAnchorPoint(Point(0,0));
stoneSprite->setPosition(Point(10,-20));
stoneSprite->setName("inactive");
//判斷倒計時是否完畢
completeStone = false;
addChild(stoneSprite,1);     

然後是倒計時遮蓋層,採用的是ProgressTimer實現,放在按鍵圖片精靈上面

stoneTimer = ProgressTimer::create(Sprite::createWithSpriteFrameName("power_loading.png"));
stoneTimer->setAnchorPoint(Point(0,0));
//順時針轉動
stoneTimer->setReverseDirection(true);
stoneTimer->setPosition(Point(10,-20));
stoneTimer->setPercentage(100);//顯示原形的百分比
this->addChild(stoneTimer,1);


添加定時器,更新ProgressTimer狀態

void PlayerStateMenu::updateStoneProgress(float Dt){  
	stoneTimer->setPercentage(stoneTimer->getPercentage() - Dt*2);//更新進度2
	if (stoneTimer->getPercentage()==0) {
		this->unschedule(schedule_selector(PlayerStateMenu::updateStoneProgress));//取消定時器
		completeStone = true;
	}
	return;
}

在你想要開始的時候schedule它比如第一波敵人出現之後


添加觸摸響應

auto stoneListener = EventListenerTouchOneByOne::create();
stoneListener->onTouchBegan = [&](Touch* touch, Event* event){
		
	auto target = static_cast<Sprite*>(event->getCurrentTarget());
	Point locationInNode = target->convertTouchToNodeSpace(touch);
	Size size = target->getContentSize();
	Rect rect = Rect(0, 0, size.width, size.height);
	//若第一次點擊點擊
	if(rect.containsPoint(locationInNode)){
		//若冷卻結束
		if(completeStone == true){
			//移出其他技能觸摸監聽
			mTouchLayer->removeAllListener();
			if(stoneSprite->getName() == "inactive"){
			//設置爲點擊狀態
			stoneSprite->setSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("power_portrait_fireball_0002.png"));
			//改變狀態TAG
			stoneSprite->setName("active");
			//改變其他2個按鍵狀態
			/****
			****/
			//觸摸層設置隕石技能監聽
			mTouchLayer->setFireBallTouchShield();
		//第二次點擊,即取消
		}else{
			mTouchLayer->removeFireBallTouchShield();
			stoneSprite->setSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("power_portrait_fireball_0001.png"));
			stoneSprite->setName("inactive");
		<span style="white-space:pre">	</span>}
<span style="white-space:pre">		</span>}
		return true;
	}
		return false;  
};
stoneListener->onTouchEnded = [&](Touch* touch, Event* event){
};
//觸摸吞噬
stoneListener->setSwallowTouches(true);
_eventDispatcher->addEventListenerWithSceneGraphPriority(stoneListener,stoneSprite);

當倒計時結束的時候,將completeStone置爲true,只有此時點擊按鍵纔會觸發。

點擊技能,在觸摸層添加一個EventListenerTouchOneByOne,覆蓋整個觸摸層,此時點擊地圖時,會執行這個觸摸事件

下面來看看觸摸層


class TouchLayer :public Layer
{
public:
	virtual bool init();
    CREATE_FUNC(TouchLayer);
	EventListenerTouchOneByOne* touchlistener;
	EventListenerTouchOneByOne* FiereBalllistener;

	void setFireBallTouchShield();
	void removeFireBallTouchShield();
	bool onFireBallTouchBegan(Touch* touch, Event* event);
	void onFireBallTouchEnded(Touch* touch, Event* event);

	bool isFlag;
	bool onTouchBegan(Touch* touch, Event* event);
	void onTouchEnded(Touch* touch, Event* event);
	void onTouchMoved(Touch* touch, Event* event);
	Size winSize;
	bool isMoved;

	void removeAllListener();
};
這裏我只截取了和隕石有關以及移動地圖的部分


在BaseMap裏添加觸摸監聽層

void BaseMap::initTouchLayer()
{
	mTouchLayer = TouchLayer::create();
	mTouchLayer->setContentSize(mapSprite->getContentSize());
	mTouchLayer->setAnchorPoint(Point(0,0));
	mTouchLayer->setPosition(Point(0,0));
	addChild(mTouchLayer,99);
}

添加地圖移動時間觸摸

touchlistener = EventListenerTouchOneByOne::create();
touchlistener->onTouchBegan = CC_CALLBACK_2(TouchLayer::onTouchBegan, this);
touchlistener->onTouchEnded = CC_CALLBACK_2(TouchLayer::onTouchEnded, this);
touchlistener->onTouchMoved = CC_CALLBACK_2(TouchLayer::onTouchMoved, this);
touchlistener->setSwallowTouches(true);
_eventDispatcher->addEventListenerWithFixedPriority(touchlistener,-1);
_eventDispatcher->addEventListenerWithSceneGraphPriority(touchlistener,this);


這裏設置將FiexPriority設置爲-1爲了確保觸摸事件先與技能等其他觸摸時間觸發

void TouchLayer::onTouchEnded(Touch* touch, Event* event)
{
<span style="white-space:pre">	</span>touchlistener->setSwallowTouches(isMoved);
	isMoved = false;
}

void TouchLayer::onTouchMoved(Touch* touch, Event* event)
{
        // 計算滑動過程中的滑動增量
        auto diff = touch->getDelta(); 

		//手指移動修正,因爲手指觸摸不像鼠標觸摸那麼固定
		if(abs(diff.x) >5|| abs(diff.y) >5){
			isMoved = true;
		}
			// 得到當前bgSprite的位置
			auto currentPos = this->getParent()->getPosition();
			// 得到滑動後bgSprite應該所在的位置
			auto pos = currentPos + diff;

			//邊界控制,約束pos的位置
			pos.x = MIN(pos.x, 0);
			pos.x = MAX(pos.x, -1200 + winSize.width);
			pos.y = MIN(pos.y, 0);
			pos.y = MAX(pos.y, -1000 + winSize.height);
			// 重設地圖層位置

			this->getParent()->setPosition(pos);
}

當手指在觸摸層上移動的時候,isMoved會爲true,這是setSwallowTouches(isMoved)會將其他觸摸事件吞噬
這樣是爲了確保移動的時候經過或者移動結束的時候碰巧在某觸摸點時,不會觸發其他觸摸事件(比如說移動完手指正好在某個防禦塔上,這樣就不會彈出防禦塔升級層)
另外當移動的時候也不會觸發技能事件監聽,可以移動完再選擇技能釋放地點


void TouchLayer::setFireBallTouchShield()
{
	//調用此方法創建隕石技能觸摸時間
	FiereBalllistener = EventListenerTouchOneByOne::create();
	FiereBalllistener->onTouchBegan = CC_CALLBACK_2(TouchLayer::onFireBallTouchBegan, this);
	FiereBalllistener->onTouchEnded = CC_CALLBACK_2(TouchLayer::onFireBallTouchEnded, this);
	FiereBalllistener->setSwallowTouches(true);
	//設置比移動觸摸事件高即可
	_eventDispatcher->addEventListenerWithFixedPriority(FiereBalllistener,1);
	_eventDispatcher->addEventListenerWithSceneGraphPriority(FiereBalllistener,this);
}

void TouchLayer::removeFireBallTouchShield()
{
	//使用技能完畢去除此監聽時間
	if(FiereBalllistener!=NULL)
		_eventDispatcher->removeEventListener(FiereBalllistener);
}

bool TouchLayer::onFireBallTouchBegan(Touch* touch, Event* event)
{
	//直接返回TRUE,攔截其他時間
	return true;
}

void TouchLayer::onFireBallTouchEnded(Touch* touch, Event* event)
{
	//播放音效
	SoundManager::playFireballUnleash();
	//創建3個隕石
	auto fireBall1 = FireBall::create();
	addChild(fireBall1);
	fireBall1->shoot(static_cast<TouchLayer*>(event->getCurrentTarget())->convertTouchToNodeSpace(touch)+Point(-30,300));
	auto fireBall2 = FireBall::create();
	addChild(fireBall2);
	fireBall2->shoot(static_cast<TouchLayer*>(event->getCurrentTarget())->convertTouchToNodeSpace(touch)+Point(0,350));
	auto fireBall3 = FireBall::create();
	addChild(fireBall3);
	fireBall3->shoot(static_cast<TouchLayer*>(event->getCurrentTarget())->convertTouchToNodeSpace(touch)+Point(30,280));
	//隕石墜落之後獲取父類的玩家狀態層,調用startStone,重新開始計時並且重置ProgressTimer遮蓋層
	static_cast<BaseMap*>(this->getParent())->playerState->startStone();
	//移除此監聽事件
	removeFireBallTouchShield();
}

我實現整個技能監聽加上觸摸移動差不多就是這樣

商店技能,召喚士兵等其他技能也是同樣的思路,只是使用的技能不同罷了~其他的例如冰凍敵人、召喚士兵等將在對應的模塊中一一介紹


今天先暫時寫到這樣,還有苦逼的實習等着我去找






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章