Cocos2dx游戏教程(十二):“见缝插针”,游戏结算界面和音效

前面游戏主场景已经可以试玩了吧,但是是不是感觉很单调呢,如何进入下一关呢?要不要配置些音乐呢,在我的BGM中是不是有些无敌的感觉呢

在这里插入图片描述
首先我们来看一下需要添加的文件
在这里插入图片描述
我们可以看到,在这一节新增了GameFailedLayer,GameSuccessLayer,GameMusic,GameLevel四个类。
我们都知道如何创建一个层,我们首先来看一下胜利失败的界面吧
在这里插入图片描述在这里插入图片描述
下面带领大家看看下如何实现界面

一、创建结算层

1、胜利层
头文件GameSuccessLayer.h

#pragma once
#include "cocos2d.h"

USING_NS_CC;

extern LanguageType type;

class GameSuccessLayer :public cocos2d::Layer{
public:
	CREATE_FUNC(GameSuccessLayer);
	virtual bool init();
public:
	//胜利对话框
	void initWinLayer();
public:
	//返回开始菜单
	void onReturnToMenuSceneBtnPressed(Ref* pSender);
	//返回选关
	void onReturnToSelectSceneBtnPressed(Ref* pSender);
	//分享
	void onShareBtnPressed(Ref* pSender);
	//下一关按钮回调
	void onNextLevelBtnPressed(cocos2d::Ref *pSender);
};

类文件 GameSuccessLayer.cpp

#include "GameSuccessLayer.h"
#include "GameLevelScene.h"
#include "Defines.h"
#include "GameMenuScene.h"
#include "GameScene.h"
#include "GameDataManage.h"
#include "GlobalManage.h"


bool GameSuccessLayer::init() {
	if(!Layer::init()) { 
		return false;
	}
	
	//胜利对话框
	initWinLayer();

	return true;
}

//胜利对话框
void GameSuccessLayer::initWinLayer() {
	//大背景
	auto bg = Sprite::create("scene/bg.jpg");
	bg->setPosition(WINSIZE / 2);
	this->addChild(bg);

	//过关背景
	auto bg2 = Sprite::create("win_or_lose/success.png");
	bg2->setPosition(Vec2(WINSIZE / 2));
	this->addChild(bg2, 1);

	//过关光效
	auto light = Sprite::create("win_or_lose/success_light.png");
	light->setPosition(Vec2(WINSIZE.width / 2, WINSIZE.height / 2 + bg2->getContentSize().height / 2 + light->getContentSize().height / 2 - 130));
	this->addChild(light);

	//过关文字
	auto title = Sprite::create("win_or_lose/success_title.png");
	title->setPosition(Vec2(WINSIZE.width / 2 - 30, WINSIZE.height / 2 + bg2->getContentSize().height / 2 + title->getContentSize().height / 2 - 30));
	this->addChild(title);

	//关卡
	auto level = Sprite::create("scene/level.png");
	level->setPosition(bg2->getContentSize().width / 2, 280);
	bg2->addChild(level);

	//关卡数
	auto levelTTF = Label::createWithCharMap("fonts/label/label_level_1.png", 31, 42, '0');
	levelTTF->setString(StringUtils::format("%d", GlobalManage::getInstance()->currentLevel));
	levelTTF->setPosition(level->getContentSize() / 2);
	level->addChild(levelTTF);

	//按钮
	auto selectItem = MenuItemImage::create("win_or_lose/select.png", "win_or_lose/select.png");
	selectItem->initWithCallback(CC_CALLBACK_1(GameSuccessLayer::onReturnToSelectSceneBtnPressed, this));
	selectItem->setPosition(Vec2(200, 146));

	auto nextItem = MenuItemImage::create("win_or_lose/next.png", "win_or_lose/next.png");
	nextItem->initWithCallback(CC_CALLBACK_1(GameSuccessLayer::onNextLevelBtnPressed, this));
	nextItem->setPosition(Vec2(520, 146));

	auto menu = Menu::create(selectItem, nextItem, NULL);
	menu->setPosition(Vec2::ZERO);
	bg2->addChild(menu);
}

