cocos2dx3.2开发 RPG《Flighting》四预先加载与选人界面

一、前言

假设你已经看懂了前面三节,那么接下来我们就开始进入真正的开发啦~~


二、正文

1、预先加载

首先我们先谈谈预先加载,什么叫预先加载,就是在资源没有被用到的时候就先把资源加载到内存,等要用的时候直接从内存里面获取就好。

这样的好处是当用的时候会省去加载的时间,但是坏处就是占用一部分内存,这是一个时间与空间的选择问题。

游戏一开始进入的是MenuScene

bool MenuScene::init(){
	preLoadingSomethings();
	MenuLayer* layer = MenuLayer::create();
	this->addChild(layer);
	return true;
}

init函数很简单,没有什么特别,需要注意的是preLoadingSomethings函数
void MenuScene::preLoadingSomethings(){
	
	std::map<int,HeroMessage> temp = HeroMessageUtil::getInstance()->getHeroMessageMap();
	

	for(auto it = temp.begin();it!=temp.end();it++){
		HeroMessage temp = it->second;
		std::string png = "BoneAnimate/" + temp.r_png;
		std::string plist = "BoneAnimate/" + temp.r_plist;
		std::string EJ = "BoneAnimate/" + temp.r_ExportJson;
		ArmatureDataManager::getInstance()->addArmatureFileInfo(png,plist,EJ);
	}

	std::map<int,MonsterMessage> monTemp = MonsterMessageUtil::getInstance()->getMonsterMessageMap();
	for(auto it = monTemp.begin();it!=monTemp.end();++it){
		MonsterMessage temp = it->second;
		std::string png = "BoneAnimate/" + temp.r_png;
		std::string plist = "BoneAnimate/" + temp.r_plist;
		std::string EJ = "BoneAnimate/" + temp.r_ExportJson;
		ArmatureDataManager::getInstance()->addArmatureFileInfo(png,EJ);
	}

	StageMessageUtil::getInstance();
}

如果你有看上一节,那么你应该知道XXXMessageUtil是什么小编了。


因为如果要使用骨骼动画,必须先把骨骼动画的资源通过 ArmatureDataManager的addArmatureFileInfo()加载

所以为了以后能够方便地使用骨骼动画,先统一在MenuScene初始化的时候加载。


2、选人界面

好吧,MenuScene跟MenuLayer没有什么其他特别的,就提供了一个开始按钮,转到选人界面ChooseScene

ChooseScene也没有什么,就包含了一个ChooseLayer。

效果图:




下面重点讲ChooseLayer

#ifndef _CHOOSELAYER_H_
#define _CHOOSELAYER_H_
#include "cocos2d.h"
#include "ui/CocosGUI.h"
#include "cocostudio/CocoStudio.h"
#include "extensions/cocos-ext.h"
USING_NS_CC;
using namespace cocostudio;
using namespace ui;
class HeroItem;
class ChooseLayer : public Layer{
public:
	virtual bool init();
	CREATE_FUNC(ChooseLayer);
private:
	//加载可选英雄
	void loadHeroes();
	//初始化
	void initHeroMsg();
	//设置当前英雄
	void setCurHeroMsg(int index,int heroIndex);

	//按钮回调函数
	void startGame(Ref* pSender,ui::TouchEventType type);

	void leftHero1(Ref* pSender,ui::TouchEventType type);
	void rightHero1(Ref* pSender,ui::TouchEventType type);

	void leftHero2(Ref* pSender,ui::TouchEventType type);
	void rightHero2(Ref* pSender,ui::TouchEventType type);

	void leftHero3(Ref* pSender,ui::TouchEventType type);
	void rightHero3(Ref* pSender,ui::TouchEventType type);

	void backToMenu(Ref* pSender,ui::TouchEventType type);

private:
	std::vector<HeroItem> heroArray;
	Text* hero_name1;
	Text* hero_name2;
	Text* hero_name3;

	Widget* pNode;

	int cur_hero1_index;
	int cur_hero2_index;
	int cur_hero3_index;

	Armature* hero1;
	Armature* hero2;
	Armature* hero3;
};

class HeroItem : public Ref{
friend class ChooseLayer;
public:
	HeroItem(const std::string& name,const int id,const std::string& resourceName,const int o_x,const int o_y);
	~HeroItem();
private:
	std::string name;
	std::string resourceName;
	int id;
	int o_x;
	int o_y;
};
#endif

