基于Cocos2d-x开发guardCarrot--6 《保卫萝卜2》解锁天天向上玩法

155 阅读12分钟

解锁天天向上玩法

  我们已经创建完《保卫萝卜2》主页面上所有音频音效(链接:blog.csdn.net/qq135595696…),接下来我们实现主页面上的天天向上玩法。

  实际上,在《保卫萝卜2》主页面中,“天天向上”按钮是锁住的,如下图:

效果图

  若“天天向上”按钮是“锁住”状态,则点击“天天向上”按钮,会出现如下图所示的对话框。图中所示的功能本质是一个内购,因为内购需要接入第三方SDK,且可选的SDK数量繁多,每个平台的接入也都不一样,所以这里将这个功能简化,采用本地数据存储的方法。

效果图

  设置一个bool类型的isUpUnlock成员变量,表示是否解锁了“天天向上”,其默认值为false。此外,又添加了一个LoadConfig()函数,用来从本地磁盘配置文件中获取isUpUnlock的值,代码如下:

config.json

{
	"baseConfig":	{
		"isUpUnlock":	"false"
	}
}
std::string MainScene::configFilePath = "config.json";
void MainScene::LoadConfig()
{
	//读取json文件
	char jsonBuf[10240] = { 0 };
	int ret = readFileContents((char*)configFilePath.c_str(), jsonBuf, sizeof(jsonBuf));
	cJSON* root = nullptr;
	root = cJSON_Parse(jsonBuf);
	if (!root)
	{
		problemLoading(configFilePath.c_str());
		return;
	}

	cJSON* baseConfig = cJSON_GetObjectItem(root, "baseConfig");
	if (!baseConfig)
	{
		problemLoading(configFilePath.c_str());
		return;
	}

	cJSON* isUpUnlock = cJSON_GetObjectItem(baseConfig, "isUpUnlock");
	if (!isUpUnlock)
	{
		problemLoading(configFilePath.c_str());
		return;
	}
	_isUpUnlock = strcmp(isUpUnlock->valuestring, "false") == 0 ? false : true;
}

  在最后一行代码中我们通过比较字符串获取“是否已经解锁”的值。然后我们通过everyDayBtnLocked来管理锁这个精灵,这样我们可以在后面解锁“天天向上”时,通过调用removeFromParent()函数来讲锁从当前场景中移除掉。接着在“天天向上”按钮的点击事件中,键入如下代码:

_everyDayBtn->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type) {
		switch (type)
		{
		case ui::Widget::TouchEventType::BEGAN:
		{
			SimpleAudioEngine::getInstance()->playEffect("Sound/MainMenu/Unlock.mp3", false, 1.0f, 1.0f, 1.0f);

			//添加如下代码
			if (false == _isUpUnlock)
			{
				//打开解锁面板(创建自定义事件并手动分发)
				EventCustom event(OPENUNCLOCKUPLAYER);
				event.setUserData("OPENUNCLOCKUPLAYER trigger");
				_eventDispatcher->dispatchEvent(&event);
			}
			else
				log("TODO:Implement the function of the \"Everyday\" button");
			break;
		}
		case ui::Widget::TouchEventType::ENDED:
			log("_everyDayBtn ENDERD");
			break;
		default:
			break;
		}
		});

  在上述的代码中,if语句主要是用于判断“天天向上”是否已经解锁了,若未解锁,则分发一个“打开解锁面板”的事件。很显然,时间的设计是发布者/订阅者的设计模式(观察者模式)。那么,我们在MainMenuScene场景中实现“打开解锁面板”的事件监听。当“打开解锁面板”的事件被触发的时候,MainMenuScene便会接收到这一事件,从而做“打开解锁面板”的处理,代码如下:

	//创建“打开解锁面板”事件的监听器
	_openUnlockUpLayer = EventListenerCustom::create(OPENUNCLOCKUPLAYER, [](EventCustom* event) {
		//获取活动的当前目标(获取当前事件监听器的事件源)
		auto target = event->getCurrentTarget();
		target->addChild(UnlockLayer::create(), 10);
		log(static_cast<char*>(event->getUserData()));
		});
	//对“打开解锁面板”事件进行监听
	_eventDispatcher->addEventListenerWithSceneGraphPriority(_openUnlockUpLayer, this);

  其中OPENUNCLOCKUPLAYER是一个宏,在MainMenuScene.cpp的开头就进行了定义。

