Cocos2dx 3.0 过渡篇(三十一)ValueVector和Vector不得不说的故事

本文投票地址http://vote.blog.csdn.net/Article/Details?articleid=37834689

前天看到一个颇为纠结的选择题:有一天你遇到一个外星人,这时外星人很热情的邀请你到他们星球去玩,你如何选

1:去,但是你有可能永远不能在回来。
2:不去,但是外星人会消去你的记忆

这问题很刺激有木有?!看似简单的一个问题,不同的答案却隐藏着不同的含义。
------------------
鱼与熊掌不可兼得,类似这种例子生活中会经常碰到。同样的,如果你有去了解过Cocos2dx3.0,也会遇到这样一个令人纠结的情况:
那就是:Value 与 Vector(Map)。
为什么这么说呢?且听我慢慢道来。
-----------------

在Cocos2dx 2.0版本,
我们要存储一个int型数据,应该放到哪里?没错,放到CCArray中,如下:

int i = 10;
CCArray _array = CCArray::create();//创建一个CCArray数组
_array->addObject(CCInteger::create(i));//将int型数据放入数组中

如果要存储一个CCObject对象,又是用什么存呢?是的,又是CCArray

CCSprite* sp = CCSprite::create("star.png");//创建一个精灵
...
_array->addObject(sp);//将精灵放入到数组中

在Cocos2dx3.0版本,
我们都知道该版本的CCArray已经被甩了(实际上用__Array也还是可以替用一下),那么要存储一个Ref(3.0后CCObject改名为Ref)对象应该如何操作?机智的我马上想到了CCArray的替代者:Vector,示例代码如下:

auto sp = Sprite::create("star.png");
...
Vector<Sprite*> sp_vec;//创建一个Sprite*类型的容器
sp_vec.pushBack(sp);//将精灵放入到容器中

如果对Vector的操作不是很熟悉,可以看之前的博客:http://blog.csdn.net/star530/article/details/19170853

接下来问题来了,如果要存储一个数据类型,如int型数据,那么用Vector可以实现吗?答案是否定的,在Vector的官方说明文档里有这么一句话:

cocos2d::Vector<T> 中的T必须是一个指向cocos2d::Ref子类对象的指针。不能是其他数据类型或者原生类型,因为我们已经将 Cocos2d-x 的内存管理模型集成到 cocos2d::Vector<T> 中。

有句话叫什么来着:上帝为你关上了一扇门,一定会为你打开一扇窗...此处不留爷,自有留爷处...既然Vector容不下数据类型的元素,那么肯定有可以替代它的东西存在。没错,ValueVector登上了历史舞台。
第一次看到ValueVector时我就愣住了,这货又是什么碗糕?几秒后我反应过来,这货肯定是Value与Vector的私生子,我实在太特么机智了,这么抽象的命名都能让我快速想到答案,心中不禁暗自得意。
先到CCValue.h头文件中看下它的声明:

typedef std::vector<Value> ValueVector;

可以看出,ValueVector实际上就是一个存放Value类型元素的std::vector容器,这里和我之前的猜测有些出入。下面将几个int型数据存储到ValueVector中。

int a = 10;
int b = 20;
ValueVector val_vec;
val_vec.push_back(Value(a));
val_vec.push_back(Value(b));

上面代码就是创建两个int型的变量,然后放入ValueVector中,其中要注意的是:因为ValueVector中只能存放Value类型的元素,所以int型的a、b变量必须转换成Value类型后才能放入到ValueVector中。

关于Value的一些用法,可以看之前的博客:http://blog.csdn.net/star530/article/details/21651751

------------------------------------------------------------------------------------------------------------

说到ValueVector,那就顺便提下它的一些简单操作:
1、读取Plist(xml)配置文件
。如下:

ValueVector star_val = FileUtils::getInstance()->getValueVectorFromFile("star.plist");

不过用ValueVector读取的plist文件只局限于是该plist的格式的以array数组类型开头的,例如下面这种:

<array>
	<dict>
		<key>name</key>
		<string>star</string>
		<key>isCool</key>
		<string>yes</string>
	</dict>
</array>

如果是以dict字典类型开头的文件,则要换用ValueMap,这是下一篇的内容,先跳过

2、往ValueVector中插入一个元素。上面有提到过,ValueVector实际上就是一个存放Value类型的vector顺序容器,所以它的插入元素方式可以直接使用vector顺序容器的操作。示例如下:

int a = 10;
std::string b = "star is so cool";
ValueVector star_val;
star_val.push_back( Value(a) );
star_val.push_back( Value(b) );//放入ValueVector前都要先将类型转成Value类型

3、提取ValueVector中的元素。这里我接上面的例子来用:

