GameMaker8.0 :新手教程 Part 24 -索引-

分类栏目:gamemaker教程

491

GameMaker8.0 :新手教程 Part 24 -索引-

1、实例索引

实例的索引,即实例的id,应该是我们最为熟悉的索引了,因此本章就从实例的索引开始讲起。

我们知道,对象只是一个模板,一个对象在房间内可以有多个实例,区别不同的对象可以使用对象名,而区别同不同的实例就用实例的索引。GM8会自动给每一个实例分配一个索引,这个索引用变量id储存,可以通过访问变量id来获取实例的索引。
通常情况下,实例id是从100001开始的。GM给实例分配索引是按照时间先后顺序的,首先给gmk工程中就已经摆在房间里的实例分配索引(按照摆上去的时间),然后在游戏运行时再接着给通过instance_create创建的实例分配索引。
注意,被删除的实例的索引不会再被分配。例如,你的房间内有四个实例,id分别是100001,100002,100003,100004,此时先删除id为100002的实例,再放置一个新的实例在房间内,新实例的id仍然是100005。也就是说,100002这个id永久置空了,再也不会有实例被分配为100002。
实例的索引一定是连续分配的。比如:
for(i = 0;i < 10;i += 1)
inst[i] = instance_create(0 , 0, objSample);
那么inst[0]到inst[9]一定是十个连续的数字。因此,(inst[0] + 9).speed = 5;和(inst[9]).speed = 5;是等效的。

在GML汉化文档的27-28页,提供了许多可以获取实例id的变量或函数。
GameMaker8.0 :新手教程 Part 24 -索引-

注意,在GML汉化文档的第27页有这么一句话:
GameMaker8.0 :新手教程 Part 24 -索引-
这句话有极大的歧义。
首先要肯定的一点是,一个实例从创建到销毁,它的id都是固定不变的。
其次是编号(number)和索引(index)在GM8中的区别。假如一个房间内有152个实例,将这些实例根据索引从小到大排序,索引最小的那个实例的编号就是0,索引最大的那个实例的编号就是151。如果下一帧销毁了2个实例,又创建了2个实例,虽然实例总数没有变,但是会重新编号,因此每一个实例编号对应的实例id就和上一帧不同了。由于编号在GM8中几乎只在instance_id[]和instance_find(obj, n)中用到,并且二者使用的还是不同的编号,也没有什么变量或函数可以获取实例的编号,因此几乎不为人所知。
因此,这句话实际想要表达的意思是“实例编号对应的实例索引每一步都会不相同,所以不可以使用上一步保存的值”。
同样的道理,在instance_find(obj, n)的汉化文档描述中:
GameMaker8.0 :新手教程 Part 24 -索引-
也是同一个意思。

2、资源名?索引!

首先我们需要明确一个事实,与其他很多语言不同的是,GM只有两种数据,实数型(real)和字符串型(string),如果你学过C语言或者C++,这两种类型就分别对应C/C++里的double类型和char*类型。如果你想用C/C++给GM8写插件的话,这一点是一定要牢记的。
给未学过编程的GM学习者的科普:通常一种语言有许多种数据类型,就拿C++举例,有空类型(void),字符型(char),宽字符型(wchar_t),整形(int),单浮点型(float),双浮点型(double),这些类型又分为有符号型(signed)和无符号型(unsigned),例如无符号整形(unsigned int),整形和双浮点型又有长(long)短(short)之分,比如无符号长整型(unsigned long int),每一种类型都有对应的指针类型(*),比如单浮点指针类型(float*),指针类型本身还可以有指针,比如长双浮点形指针的指针类型(long double**),编程者也可以通过struct/class创建新的类型,比如class complex{},就创建了一个新的complex类型。因此,GM只有两种数据类型,可以说是真的相当友好了。

咳,扯远了。
现在假设我们有一个精灵sprLight,我们用一个变量来保存它:
spr = sprLight;
那么spr这个变量到底储存了什么呢,是字符串"sprLight"吗?
如果你有心自己试验一下,通过show_message或者draw_text,你会发现spr储存了一个数字。
GameMaker8.0 :新手教程 Part 24 -索引-
如果你更有心,把所有资源:精灵,音频,背景图片,路径,脚本,字体,时间轴,对象,房间,全部用变量来保存,你会发现,所有这些变量保存的都是一个数字,而不是他们的名字对应的字符串。
这些数字就是资源的索引。
索引并不是实例的特权,任何存在于GM中的资源都会被分配索引。

3、万物皆索引

“任何存在于GM中的资源都会被分配索引”并不是夸大其词,除了实例的索引和资源的索引外,字符串中的字符,视野,表面,颜色,粒子,数据结构,dll插件,文件流等等,都是通过索引来操作的。
这些索引都遵循着共同的规则:
①从0开始分配。
②分配是连续的,前一个分配n,后一个就分配n+1。
③被销毁的资源的索引不会再次被分配。
④分配索引遵循创建时间先后。
⑤任何函数,当参数要求某项索引时,直接填入准确的数字是可以的。

4、对象与实例

那么为什么唯独实例的索引是从100001开始的呢?因为前100000是预留给对象的。
我们知道,在很多时候,一个参数位置是既可以填入对象名也可以填入实例索引的,通常用obj/id来表示,例如:with(obj/id),place_meeting(x, y, obj/id),instance_exists(obj/id)等。如果实例索引也是从0开始的,在调用函数时,GM就无法确认这个索引到底是对象的还是实例的。因此,GM8给对象预留了0-100000的索引位置,让实例的索引从100001开始。

我们之前还提到过特殊实例,self,other,all,noone,global,无主,local,他们的索引分别是-1,-2,-3,-4,-5,-6,-7,self(-1)表示调用者自身,通常用于当局部变量与globalvar变量冲突时,区别局部变量和globalvar变量,other(-2)表示对方,用于碰撞事件中表示碰撞的实例,或在with()结构中表示with的调用者,all(-3)表示所有实例,noone(-4)表示无实例,因此noone不能储存变量或执行函数,global(-5)表示全局变量,无主变量(-6)是一中特殊的变量,表示不属于任何实例的变量,目前已知的有两种,第一是通过globalvar声明的变量,第二种是在房间创建代码(Room Creation Code)中使用的变量,local(-7)表示通过var声明的变量。
注意,通过globalvar声明的变量可以同时使用(-5)和(-6)调用,但是通过global.声明的变量只能使用(-5)调用,除非再用globalvar声明一次。
由于索引本质就是实数,因此num = global*local;会给num赋值35。

5、扩展:句柄

句柄是windows系统的概念,不属于GM。
句柄可以理解为windows用来管理资源的索引,其本质是一个0至4294967295之间的整数。与GM的索引相同,windows对系统内几乎所有的资源都分配了句柄,文件有文件句柄,窗口有窗口句柄,进程有进程句柄,位图有位图句柄,内存有内存句柄等,想要管理windows资源,大都得先知道资源对应的句柄。
由于GM没有提供对句柄的操作函数,因此并不能直接管理windows资源,但是我们却可以管理GM的资源。GM中有一个函数window_handle(),返回游戏主窗口的句柄。在编写dll插件时,如果想要直接向游戏窗口内添加内容,而不是经过GM的函数,就必须得到游戏窗口的句柄。