#define OPENUNCLOCKUPLAYER "OPENUNCLOCKUPLAYER"

  当名字为OPENUNCLOCKUPLAYER的自定义事件被触发的时候,MainMenuScene会创建UnlockLayer层,从而创建出“解锁天天向上”对话框,并将其添加到当前场景中。

  UnlockLayer是一个LayerColor(也可以说是UnlockLayer类其继承的父类),其颜色为黑色,不透明度为220,这样可以“高亮突出”当前层里面的内容。UnlockLayer里的内容是一个对话框,很显然,它属于UI控件。

  关于UnlockLayer,首先,我们直接创建UnlockLayer.h和UnlockLayer.cpp来实现解锁界面,同时使用它来存放我们所需的UI控制,代码如下:

bool UnlockLayer::init()
{
	//初始颜色为黑色,不透明度220
	if (!LayerColor::initWithColor(Color4B(0, 0, 0, 220)))return false;
    this->setContentSize(Director::getInstance()->getVisibleSize());

	//背景layer添加触摸事件,吞噬掉在该layer之上的UI触摸事件,使得MainScene场景中的“天天向上”和“开始冒险”不会被点击
	_swallowlistener = EventListenerTouchOneByOne::create();
	_swallowlistener->setSwallowTouches(true);
	_swallowlistener->onTouchBegan = [](Touch* touch, Event* event) {
		log("Swallow Event");
		//必须返回true,否则依然无法吞噬触摸事件
		return true;
	};
	_eventDispatcher->addEventListenerWithSceneGraphPriority(_swallowlistener, this);
	return true;
}

  我们首先将UnlockLayer类的大小设置为getVisibleSize的大小。然后我们开启触发事件,这样做是为了“吞噬”掉UI的触摸事件,使得MainScene中的“开始冒险”和“天天向上”按钮不会被点击到。

  接着,又定义一个精灵来创建如下如所示的背景图片,代码如下:

效果图

	auto woodbgPinfo = AutoPolygon::generatePolygon("Common/bg/woodbg_notice.png");
	Sprite* woodbgSprite = Sprite::create(woodbgPinfo);
	this->addChild(woodbgSprite);
	woodbgSprite->setPosition(Director::getInstance()->getVisibleSize() / 2);

  将背景添加到UnlockLayer中,因为这是一个UI模块。且后面的UI控件我们都使用woodbgSprite作为父节点。

  接下来是包括锁、解锁所需的价钱,文本提示、确定/取消按钮等添加到UnlockLayer中,源码如下:

	Sprite* unlockFloorSprite = Sprite::create("MainMenu/unlock_floor.png");
	woodbgSprite->addChild(unlockFloorSprite);
	unlockFloorSprite->setPosition(woodbgSprite->getContentSize().width / 2, woodbgSprite->getContentSize().height / 2 + 120);

	_confirmBtn = Button::create("UI/btn_blue_m.png", "UI/btn_blue_m_pressed.png", "");
	_confirmBtn->setPosition(Vec2(woodbgSprite->getContentSize().width / 2 - _confirmBtn->getContentSize().width / 2, 150));
	woodbgSprite->addChild(_confirmBtn);

	Sprite* confirmPic = Sprite::create("UI/zh/btn_blue_m_ok.png");
	_confirmBtn->addChild(confirmPic);
	confirmPic->setPosition(_confirmBtn->getContentSize() / 2);


	_cancelBtn = Button::create("UI/btn_green_m.png", "UI/btn_green_m_pressed.png", "");
	_cancelBtn->setPosition(Vec2(woodbgSprite->getContentSize().width - _confirmBtn->getContentSize().width, 150));
	woodbgSprite->addChild(_cancelBtn);

	Sprite* cancelPic = Sprite::create("UI/zh/btn_green_m_cancel.png");
	_cancelBtn->addChild(cancelPic);
	cancelPic->setPosition(_cancelBtn->getContentSize() / 2);

  以下是按钮的触摸事件机制的实现,由于UI控件又自己的一套触摸事件机制,并不需要我们给每个控件添加事件监听器,源码如下:

//自定义事件
#define UNLOCKUP "UNLOCKUP"
//发布消息
#define UNLOCKUPNOTICE "UNLOCKUPNOTICE"
void UnlockLayer::InitEvent()
{
	//确定事件
	_confirmBtn->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type) {
		switch (type)
		{
		case cocos2d::ui::Widget::TouchEventType::BEGAN:
			log("confirmBtn Began Touch");
			break;
		case cocos2d::ui::Widget::TouchEventType::ENDED:
		{
			EventCustom event(UNLOCKUP);
			event.setUserData("true");
			_eventDispatcher->dispatchEvent(&event);
            //给UNLOCKUPNOTICE的观察者发送通知消息
			NotificationCenter::sharedNotificationCenter()->postNotification(UNLOCKUPNOTICE, (CCObject*)"true");
			this->removeFromParent();
			break;
		}
		default:
			break;
		}
		});


	//解锁逻辑的自定义事件
	_unlockUpListener = EventListenerCustom::create(UNLOCKUP, [](EventCustom* event) {
		log(static_cast<char*>(event->getUserData()));
		if (strcmp("true", static_cast<char*>(event->getUserData())) == 0)
		{
			char jsonBuf[10240] = { 0 };
			int ret = readFileContents("config.json", jsonBuf, sizeof(jsonBuf));
			cJSON* root = nullptr;
			root = cJSON_Parse(jsonBuf);
			if (!root)
				return;
			cJSON* baseConfig = cJSON_GetObjectItem(root, "baseConfig");
			if (!baseConfig)
				return;
			changeStringValueByKey(baseConfig, "isUpUnlock", "true");
			writeJson2File(root, "config.json");
		}
		});
	_eventDispatcher->addEventListenerWithSceneGraphPriority(_unlockUpListener, _confirmBtn);


	//取消事件
	_cancelBtn->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type) {
		switch (type)
		{
		case cocos2d::ui::Widget::TouchEventType::BEGAN:
			log("cancelBtn Began Touch");
			break;
		case cocos2d::ui::Widget::TouchEventType::ENDED:
			this->removeFromParent();
			break;
		default:
			break;
		}
		});
}

  代码中给“确定”和“取消”按钮添加了触摸事件,在“确定”按钮中,当我们触摸抬起的时候,分发了一个”天天向上解锁“的事件,事件携带着”解锁成功“的数据。同时cocos2d-x框架中内置的观察者模式封装了一个NotificationCenter单例类,也被称为消息通知中心。可以在开发的时候用于层与层之间或场景之间进行数据的消息的传递。以下是一些常用的API接口:

 NotificationCenter ()
 ~NotificationCenter ()

void    addObserver (CCObject *target, SEL_CallFuncO selector, const char *name, CCObject *obj)

void    removeObserver (CCObject *target, const char *name)

int     removeAllObservers (CCObject *target)

void    postNotification (const char *name)

void    postNotification (const char *name, CCObject *object)

  NotificationCente的实现机制是 一个对象通过addObserver注册观察者,并通过消息名称(const char *name)对目标进行监测,当目标对象状态发生变化时,即目标对象通过postNotification发送消息,注册为观察者的对象便做出相应反应。目标对象可以通过postNotification发送带数据的消息和不带数据的消息。层或者场景之间便可通过postNotification发送带数据的消息进行传递消息和数据。

  最后执行了从父结点删除当前层的操作。

  很显然,若”天天向上“解锁成功,则主页面中”天天向上“菜单项中的锁就应该移除掉,所以应该在UnlockLayer层中实现”天天向上解锁“的事件监听,即_unlockUpListener事件监听器,其实现主要是通过更改config.json文件中的isUpUnlock属性(将其值为true)来实现数据持久化。关于如何解析json数据并对其进行更改,可以参考文章:blog.csdn.net/qq135595696…

  最后附上UnlockLayer.h以及MainScene.h、MainScene.cpp部分完整代码以及最终实现效果:

  UnlockLayer.h

#pragma once
#include "cocos2d.h"
#include "ui/CocosGUI.h"

class UnlockLayer :public cocos2d::LayerColor
{
public:
	CREATE_FUNC(UnlockLayer);

	virtual bool init();

private:
	void InitUI();

	void InitEvent();

private:
	cocos2d::Layer* _backgroundLayer;

	cocos2d::EventListenerCustom* _unlockUpListener;
	