注意的是,我这里没有用数组,而是直接用hero1、hero2、hero3这样子的枚举,所以就限定死了只有3个位置。。这是一种笨方法,会出现代码的冗余,在开发中不应该出现,这里懒得修改。。所以请各位不要学习,见谅见谅。

而且这里的布局我也是用cocostudio1.6的,所以你们可能有点看不懂。如果需要补充cocostudio的UI编辑器知识,推荐以下文章

http://cn.cocos2d-x.org/tutorial/show?id=1674


这里我先定义HeroItem结构保存我在选人界面需要用到的信息,其实他就是简化版的HeroMessage(因为在选人界面只用到一部分信息)

而且注意我定义了一个vector<HeroItem>。


下面看各个函数的具体实现:

bool ChooseLayer::init(){
	pNode = GUIReader::getInstance()->widgetFromJsonFile("UI/ChooseLayerUI.json");
	this->addChild(pNode,0);

	Button* enterBtn = (Button*)Helper::seekWidgetByName(pNode,"enterBtn");
	enterBtn->addTouchEventListener(this,toucheventselector(ChooseLayer::startGame));

	Button* backBtn = (Button*)Helper::seekWidgetByName(pNode,"backBtn");
	backBtn->addTouchEventListener(this,toucheventselector(ChooseLayer::backToMenu));

	Button* leftBtn1 = (Button*)Helper::seekWidgetByName(pNode,"leftBtn1");
	leftBtn1->addTouchEventListener(this,toucheventselector(ChooseLayer::leftHero1));

	Button* leftBtn2 = (Button*)Helper::seekWidgetByName(pNode,"leftBtn2");
	leftBtn2->addTouchEventListener(this,toucheventselector(ChooseLayer::leftHero2));
	
	Button* leftBtn3 = (Button*)Helper::seekWidgetByName(pNode,"leftBtn3");
	leftBtn3->addTouchEventListener(this,toucheventselector(ChooseLayer::leftHero3));


	Button* rightBtn1 = (Button*)Helper::seekWidgetByName(pNode,"rightBtn1");
	rightBtn1->addTouchEventListener(this,toucheventselector(ChooseLayer::rightHero1));

	Button* rightBtn2 = (Button*)Helper::seekWidgetByName(pNode,"rightBtn2");
	rightBtn2->addTouchEventListener(this,toucheventselector(ChooseLayer::rightHero2));

	Button* rightBtn3 = (Button*)Helper::seekWidgetByName(pNode,"rightBtn3");
	rightBtn3->addTouchEventListener(this,toucheventselector(ChooseLayer::rightHero3));

	
	initHeroMsg();

	return true;
}
init函数就是负责获取按钮,并为按钮绑定回调函数的,至于回调函数的实现等下再说。

注意最后一行调用了initHeroMsg

看initHeroMsg函数之前,先看loadHeroes函数

void ChooseLayer::loadHeroes(){
	map<int,HeroMessage> temp = HeroMessageUtil::getInstance()->getHeroMessageMap();
	for(auto it = temp.begin();it!=temp.end();it++){
		HeroMessage msg = (*it).second;
		HeroItem item(msg.name,msg.id,msg.r_name,msg.offset_x,msg.offset_y);
		heroArray.push_back(item);
	}
}
loadHeroes函数就是对heroArray的初始化,调用过一次这个函数之后,以后就只需要从heroArray里面拿数据就好了


好的,回过头来看initHeroMsg吧

void ChooseLayer::initHeroMsg(){
	loadHeroes();
	
	hero_name1 = (Text*)Helper::seekWidgetByName(pNode,"heroName1");
	hero_name2 = (Text*)Helper::seekWidgetByName(pNode,"heroName2");
	hero_name3 = (Text*)Helper::seekWidgetByName(pNode,"heroName3");

	cur_hero1_index = 0;
	cur_hero2_index = 0;
	cur_hero3_index = 0;

	hero1 = nullptr;
	hero2 = nullptr;
	hero3 = nullptr;

	setCurHeroMsg(0,1);
	setCurHeroMsg(0,2);
	setCurHeroMsg(0,3);
}
先loadHeroes初始化array