//返回开始菜单
void GameSuccessLayer::onReturnToMenuSceneBtnPressed(Ref* pSender) {
	GameDataManage::getInstance()->setCurrentMaxLevel(GlobalManage::getInstance()->currentLevel + 1);
	Director::getInstance()->replaceScene(GameMenuScene::createScene());
}

//返回选关
void GameSuccessLayer::onReturnToSelectSceneBtnPressed(Ref* pSender) {
	Director::getInstance()->replaceScene(GameLevelScene::createScene());
}

//分享
void GameSuccessLayer::onShareBtnPressed(Ref* pSender) {
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
#endif
}

//重新开始
void GameSuccessLayer::onNextLevelBtnPressed(Ref* pSender) {
	if(GlobalManage::getInstance()->currentLevel >= GameDataManage::getInstance()->totalRow) {
		//跳转到主菜单界面
		Director::getInstance()->replaceScene(GameMenuScene::createScene());
	} else {
		GameDataManage::getInstance()->setCurrentMaxLevel(GlobalManage::getInstance()->currentLevel + 1);
		GlobalManage::getInstance()->currentLevel = GlobalManage::getInstance()->currentLevel + 1;
		//初始化下一关
		GameDataManage::getInstance()->loadGameData(GlobalManage::getInstance()->currentLevel);
		Director::getInstance()->replaceScene(GameScene::createScene());
	}
}

2、失败层
头文件GameFailedLayer.h

#pragma once
#include "cocos2d.h"

USING_NS_CC;

extern LanguageType type;

class GameFailedLayer :public cocos2d::Layer{
public:
	CREATE_FUNC(GameFailedLayer);
	virtual bool init();
public:
	//胜利对话框
	void initFailedLayer();
public:
	//返回开始菜单
	void onReturnToMenuSceneBtnPressed(Ref* pSender);
	//返回选关
	void onReturnToSelectSceneBtnPressed(Ref* pSender);
	//分享
	void onShareBtnPressed(Ref* pSender);
	//重新开始
	void onRestartBtnPressed(Ref* pSender);
};

类文件GameFailedLayer.cpp

#include "GameFailedLayer.h"
#include "GameLevelScene.h"
#include "Defines.h"
#include "GameMenuScene.h"
#include "GameScene.h"
#include "GlobalManage.h"

bool GameFailedLayer::init() {
	if(!Layer::init()) { 
		return false;
	}
	
	//失败对话框
	initFailedLayer();

	return true;
}

//胜利对话框
void GameFailedLayer::initFailedLayer() {
	//背景
	auto bg = Sprite::create("scene/bg.jpg");
	bg->setPosition(WINSIZE / 2);
	this->addChild(bg);

	//过关背景
	auto bg2 = Sprite::create("win_or_lose/failed.png");
	bg2->setPosition(Vec2(WINSIZE / 2));
	this->addChild(bg2, 1);

	//过关光效
	auto light = Sprite::create("win_or_lose/failed_light.png");
	light->setPosition(Vec2(WINSIZE.width / 2, WINSIZE.height / 2 + bg2->getContentSize().height / 2 + light->getContentSize().height / 2 - 130));
	this->addChild(light);

	//过关文字
	auto title = Sprite::create("win_or_lose/failed_title.png");
	title->setPosition(Vec2(WINSIZE.width / 2 - 30, WINSIZE.height / 2 + bg2->getContentSize().height / 2 + title->getContentSize().height / 2 - 30));
	this->addChild(title);

	//关卡
	auto level = Sprite::create("scene/level.png");
	level->setPosition(bg2->getContentSize().width / 2, 280);
	bg2->addChild(level);

	//关卡数
	auto levelTTF = Label::createWithCharMap("fonts/label/label_level_1.png", 31, 42, '0');
	levelTTF->setString(StringUtils::format("%d", GlobalManage::getInstance()->currentLevel));
	if (type == LanguageType::CHINESE) {
		levelTTF->setPosition(level->getContentSize() / 2);
	}
	else {
		levelTTF->setPosition(level->getContentSize().width, level->getContentSize().height / 2);
	}
	level->addChild(levelTTF);

	//按钮
	auto selectItem = MenuItemImage::create("win_or_lose/select.png", "win_or_lose/select.png");
	selectItem->initWithCallback(CC_CALLBACK_1(GameFailedLayer::onReturnToSelectSceneBtnPressed, this));
	selectItem->setPosition(Vec2(200, 146));

	auto replayItem = MenuItemImage::create("win_or_lose/replay.png", "win_or_lose/replay.png");
	replayItem->initWithCallback(CC_CALLBACK_1(GameFailedLayer::onRestartBtnPressed, this));
	replayItem->setPosition(Vec2(520, 146));

	auto menu = Menu::create(selectItem, replayItem, NULL);
	menu->setPosition(Vec2::ZERO);
	bg2->addChild(menu);

}