	cocos2d::EventListenerTouchOneByOne* _swallowlistener;

	cocos2d::ui::Button* _confirmBtn;
	cocos2d::ui::Button* _cancelBtn;
};

  MainScene.h

#pragma once
#include "cocos2d.h"
#include "ui/CocosGUI.h"
#include <string.h>

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

	virtual bool init();

	CREATE_FUNC(MainScene);

	~MainScene();
private:
	void InitSprite(cocos2d::Sprite*& outSprite, cocos2d::Node* parentNode, const std::string& fileName, float x, float y, int localZOrder);

	bool InitUI();

	bool InitUIAnimation();

	void LoadConfig();

	void InitEvent();

	void GetUnlockLayterMsg(cocos2d::CCObject* obj);

private:
	static float actionDuration;
	cocos2d::Sprite* _monster1;
	cocos2d::Sprite* _monster2;
	cocos2d::Sprite* _monster3;
	cocos2d::Sprite* _monster4;
	cocos2d::Sprite* _monster5;
	cocos2d::Sprite* _monster6;
	cocos2d::Sprite* _monster6Hand;
	cocos2d::Sprite* _carrot;
	
	//按钮事件
	cocos2d::ui::Button* _startGameBtn;
	cocos2d::ui::Button* _everyDayBtn;
	cocos2d::Sprite* _everyDayBtnLocked;

	//是否解锁“天天向上”,默认为false
	bool _isUpUnlock;
	static std::string configFilePath;


	cocos2d::EventListenerCustom* _openUnlockUpLayerListener;

};

  MainScene.cpp

#include "MainScene.h"
#include "SimpleAudioEngine.h"
#include "cJsonFile.h"
#include "UnlockLayer.h"

//自定义事件
#define OPENUNCLOCKUPLAYER "OPENUNCLOCKUPLAYER"
//监听消息体
#define UNLOCKUPNOTICE "UNLOCKUPNOTICE"

USING_NS_CC;
using namespace cocos2d::ui;
using namespace CocosDenshion;

float MainScene::actionDuration = 1.0f;
std::string MainScene::configFilePath = "config.json";

cocos2d::Scene* MainScene::createScene()
{
	//加载背景音乐
	auto mainAudio = SimpleAudioEngine::getInstance();
	mainAudio->playBackgroundMusic("Sound/MainMenu/BGMusic.mp3", true);
	return MainScene::create();
}

static void problemLoading(const char* filename)
{
	printf("Error while loading:%s\n", filename);
	printf("Depending on how you compiled you might have to add 'Resources/' in front of filenames in MainScene.cpp\n");
}


MainScene::~MainScene()
{
	//一般要在接受通知的一方在接受完通知后需要remove监听
	NotificationCenter::sharedNotificationCenter()->removeObserver(this, "unlockUp");
}

void MainScene::InitSprite(cocos2d::Sprite*& outSprite, cocos2d::Node* parentNode, const std::string& fileName, float x, float y, int localZOrder)
{
	if (fileName == "MainMenu/front_front.png" || fileName == "MainMenu/front_smoke_3.png" || fileName == "MainMenu/front_smoke_1.png")
		outSprite = Sprite::create(fileName);
	else
	{
		auto pinfo = AutoPolygon::generatePolygon(fileName);
		outSprite = Sprite::create(pinfo);
	}
	if (nullptr == outSprite)
	{
		outSprite = nullptr;
		problemLoading(fileName.c_str());
		return;
	}
	outSprite->setPosition(Vec2(x, y));
	parentNode->addChild(outSprite, localZOrder);
}