int a1 = star_val.at(0).asInt();
std::string b1 = star_val.at(1).asString();
CCLOG("a1 = %d ,b1 = %s",a1,b1);

上面的代码比较容易理解,就是提取star_val中放在0和1位置上的元素,然后分别转成int型和string型。asInt()与asString()是Value用来实现类型转换的函数。

4、删除ValueVector中的元素。容器中比较常用的删除元素方式有三种:
1)删除容器中最后一个元素

star_val.pop_back();//直接删除容器中最后一个元素

2)用erase删除容器中的某一个元素?为什么我要在前面加个问号呢?假设我要删除star_val中的 元素a,代码如下:

auto star_iter = std::find(star_val.begin(),star_val.end(),a);
star_val.erase(star_iter);

上面两行代码信息量还是比较大的,首先我们要知道erase 删除的是由一个迭代器指向的单个元素,而不是直接这样:
star_val.erase(a);

这种操作是错误的,那么,什么是迭代器呢?我举个小例子:

假设一个教室就是一个vector容器,每个学生都是vector中的一个元素,而学生对应的座号就是迭代器。假设有一个新来的老师erase,她上课的时候你竟然和旁边的女同学眉来眼去,老师大怒,她打算让你立马从教室中滚出去,但她根本不知道你的名字,所以她只能这样做:

“第3列、第5排那个搞小动作的童鞋......别指了,说的就是你,你特么给我滚出去”

好了,让我们忘记这个麻辣女老师吧。既然已经知道erase里的参数须是一个迭代器,那么a元素对应的迭代器是什么呢?这里就要用到find算法,它将返回a在容器中的迭代器。(std::find的具体用法请猛戳这里:点我!!!
最后,我不得不羞涩的告诉大家,这种删除元素的方式是无法编译成功的!!!因为Value里没有重载==运算符,而std::find里面的数据类型必须实现==运算符,所以没法用查找,也就没法删除。
看到这里有人肯定要拍桌子了:尼玛,这方法不能删除你写这么多干嘛?裤子都脱了你就给我看这个?&……%*。
我的回答是:呵呵...知道我当初折腾这个erase用了多少时间么?没错!我现在就是报复社会的节奏!不拿你们乐呵乐呵偶心里不痛快~!

3)请收起手里愤怒的西瓜刀,深吸一口气。既然无法删除指定的元素,那我破罐子破摔,将全部元素都删除总可以吧?答案是肯定的:

star_val.clear();

用clear删除全部元素,从根源上解决您生理上的困扰~

-----------------------------------------------------------------------------------------------------------------------

好了,ValueVector的用法说到这里,最后做下总结和补充:
1、Vector只能用来存放Ref类型的元素,不能存放数据类型的元素;
2、ValueVector只能用来存放Value类型的元素,因为Value说到底就是数据类型,所以也可以认为ValueVector只能用来存放数据类型,千万别将Ref类型的元素放进入,否则会很刺激。
3、ValueVector中可以放ValueVector,前提是将ValueVector转成Value类型;而Vector中不能存放Vector类型的元素,如下:

ValueVector star_val;
ValueVector star_val2;
star_val.push_back( Value(star_val2) );//正确

Vector< Vector<Ref*> > star_vec;//错误!

OK,就写到这里吧。

----------------------------------------------------------------------------------------------------------------------

尊重原创,转载请注明来源:http://blog.csdn.net/star530/article/details/37834689

本文参加了CSDN博客大赛,如果你觉得该篇对你有所帮助,请给我投上一票吧!我这辈子都会感激你的!投票地址:

http://vote.blog.csdn.net/Article/Details?articleid=37834689拉倒页面最下方即可投票

Cocos2dx 3.0 过渡篇(三十一)ValueVector和Vector不得不说的故事

时间: 2024-10-07 06:39:24

Cocos2dx 3.0 过渡篇(三十一)ValueVector和Vector不得不说的故事的相关文章

Cocos2dx 3.0 过渡篇(二十九)globalZOrder()与localZOrder()

前天很难得的加班到八点...为什么说难得呢?因为平时我几乎就没加班过.六点下班后想走就走,想留就留.率直洒脱,不拘一格,尽显男儿本色.程序员,就是这么自信! -----------这篇博客的标题本想叫"...3.0新的渲染...介绍",最后还是拉不下这个脸.为啥?觉得自己对渲染的认识还是过于表面,谈不上理解.当然了,这并不影响这篇博客继续写下去.下面看一段3.0Release Notes 对于新渲染器的一段介绍: Node 增加了新的函数 setGlobalZOrder() / get

Cocos2dx 3.0 过渡篇(二十八)C++11强类型枚举