//返回开始菜单
void GameFailedLayer::onReturnToMenuSceneBtnPressed(Ref* pSender) {
	Director::getInstance()->replaceScene(GameMenuScene::createScene());
}

//返回选关
void GameFailedLayer::onReturnToSelectSceneBtnPressed(Ref* pSender) {
	Director::getInstance()->replaceScene(GameLevelScene::createScene());
}

//分享
void GameFailedLayer::onShareBtnPressed(Ref* pSender) {
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
#endif
}

//重新开始
void GameFailedLayer::onRestartBtnPressed(Ref* pSender) {
	Director::getInstance()->replaceScene(GameScene::createScene());
}

胜利失败界面已经创建好了,那么我我们在GameScene中进行触发吧,触发方式如下,在GameScene中update下如下实现

//刷新游戏
void GameScene::update(float dt) {
	//刷新玩家小球位置
	auto max = userBallList.size() >= 4 ? 4 : userBallList.size();
	for (unsigned int i = 0; i < max; i++) {
		auto ball = userBallList.at(i);
		if (!ball) {
			continue;
		}
		ball->setPosition(360, 300 - 42 * i);
		ball->setVisible(true);
	}
	//检测是否碰撞,如果碰撞,游戏结束
	if (isBallCollision) {
		//播放音效
		GameMusic::playEffect("music/fail.wav");
		circle->stopAction(rotate);
		this->runAction(Sequence::create(
			DelayTime::create(0.8f),
			CallFunc::create(CC_CALLBACK_0(GameScene::createFailedLayer, this)),
			NULL));
		unscheduleUpdate();
	}

	if (!isBallCollision) {
		if (userBallNum == 0) {
			//播放音效
			GameMusic::playEffect("music/win.wav");
			this->runAction(Sequence::create(
				DelayTime::create(0.5f),
				CallFunc::create(CC_CALLBACK_0(GameScene::createSuccessLayer, this)),
				NULL));
			unscheduleUpdate();
		}
	}
}

有人会问Update是干甚的?下一节将会带领大家了解cocos2dx刷新和定时器

二、创建选关界面

上述胜利失败界面已经显示出来了,那么我们如何进入下一关呢?
首先我们需要一个关卡选择的界面,还记得前面第二个场景中关卡选择按钮么,就是跳转到这个界面哦
在这一段代码中涉及到触摸方法,后续会对相关内容进行单独的介绍
那么我们直接看一下实现

头文件GameLevelScene.h

#pragma once
#include "cocos2d.h"

USING_NS_CC;

class GameLevelScene : public cocos2d::Layer {
public:
	GameLevelScene();
	~GameLevelScene();
    static cocos2d::Scene* createScene();
    virtual bool init();   
    CREATE_FUNC(GameLevelScene);
	//触摸开始方法
    bool onTouchBegan(Touch* touch, Event* event);
    //触摸移动方法 
    void onTouchMoved(Touch* touch, Event* event);
    //触摸结束方法
    void onTouchEnded(Touch* touch, Event* event);
public:
	void onKeyReleased(EventKeyboard::KeyCode keycode, Event* event);
public:
	//点击关卡按钮
	void onLevelBtnPressed(Ref* pSender, int level);
	//返回按钮回调
	void onBackBtnPressed(cocos2d::Ref *pSender);
private:
	Layer *levelLayer;
private:
	Point pos1;
	Point pos2;
	//当前页编号
	int pageIndex;
};

类文件GameLevelScene.cpp

#include "GameLevelScene.h"
#include "GameScene.h"
#include "GameMenuScene.h"
#include "GameDataManage.h"
#include "GlobalManage.h"
#include "Defines.h"

#define PAGE_CONTIANER_MAX	40
#define LEVEL_PAGES  (int)(ceil((float)(GameDataManage::getInstance()->totalRow) / (float)(PAGE_CONTIANER_MAX)))