bool MainScene::InitUI()
{
	auto visibleSize = Director::getInstance()->getVisibleSize();
	Vec2 origin = Director::getInstance()->getVisibleOrigin();

	//背景
	Sprite* rootNode = nullptr;
	InitSprite(rootNode, this, "MainMenu/zh/front_bg.png", origin.x + visibleSize.width / 2, origin.y + visibleSize.height / 2, -1);
	if (nullptr == rootNode)
		return false;

	//前置背景
	Sprite* frontNode = nullptr;
	InitSprite(frontNode, this, "MainMenu/front_front.png", origin.x + visibleSize.width / 2, origin.y + visibleSize.height / 2, 3);
	if (nullptr == frontNode)
		return false;

	//开始冒险按钮
	_startGameBtn = Button::create("MainMenu/zh/front_btn_start_normal.png", "MainMenu/zh/front_btn_start_pressed.png", "null.png");
	if (nullptr == _startGameBtn)
		problemLoading("MainMenu/zh/front_btn_start_normal.png||MainMenu/zh/front_btn_start_pressed.png");
	else
	{
		_startGameBtn->setPosition(Vec2(origin.x + 562, origin.y + 384));
		this->addChild(_startGameBtn, 1);
	}

	//天天向上按钮
	_everyDayBtn = Button::create("MainMenu/zh/front_btn_floor_normal.png", "MainMenu/zh/front_btn_floor_pressed.png", "null.png");
	if (nullptr == _everyDayBtn)
		problemLoading("MainMenu/zh/front_btn_floor_normal.png||MainMenu/zh/front_btn_floor_pressed.png");
	else
	{
		_everyDayBtn->setPosition(Vec2(origin.x + 563, origin.y + 261));
		this->addChild(_everyDayBtn, 1);
	}

	//锁
	if (false == _isUpUnlock)
	{
		_everyDayBtnLocked = nullptr;
		InitSprite(_everyDayBtnLocked, _everyDayBtn, "MainMenu/front_btn_floor_locked.png", _everyDayBtn->getSize().width, _everyDayBtn->getSize().height / 2, 1);
		if (nullptr == _everyDayBtnLocked)
			return false;
	}
	

	//Monster4
	_monster4 = nullptr;
	InitSprite(_monster4, this, "MainMenu/front_monster_4.png", origin.x + 227, origin.y + 475, 1);
	if (nullptr == _monster4)
		return false;
	_monster4->setScale(0.75);

	//设置按钮
	auto setUpBtn = Button::create("MainMenu/front_btn_setting_normal.png", "MainMenu/front_btn_setting_pressed.png", "null.png");
	if (nullptr == setUpBtn)
		problemLoading("MainMenu/front_btn_setting_normal.png||MainMenu/front_btn_setting_pressed.png");
	else
	{
		_monster4->addChild(setUpBtn, 1);
		setUpBtn->setPosition(Vec2(176, 89));
	}

	//保卫的萝卜
	_carrot = nullptr;
	InitSprite(_carrot, this, "MainMenu/front_carrot.png", origin.x + 920, origin.y + 90, 2);//起始坐标
	//origin.x + 960, origin.y + 50 //控制起始坐标
	//origin.x + 700, origin.y + 0 //控制结束坐标
	//origin.x + 620, origin.y + 14 //终点坐标
	if (nullptr == _carrot)
		return false;
	_carrot->setScale(0.45);

	//Monster6
	_monster6 = nullptr;
	InitSprite(_monster6, this, "MainMenu/front_monster_6.png", origin.x + 995, origin.y + 248, 1);
	if (nullptr == _monster6)
		return false;
	_monster6->setScale(0.75);
	//Monster6Hand
	_monster6Hand = nullptr;
	InitSprite(_monster6Hand, this, "MainMenu/front_monster_6_hand.png", origin.x + 894, origin.y + 256, -1);
	if (nullptr == _monster6Hand)
		return false;
	_monster6Hand->setScale(0.75);

	//答疑按钮
	auto confuseBtn = Button::create("MainMenu/front_btn_help_normal.png", "MainMenu/front_btn_help_pressed.png", "null.png");
	if (nullptr == confuseBtn)
		problemLoading("MainMenu/front_btn_help_normal.png||MainMenu/front_btn_help_pressed.png");
	else
	{
		_monster6Hand->addChild(confuseBtn, 0);
		confuseBtn->setPosition(Vec2(170, 405));
	}


	//Monster5
	_monster5 = nullptr;
	InitSprite(_monster5, this, "MainMenu/front_monster_5.png", origin.x + 882, origin.y + 155, 1);
	if (nullptr == _monster5)
		return false;
	_monster5->setScale(0.75);


	//烟雾2
	Sprite* smoke2 = nullptr;
	InitSprite(smoke2, this, "MainMenu/front_smoke_3.png", origin.x + 1020, origin.y + 165, 1);
	if (nullptr == smoke2)
		return false;


	//Monster3
	_monster3 = nullptr;
	InitSprite(_monster3, this, "MainMenu/front_monster_3.png", origin.x + 160, origin.y + 190, 1);
	if (nullptr == _monster3)
		return false;
	_monster3->setScale(0.75);


	//Monste1
	_monster1 = nullptr;
	InitSprite(_monster1, this, "MainMenu/front_monster_1.png", origin.x + 230, origin.y + 155, 1);
	if (nullptr == _monster1)
		return false;
	_monster1->setScale(0.85);


	//烟雾1
	Sprite* smoke1 = nullptr;
	InitSprite(smoke1, this, "MainMenu/front_smoke_1.png", origin.x + 120, origin.y + 170, 1);
	if (nullptr == smoke1)
		return false;

	return true;
}