一朋友在微信朋友圈晒了张照片,随手点开大图,带着欣赏的眼光扫了下,恩,几个月不见,又漂亮了...咦?等等,她戴的这是什么?酷炫的造型!金属边框!微型摄像头!这不是传说中的谷歌眼镜么?土豪啊,还好我们已经是朋友了...我先给了她一个赞,然后直奔主题,霸气回复道:我过几天去找你,你戴的是谷歌眼镜吧,哼哼小样,不想死的话...就让我...摸一下下可以么,我不奢求戴,摸一下就满足了...(哎,丢人啊). ------------------- 在cocos2dx 3.0的文档里有这么一句话:以 k 开头

Cocos2dx 3.0 过渡篇(三十二)话说ValueMap的一般使用

周末到厦门找死党聚聚,晚上一伙人杀到一还算凑合的大排档准备来个不醉不归.菜都点完了朋友突然说这里没有洗手间...尼玛,当时我们就不乐意了:喝五六个小时的啤酒,没有洗手间你是打算憋死谁?二话不说直接换一家,不过这次一定要谨慎选择,最终看到一家看起来还算正宗的大排档,我下意识拨了下头发,走到前台MM面前,轻声问道:你们这...有洗手间吗? 声音低沉且性感,语调中还夹带着些许的忧伤. 前台MM瞪大眼睛,好一会才反应过来说道:洗手间?肯定有啊! ----------------------------

Cocos2dx 3.0 过渡篇(二十五)死不了的贪食蛇(触摸版)

上一篇写的贪食蛇的重力感应控制版,这一篇就讲下触摸控制版吧.额,也不知道写了那个贪食蛇教程究竟有没有获得沈老师的书,假设没有的话,看我不拿西瓜刀砍掉 偶尔E往事 的那啥! 重力版链接:http://blog.csdn.net/start530/article/details/23707985 触摸版与重力版的代码大部分都一样,不一样的地方就是要将打开重力感应换成创建一个触摸监听.步骤例如以下: 1.在GameLayer的init()中创建一个触摸监听事件 [cpp] view plaincopy

Cocos2dx 3.0 过渡篇(二十七)C++11多线程std::thread的简单使用(下)

本篇接上篇继续讲:上篇传送门:http://blog.csdn.net/star530/article/details/24186783 简单的东西我都说的几乎相同了,想挖点深的差点把自己给填进去. 以下实际演练一下.请同意我參考偶尔E往事的一篇线程的博客, 他用的是pThread.这里我就用std::thread. 1.售票孙鑫老师的C++和Java多线程售票也一直让我念念不忘(好吧,我承认我没看过).这里用cocos2d-x3.0和C++11的std::thread实现一个吧.总共同拥有10

1、Cocos2dx 3.0游戏开发三找一小块前言

尊重开发人员的劳动成果,转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/27094663 前言 Cocos2d-x 是一个通用平面游戏引擎.基于一个相同十分著名的游戏引擎 Cocos2d-iPhone 设计. 它继承了 Cocos2d 系列引擎一贯的特点:使用简单.执行高效.灵活,且功能强大. 与 Cocos2d-iPhone 不同的是.Cocos2d-x 还拥有强大的跨平台能力,仅仅须要编写一次代码. 就能够无缝地部署在

Cocos2dx3.0过渡篇 各种遍历与范围for语句的使用【转】

1.CCArray的遍历看到这里,有些人又按耐不住的要举起西瓜刀了:你不是说3.0beta后已经没有CCArray这货了吗?现在又拿出来作甚?其实我也很无辜,CCArray确实是没了,但在某个不为人知的角落里却藏着__Array这货,我大胆猜测它是CCArray同父异母的兄弟,因为它有着和CCArray一样的功能.可惜的是,因为Vector的崛起,__Array注定只会埋没. CCArray的遍历宏是CCARRAY_FOREACH(_array,_object),这种遍历方式是正想遍历,用for

9、Cocos2dx 3.0游戏开发三查找值小工厂方法模式和对象

重开发人员的劳动成果,转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/27704153 工厂方法模式 工厂方法是程序设计中一个经典的设计模式.指的是基类中仅仅定义创建对象的接口,将实际的实现推迟到子类中. 在这里.我们将它稍加推广,泛指一切生成并返回一个对象的静态函数. 一个经典的工厂方法如同这样: Sprite* factoryMethod() { Sprite* ret = new Sprite(); //在这里对 r

10、Cocos2dx 3.0游戏开发找小三之容器篇:Vector、Map、Value

重开发者的劳动成果,转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/27705613 容器 3.0版本之前Cocos2d-x 引擎为我们提供了 CCArray. CCDictionary 等 Objective-C 风格的容器: 使用 Cocos2d-x 容器的一个重要原因在于 Cocos2d-x 的内存管理. 一般来说,被存入容器的对象在移除之前都应该保证是有效的, 但值得注意的是,在v3.0 beta版本中加入了数据结