GameLevelScene::GameLevelScene() :pageIndex(1){
}

GameLevelScene::~GameLevelScene() {
}

Scene* GameLevelScene::createScene()
{
    auto scene = Scene::create();
    auto layer = GameLevelScene::create();
    scene->addChild(layer);
    return scene;
}

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

	//绘制游戏背景
	auto bg = Sprite::create("level/bg_level.jpg");
	bg->setPosition(WINSIZE / 2);
	this->addChild(bg);

	//返回按钮
	auto back = MenuItemImage::create(
		"common/back.png",
		"common/back.png",
		CC_CALLBACK_1(GameLevelScene::onBackBtnPressed, this));
	back->setPosition(60, WINSIZE.height - 60);
	
	auto menu = Menu::create(back, NULL);
	menu->setPosition(Point::ZERO);
	this->addChild(menu, 1);
	
	levelLayer = Layer::create();
	this->addChild(levelLayer);
	//绘制关卡
	int index = 0;
	int maxLevel = GameDataManage::getInstance()->totalRow;
	for(int i = 1; i <= maxLevel; i++) {
		MenuItemImage *item = NULL;
		if(i <= GameDataManage::getInstance()->getCurrentMaxLevel()) {
			item = MenuItemImage::create(
				"level/has_pass.png",
				"level/has_pass.png",
				CC_CALLBACK_1(GameLevelScene::onLevelBtnPressed, this, i));
		} else {
			item = MenuItemImage::create(
				"level/has_pass.png",
				"level/has_pass.png",
				CC_CALLBACK_1(GameLevelScene::onLevelBtnPressed, this, i));
			//添加所锁
			auto lock = Sprite::create("level/lock.png");
			lock->setPosition(Vec2(item->getContentSize() / 2));
			item->addChild(lock, 10);
		}
		item->setPosition(WINSIZE.width * (int)(index / PAGE_CONTIANER_MAX) + 130 + index % 5 * (item->getContentSize().width + 5),
			1080-(index % PAGE_CONTIANER_MAX) / 5 * (item->getContentSize().width + 5));
	
		auto menu = Menu::create(item, NULL);
		menu->setPosition(Point::ZERO);
		levelLayer->addChild(menu);
		index++;
		//显示关卡数
		auto levelTTF = Label::createWithCharMap("fonts/label/label_level_2.png", 32, 44, '0');
		levelTTF->setPosition(item->getContentSize() / 2);
		levelTTF->setString(to_string(i));
		item->addChild(levelTTF);
	}

		//创建一个触摸监听 
	auto touchListener = EventListenerTouchOneByOne::create();   
	//向下传递触摸事件
	touchListener->setSwallowTouches(false);
	touchListener->onTouchBegan = CC_CALLBACK_2(GameLevelScene::onTouchBegan, this);
	touchListener->onTouchMoved = CC_CALLBACK_2(GameLevelScene::onTouchMoved, this);
	touchListener->onTouchEnded = CC_CALLBACK_2(GameLevelScene::onTouchEnded, this);
	_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);

	//注册捕捉监听
	auto listenerkeyPad = EventListenerKeyboard::create();
	listenerkeyPad->onKeyReleased = CC_CALLBACK_2(GameLevelScene::onKeyReleased, this);
	_eventDispatcher->addEventListenerWithSceneGraphPriority(listenerkeyPad, this);

	return true;
}

//触摸开始方法
bool GameLevelScene::onTouchBegan(Touch* touch, Event* event) {
	pos1 = touch->getLocation();
	return true;
}
//触摸移动方法 
void GameLevelScene::onTouchMoved(Touch* touch, Event* event) {
	pos2 = touch->getLocation();
}
//触摸结束方法
void GameLevelScene::onTouchEnded(Touch* touch, Event* event) {
	if(pos1.x - pos2.x > 100) {
		//向后翻页
		if(pageIndex < LEVEL_PAGES) {
			if(levelLayer->getNumberOfRunningActions() == 0) {
				levelLayer->runAction(MoveTo::create(0.5f, Point(-WINSIZE.width * pageIndex, 0)));
				pageIndex++;	
			}
		} else {
			pageIndex = LEVEL_PAGES;
		}	
	}
	if(pos1.x - pos2.x < -100) {
		//向前翻页
		if(pageIndex > 1) {
			if(levelLayer->getNumberOfRunningActions() == 0) {
				levelLayer->runAction(MoveTo::create(0.5f, Point(-WINSIZE.width * (pageIndex - 2), 0)));	
				pageIndex--;
			}
		} else {
			pageIndex = 1;
		}
	}
}