下面的也是对一些变量初始化。

cur_hero1_index表示的是1号位置当前的角色对应array中的位置

setCurHeroMsg(0,1);表示设置1号位置的角色的index为0

具体实现如下:

void ChooseLayer::setCurHeroMsg(int index,int heroIndex){
	if(index < 0){
		index = index + heroArray.size();
	}

	if(index >= heroArray.size()){
		index = index - heroArray.size();
	}
	switch(heroIndex){
	case 1:
		cur_hero1_index = index;
		hero_name1->setText(heroArray[cur_hero1_index].name);
		if(hero1)	hero1->removeFromParentAndCleanup(true);
		hero1 = Armature::create(heroArray[cur_hero1_index].resourceName);
		hero1->setPosition(hero_name1->getPositionX()+heroArray[cur_hero1_index].o_x,hero_name1->getPositionY()+heroArray[cur_hero1_index].o_y);
		hero1->getAnimation()->play("stand");
		this->addChild(hero1);
		break;
	case 2:
		cur_hero2_index = index;
		hero_name2->setText(heroArray[cur_hero2_index].name);
		if(hero2)	hero2->removeFromParentAndCleanup(true);
		hero2 = Armature::create(heroArray[cur_hero2_index].resourceName);
		hero2->setPosition(hero_name2->getPositionX()+heroArray[cur_hero2_index].o_x,hero_name2->getPositionY()+heroArray[cur_hero2_index].o_y);
		hero2->getAnimation()->play("stand");
		this->addChild(hero2);
		break;
	case 3:
		cur_hero3_index = index;
		hero_name3->setText(heroArray[cur_hero3_index].name);
		if(hero3)	hero3->removeFromParentAndCleanup(true);
		hero3 = Armature::create(heroArray[cur_hero3_index].resourceName);
		hero3->setPosition(hero_name3->getPositionX()+heroArray[cur_hero3_index].o_x,hero_name3->getPositionY()+heroArray[cur_hero3_index].o_y);
		hero3->getAnimation()->play("stand");
		this->addChild(hero3);
		break;
	default:
		break;
	
	}
}
第一个参数:index,表示对应heroArray的位置

第二个参数:heroIndex,表示哪一个位置的英雄


一开始先判断index的合法性,这样的实现能够使其达到一种首尾循环的效果。

接着的switch语句是根据英雄的位置,去修改相应的对象,应该不能理解。

PS:再强调一次,我一开始写这个代码的时候图个简单,所以用了枚举的笨方法,大家不要学习,看一看,笑一笑就好。


如果都看懂了最重要的setCurHeroMsg()函数,那么很容易就想到,3对左右选择按钮的实现就可以依靠setCurHeroMsg函数了

void ChooseLayer::leftHero1(Ref* pSender,TouchEventType type){
	if(type == TouchEventType::TOUCH_EVENT_BEGAN){
		setCurHeroMsg(cur_hero1_index - 1,1);
	}
}

void ChooseLayer::leftHero2(Ref* pSender,TouchEventType type){
	if(type == TouchEventType::TOUCH_EVENT_BEGAN){
		setCurHeroMsg(cur_hero2_index - 1,2);
	}
}

void ChooseLayer::leftHero3(Ref* pSender,TouchEventType type){
	if(type == TouchEventType::TOUCH_EVENT_BEGAN){
		setCurHeroMsg(cur_hero3_index - 1,3);
	}
}

void ChooseLayer::rightHero1(Ref* pSender,TouchEventType type){
	if(type == TouchEventType::TOUCH_EVENT_BEGAN){
		setCurHeroMsg(cur_hero1_index + 1,1);
	}
}

void ChooseLayer::rightHero2(Ref* pSender,TouchEventType type){
	if(type == TouchEventType::TOUCH_EVENT_BEGAN){
		setCurHeroMsg(cur_hero2_index + 1,2);
	}
}

void ChooseLayer::rightHero3(Ref* pSender,TouchEventType type){
	if(type == TouchEventType::TOUCH_EVENT_BEGAN){
		setCurHeroMsg(cur_hero3_index + 1,3);
	}
}

好的,现在就只剩下进入游戏和返回这两个按钮的回调函数没有解释了。

返回按钮很简单