bool MainScene::InitUIAnimation()
{
	//1号和5号怪物动作
	auto monster15MoveBy1 = MoveBy::create(actionDuration * 2, Vec2(7, 0));
	auto monster15MoveBy2 = MoveBy::create(actionDuration * 2, Vec2(-7, 0));
	auto monster15Seq = Sequence::create(monster15MoveBy1, monster15MoveBy2, nullptr);
	_monster1->runAction(RepeatForever::create(monster15Seq));
	_monster5->runAction(RepeatForever::create(monster15Seq->clone()));


	//3号、4号和6号怪物(以及其手臂)动作
	auto monster346MoveBy1 = MoveBy::create(actionDuration * 2, Vec2(0, 7));
	auto monster346MoveBy2 = MoveBy::create(actionDuration * 2, Vec2(0, -7));
	auto monster346Seq = Sequence::create(monster346MoveBy1, monster346MoveBy2, nullptr);
	_monster3->runAction(RepeatForever::create(monster346Seq));
	_monster4->runAction(RepeatForever::create(monster346Seq->clone()));
	_monster6->runAction(RepeatForever::create(monster346Seq->clone()));
	_monster6Hand->runAction(RepeatForever::create(monster346Seq->clone()));


	//Monster2初始化及2号怪物动作
	_monster2 = Sprite::create(AutoPolygon::generatePolygon("MainMenu/front_monster_2.png"));
	if (nullptr == _monster2)
	{
		problemLoading("MainMenu/front_monster_2.png");
		return false;
	}
	_monster2->setScale(0.75);
	this->addChild(_monster2, 1);
	auto monster2MoveTo = MoveTo::create(actionDuration * 0.5, Vec2(Director::getInstance()->getVisibleOrigin().x + 342, Director::getInstance()->getVisibleOrigin().y + 140));
	auto monster2Seq = Sequence::create(monster2MoveTo, CallFunc::create([&]() {
		auto monster2MoveBy1 = MoveBy::create(actionDuration * 0.55, Vec2(0, 7));
		auto monster2MoveBy2 = MoveBy::create(actionDuration * 0.55, Vec2(0, -7));
		auto monsterSeq = Sequence::create(monster2MoveBy1, monster2MoveBy2, nullptr);
		_monster2->runAction(RepeatForever::create(monsterSeq));
		}), nullptr);
	_monster2->runAction(monster2Seq);


	//萝卜动作(贝塞尔曲线+缩放并行,即贝塞尔曲线加缩放并行运动)
	ccBezierConfig controlPointTo;
	controlPointTo.controlPoint_1.set(Director::getInstance()->getVisibleOrigin().x + 960, Director::getInstance()->getVisibleOrigin().y + 50);
	controlPointTo.controlPoint_2.set(Director::getInstance()->getVisibleOrigin().x + 700, Director::getInstance()->getVisibleOrigin().y + 0);
	controlPointTo.endPosition.set(Director::getInstance()->getVisibleOrigin().x + 620, Director::getInstance()->getVisibleOrigin().y + 14);
	auto carrotBezierTo = BezierTo::create(actionDuration * 0.5, controlPointTo);
	auto carrotScaleTo = ScaleTo::create(actionDuration * 0.5, 0.75);
	auto carrotSpawn = Spawn::createWithTwoActions(carrotBezierTo, carrotScaleTo);
	_carrot->runAction(carrotSpawn);
	return true;
}