void GameLevelScene::onKeyReleased(EventKeyboard::KeyCode keycode, Event* event) {
	if (keycode == EventKeyboard::KeyCode::KEY_ESCAPE) {
		Director::getInstance()->replaceScene(GameMenuScene::createScene());
	} else if (keycode == EventKeyboard::KeyCode::KEY_MENU) {

	}
}

//点击关卡按钮
void GameLevelScene::onLevelBtnPressed(Ref* pSender, int level) {
	GlobalManage::getInstance()->currentLevel = level;
	if(GlobalManage::getInstance()->currentLevel > GameDataManage::getInstance()->getCurrentMaxLevel()) {
	} else {
		//友盟统计关卡
		GameDataManage::getInstance()->loadGameData(GlobalManage::getInstance()->currentLevel);
		Director::getInstance()->replaceScene(GameScene::createScene());
	}
}

//返回按钮回调
void GameLevelScene::onBackBtnPressed(cocos2d::Ref *pSender) {
	Director::getInstance()->replaceScene(GameMenuScene::createScene());
}

三、游戏音效SimpleAudioEngine

SimpleAudioEngine是一个单例,使用方式为

CocosDenshion::SimpleAudioEngine::getInstance()

开启音效别忘了在AppDelegete中将如下打开哦,这个是设置游戏前台后台运行时需要做的操作哦

// This function will be called when the app is inactive. When comes a phone call,it's be invoked too
void AppDelegate::applicationDidEnterBackground() {
	Director::getInstance()->stopAnimation();
	// if you use SimpleAudioEngine, it must be pause
	CocosDenshion::SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
}

// this function will be called when the app is active again
void AppDelegate::applicationWillEnterForeground() {
	Director::getInstance()->startAnimation();
	// if you use SimpleAudioEngine, it must resume here
	CocosDenshion::SimpleAudioEngine::getInstance()->resumeBackgroundMusic();
}

我们来看下对GameMusic的封装

头文件GameMusic.h

#pragma once
#include "cocos2d.h" 
#include "GlobalManage.h"
#include "SimpleAudioEngine.h"

class GameMusic
{
public:
    //播放音乐
    static void playMusic(const char *music, bool loop = false);
	//播放音效
    static void playEffect(const char *effect, bool loop = false);
	//停止音乐
    static void stopMusic();
	//停止音效
    static void stopAllEffect();
    //暂停音乐
    static void pauseMusic();
	//恢复音乐
    static void resumeMusic();
};

类文件GameMusic.cpp

#include "GameMusic.h"
#include "GlobalManage.h"

USING_NS_CC;

//播放音乐
void GameMusic::playMusic(const char *music, bool loop) {
	if(GlobalManage::getInstance()->isPlayMusic) {
		CocosDenshion::SimpleAudioEngine::getInstance()->playBackgroundMusic(music, loop);
	}
}

//播放音效
void GameMusic::playEffect(const char *effect, bool loop) {
	if(GlobalManage::getInstance()->isPlayEffect) {
		CocosDenshion::SimpleAudioEngine::getInstance()->playEffect(effect, loop);
	}
}

//停止音乐
void GameMusic::stopMusic() {
	 CocosDenshion::SimpleAudioEngine::getInstance()->stopBackgroundMusic();
}

//停止音效
void GameMusic::stopAllEffect() {
	CocosDenshion::SimpleAudioEngine::getInstance()->stopAllEffects();
}

//暂停音乐
void GameMusic::pauseMusic() {
	CocosDenshion::SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
}

//恢复音乐
void GameMusic::resumeMusic() {
	CocosDenshion::SimpleAudioEngine::getInstance()->resumeBackgroundMusic();
}

实现到这里其实整个游戏大部分已经完成啦,有兴趣的小伙伴们可以发散下自己的思维啊,设计一些更好玩的玩法哈

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值