void ChooseLayer::backToMenu(Ref* pSender,TouchEventType type){
	if(type == TouchEventType::TOUCH_EVENT_ENDED){
		Director::getInstance()->replaceScene(MenuScene::create());
	}
}
其实进入游戏的函数也很简单啦,看不懂没关系,毕竟我们还没有讲战斗场景嘛。哈哈
void ChooseLayer::startGame(Ref* pSender,TouchEventType type){
	if(type == TouchEventType::TOUCH_EVENT_ENDED){

		GameScene* scene = GameScene::create();
		scene->setHeroTeam(
						HeroMessageUtil::getInstance()->getMessageById(heroArray[cur_hero1_index].id),HeroMessageUtil::getInstance()->getMessageById(heroArray[cur_hero2_index].id),HeroMessageUtil::getInstance()->getMessageById(heroArray[cur_hero3_index].id)
		);
		scene->setMonsterDeq(StageMessageUtil::getInstance()->getMessageById(3001).monsterDeq);
		Director::getInstance()->replaceScene(scene);
	}
}

大致的意思就是把当前三个位置的3个信息传到GameScene,由GameScene想干嘛就干嘛去

还有这里默认把id为3001的地图信息(StageMessage)也传到GameScene了,因为当时懒得弄关卡选择器哈哈。关于关卡选择和StageMessage的问题,后面在将战斗场景的时候还会跟大家交代清楚的,现在可以先视而不见吧。


至此,选人界面开发完毕。

我的csdn地址:http://blog.csdn.net/hezijian22

邮箱地址:578690286@qq.com

如有问题或指教,欢迎与我交流,谢谢。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


    本文实践自 RayWenderlich、Ali Hafizji 的文章《How To Create Dynamic Textures with CCRenderTexture in Cocos2D 2.X》,文中使用Cocos2D,我在这里使用Cocos2D-x 2.1.4进行学习和移植。在这篇文章,将会学习到如何创建实时纹理、如何用Gimp创建无缝拼接纹
Cocos-code-ide使用入门学习地点:杭州滨江邮箱:appdevzw@163.com微信公众号:HopToad 欢迎转载,转载标注出处:http://blog.csdn.netotbaron/article/details/424343991.  软件准备 下载地址:http://cn.cocos2d-x.org/download 2.  简介2.1         引用C
第一次開始用手游引擎挺激动!!!进入正题。下载资源1:从Cocos2D-x官网上下载,进入网页http://www.cocos2d-x.org/download,点击Cocos2d-x以下的Download  v3.0,保存到自定义的文件夹2:从python官网上下载。进入网页https://www.python.org/downloads/,我当前下载的是3.4.0(当前最新
    Cocos2d-x是一款强大的基于OpenGLES的跨平台游戏开发引擎,易学易用,支持多种智能移动平台。官网地址:http://cocos2d-x.org/当前版本:2.0    有很多的学习资料,在这里我只做为自己的笔记记录下来,错误之处还请指出。在VisualStudio2008平台的编译:1.下载当前稳
1.  来源 QuickV3sample项目中的2048样例游戏,以及最近《最强大脑》娱乐节目。将2048改造成一款挑战玩家对数字记忆的小游戏。邮箱:appdevzw@163.com微信公众号:HopToadAPK下载地址:http://download.csdn.net/detailotbaron/8446223源码下载地址:http://download.csdn.net/
   Cocos2d-x3.x已经支持使用CMake来进行构建了,这里尝试以QtCreatorIDE来进行CMake构建。Cocos2d-x3.X地址:https://github.com/cocos2d/cocos2d-x1.打开QtCreator,菜单栏→"打开文件或项目...",打开cocos2d-x目录下的CMakeLists.txt文件;2.弹出CMake向导,如下图所示:设置
 下载地址:链接:https://pan.baidu.com/s/1IkQsMU6NoERAAQLcCUMcXQ提取码:p1pb下载完成后,解压进入build目录使用vs2013打开工程设置平台工具集,打开设置界面设置: 点击开始编译等待编译结束编译成功在build文件下会出现一个新文件夹Debug.win32,里面就是编译