void MainScene::LoadConfig()
{
	//读取json文件
	char jsonBuf[10240] = { 0 };
	int ret = readFileContents((char*)configFilePath.c_str(), jsonBuf, sizeof(jsonBuf));
	cJSON* root = nullptr;
	root = cJSON_Parse(jsonBuf);
	if (!root)
	{
		problemLoading(configFilePath.c_str());
		return;
	}

	cJSON* baseConfig = cJSON_GetObjectItem(root, "baseConfig");
	if (!baseConfig)
	{
		problemLoading(configFilePath.c_str());
		return;
	}

	cJSON* isUpUnlock = cJSON_GetObjectItem(baseConfig, "isUpUnlock");
	if (!isUpUnlock)
	{
		problemLoading(configFilePath.c_str());
		return;
	}
	_isUpUnlock = strcmp(isUpUnlock->valuestring, "false") == 0 ? false : true;
}

void MainScene::InitEvent()
{
	//初始化“开始冒险”和“天天向上”按钮事件
	_startGameBtn->addTouchEventListener([](Ref* sender, Widget::TouchEventType type) {
		switch (type)
		{
		case ui::Widget::TouchEventType::BEGAN:
		{
			SimpleAudioEngine::getInstance()->playEffect("Sound/MainMenu/Select.mp3", false, 1.0f, 1.0f, 1.0f);
			break;
		}
		case ui::Widget::TouchEventType::ENDED:
			log("_startGameBtn ENDERD");
			break;
		default:
			break;
		}
		});

	_everyDayBtn->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type) {
		switch (type)
		{
		case ui::Widget::TouchEventType::BEGAN:
		{
			SimpleAudioEngine::getInstance()->playEffect("Sound/MainMenu/Unlock.mp3", false, 1.0f, 1.0f, 1.0f);
			if (false == _isUpUnlock)
			{
				//打开解锁面板(创建自定义事件并手动分发)
				EventCustom event(OPENUNCLOCKUPLAYER);
				event.setUserData("OPENUNCLOCKUPLAYER trigger");
				_eventDispatcher->dispatchEvent(&event);
			}
			else
				log("TODO:Implement the function of the \"Everyday\" button");
			break;
		}
		case ui::Widget::TouchEventType::ENDED:
			log("_everyDayBtn ENDERD");
			break;
		default:
			break;
		}
		});



}

bool MainScene::init()
{
	if (!Scene::init())
		return false;

	//初始化基础配置
	LoadConfig();

	//UI初始化
	if (!InitUI())
		return false;

	//初始化主页面动画
	if (!InitUIAnimation())
		return false;

	//初始化事件
	InitEvent();

	

	//创建“打开解锁面板”事件的监听器
	_openUnlockUpLayerListener = EventListenerCustom::create(OPENUNCLOCKUPLAYER, [](EventCustom* event) {
		//获取活动的当前目标(获取当前事件监听器的事件源)
		auto target = event->getCurrentTarget();
		target->addChild(UnlockLayer::create(), 10);
		log(static_cast<char*>(event->getUserData()));
		});
	//对“打开解锁面板”事件进行监听
	_eventDispatcher->addEventListenerWithSceneGraphPriority(_openUnlockUpLayerListener, this);

	//注意GetUnlockLayterMsg所属于的类,即MainScene一定要加上,否则报错
	NotificationCenter::sharedNotificationCenter()->addObserver(this, callfuncO_selector(MainScene::GetUnlockLayterMsg), UNLOCKUPNOTICE, nullptr);
	return true;
}

void MainScene::GetUnlockLayterMsg(CCObject* obj)
{
	log("unlockUp: %s", (char*)obj);
	if (strcmp("true", (char*)obj) == 0)
	{
		log("remove success");
		_everyDayBtnLocked->removeFromParent();
		_isUpUnlock = true;
	}
}

实现效果展示

  至此,”天天向上“玩法功能开发完毕。运行项目,点击”天天向上“按钮,在弹出的对话框中点击”确定“按钮,便可解锁成功。当关闭游戏之后,第二次在启动游戏时,会发展”天天向上“菜单按钮上并不会出现锁了。

基于Cocos2d-x开发guardCarrot--6 《保卫萝卜2》解锁天天向上玩法_cocos2d保卫萝卜教程_ufgnix0802的博客-CSDN博客(ufgnix0802.blog.csdn.net/article/det…)

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 8 天,   点击查看活动详情****