分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!http://www.captainbed.net前言上次用象棋演示了cocos2dx的基本用法,但是对cocos2dx并没有作深入的讨论,这次以超级马里奥的源代码为线索,我们一起来学习超级马里奥的实
1. 圆形音量button事实上作者的本意应该是叫做“电位计button”。可是我觉得它和我们的圆形音量button非常像,所以就这么叫它吧~先看效果:好了,不多解释,本篇到此为止。(旁白: 噗。就这样结束了?)啊才怪~我们来看看代码:[cpp] viewplaincopyprint?CCContro
原文链接:http://www.cnblogs.com/physwf/archive/2013/04/26/3043912.html为了进一步深入学习贯彻Cocos2d,我们将自己写一个场景类,但我们不会走的太远,凡是都要循序渐进,哪怕只前进一点点,那也至少是前进了,总比贪多嚼不烂一头雾水的好。在上一节中我们建
2019独角兽企业重金招聘Python工程师标准>>>cocos2d2.0之后加入了一种九宫格的实现,主要作用是用来拉伸图片,这样的好处在于保留图片四个角不变形的同时,对图片中间部分进行拉伸,来满足一些控件的自适应(PS: 比如包括按钮,对话框,最直观的形象就是ios里的短信气泡了),这就要求图
原文链接:http://www.cnblogs.com/linji/p/3599478.html1.环境和工具准备Win7VS2010/2012,至于2008v2版本之后似乎就不支持了。 2.安装pythonv.2.0版本之前是用vs模板创建工程的,到vs2.2之后就改用python创建了。到python官网下载版本2.7.5的,然后
环境:ubuntu14.04adt-bundle-linux-x86_64android-ndk-r9d-linux-x86_64cocos2d-x-3.0正式版apache-ant1.9.3python2.7(ubuntu自带)加入环境变量exportANDROID_SDK_ROOT=/home/yangming/adt-bundle-linux/sdkexportPATH=${PATH}:/$ANDROID_SDK_ROOTools/export
1开发背景游戏程序设计涉及了学科中的各个方面,鉴于目的在于学习与进步,本游戏《FlappyBird》采用了两个不同的开发方式来开发本款游戏,一类直接采用win32底层API来实现,另一类采用当前火热的cocos2d-x游戏引擎来开发本游戏。2需求分析2.1数据分析本项目要开发的是一款游
原文链接:http://www.cnblogs.com/linji/p/3599912.html//纯色色块控件(锚点默认左下角)CCLayerColor*ccc=CCLayerColor::create(ccc4(255,0,0,128),200,100);//渐变色块控件CCLayerGradient*ccc=CCLayerGradient::create(ccc4(255,0,0,
原文链接:http://www.cnblogs.com/linji/p/3599488.html//载入一张图片CCSprite*leftDoor=CCSprite::create("loading/door.png");leftDoor->setAnchorPoint(ccp(1,0.5));//设置锚点为右边中心点leftDoor->setPosition(ccp(240,160));/
为了答谢广大学员对智捷课堂以及关老师的支持,现购买51CTO学院关老师的Cocos2d-x课程之一可以送智捷课堂编写图书一本(专题可以送3本)。一、Cocos2d-x课程列表:1、Cocos2d-x入门与提高视频教程__Part22、Cocos2d-x数据持久化与网络通信__Part33、Cocos2d-x架构设计与性能优化内存优
Spawn让多个action同时执行。Spawn有多种不同的create方法,最终都调用了createWithTwoActions(FiniteTimeAction*action1,FiniteTimeAction*action2)方法。createWithTwoActions调用initWithTwoActions方法:对两个action变量初始化:_one=action1;_two=action2;如果两个a
需要环境:php,luajit.昨天在cygwin上安装php和luajit环境,这真特么是一个坑。建议不要用虚拟环境安装打包环境,否则可能会出现各种莫名问题。折腾了一下午,最终将环境转向linux。其中,luajit的安装脚本已经在quick-cocos2d-x-develop/bin/中,直接luajit_install.sh即可。我的lin
v3.0相对v2.2来说,最引人注意的。应该是对触摸层级的优化。和lambda回调函数的引入(嗯嗯,不枉我改了那么多类名。话说,每次cocos2dx大更新。总要改掉一堆类名函数名)。这些特性应该有不少人研究了,所以今天说点跟图片有关的东西。v3.0在载入图片方面也有了非常大改变,仅仅只是