访问器

GameMaker语言(GML )还允许您通过使用称为访问器的逻辑表达式来访问某些数据结构数组。这与您通常使用数组时的结构相似,只是在第一个参数之前使用了标识符号来告诉GameMaker您正在使用(以前创建的)数据结构或数组文本。

 

DS Lists [| ]DS Lists [| ] 列表

DS lists (数据结构列表) 语法为:

list_index[| index]

因此,当你使用ds_list_create创建列表时,你将使用列表索引(你已经存储在变量中)来引用它,index值是列表中要设置或添加的位置。例如,下面的代码创建一个列表,然后添加10个条目,将每个条目设置为从0到9的随机数:

ds = ds_list_create();
var index = 0;
repeat(10)
{
    ds[| index++] = irandom(9);
}

请注意,如果您使用表达式向已经有值的索引添加引用,则先前的值将被替换,而不是向列表中添加进一步的索引。要添加更多的条目,您需要知道DS列表的大小并将它们添加到末尾。同样值得注意的是,你可以设置一个列表索引,它比被引用的列表的大小,这将设置该值,同时扩展列表并将列表中的所有位置初始化为0。

创建列表结构并使用数据填充后,要从列表中获取值,可能需要类似以下内容:

value = ds[| 5];

上面的代码将从位置5(第六个索引,因为列表从0开始)获取值并将其存储在变量中。如果您提供的位置超出列表大小,则将返回值undefined,您可以使用函数is_undefined检查。

 

DS Maps [? ]DS Maps [? ] 映射

DS Maps的访问器是?,语法为:

map_index[? key]

提示键不限于字符串,可以是任何类型,包括struct

使用ds_map_create创建映射后,您将使用存储在变量中的映射索引来引用它,key值是要设置或获取的映射键。例如,下面的代码创建一个映射,然后使用以下语法向其中添加几个条目:

ds = ds_map_create();
ds[? "Name"] = "Hamish";
ds[? "Company"] = "MacSeweeny Games";
ds[? "Game"] = "Catch The Haggis";

注意如果映射已经包含与您尝试添加的键值相同的键值,则不会使用新值创建重复的键值,而是会替换先前的值。

创建地图结构并使用数据填充之后,要从特定的映射键获取值,可能会出现以下情况:

value = ds[? "Name"];

上面的代码将从键"Name"中获取值并将其存储在变量中,但要注意,如果给定的键在DS映射中不存在,则返回的值将是undefined。这可以使用函数is_undefined进行检查。

 

DS Grids [# ]DS Grids [# ] 网格

DS网格的语法为:

grid_index[# xpos, ypos]

使用ds_grid_create函数创建网格后,您将使用存储在变量中的网格索引来引用它,xposypos是网格中的位置,以获取或设置值。例如,下面的代码创建一个网格,将其清除为0,然后向其中添加几个条目:

ds = ds_grid_create();
ds_grid_clear(ds, 0);
var gw = ds_grid_width(ds) - 1;
var gh = ds_grid_height(ds) - 1;
repeat(10)
{
    var xx = irandom(gw);
    var yy = irandom(gh);
    if (ds[# xx, yy] == 0)
    {
        ds[# xx, yy] = 1;
    }
}

创建网格结构并使用数据填充之后,要从特定网格位置获取值,可能需要类似以下内容:

value = ds[# mouse_x div 16, mouse_y div 16];

上面的代码将根据鼠标位置从给定的DS网格中获取值(除以房间中的"单元格"宽度以获得正确的位置)。如果您提供的位置在网格边界之外,则将返回值undefined,您可以使用函数is_undefined检查。

 

Arrays [@ ]Arrays [@ ] 数组

此访问器仅在启用写时复制选项时使用。

数组也有自己的访问器,其工作方式与上面列出的数据结构的访问器类似。然而,数组访问器有一个有趣的属性,那就是允许你从脚本函数方法中修改一个数组,而不需要复制它。当你把一个数组传递到一个函数中时,它是通过引用传递的,这意味着数组本身并没有被赋予到脚本中,而只是被引用来获取数据。通常情况下,如果你需要改变这个数组,它将被复制到脚本中,然后你需要将复制的数组传回(返回),以更新原始数组。这可能会产生昂贵的处理开销,所以你可以使用访问器来代替,因为这将直接改变原始数组,而不需要复制它。你可以在下面的例子中看到这是如何工作的。

使用@访问器的数组的语法为:

array[@ i]

在实例中创建数组后,可以通过引用将其传递给脚本,然后使用访问器@直接更改它。例如,您可以创建数组并调用如下函数:

array[99] = 0;
array_populate(array);

函数本身具有如下内容:

function array_populate(_array)
{
    var a = _array; var i = 0; repeat(25)
    {
        i = irandom(99);
        while (a[i] != 0)
        {
            i = irandom(99);
        }
        a[@ i] = 100;
    }
}

该函数所做的就是在数组中选择25个随机位置,并将所选数组位置的值设置为100。

当然,如果禁用了"写入时复制",则不需要@访问器。

注意在脚本函数中使用参数[n]数组时,不能使用数组访问器@

 

 

Structs [$ ]Structs [$ ] 结构

结构访问器使用$符号作为标识符号。这使得结构的访问器语法为:

struct[$ "name"]

如果您使用global关键字访问全局结构,则该访问器本质上是函数variable_struct_get()variable_struct_set()以及variable_global_getvariable_global_set的包装器。

您可以像 DS 地图的访问器一样使用它。例如,如果您创建了一个结构体并希望从名为"my_health"的变量中检索值,那么您可以执行以下操作:

var _hp = struct[$ "my_health"];

如您所见,您并没有提供变量本身,而是提供了一个带有变量名称的字符串

注意 如果结构没有具有给定名称的变量,则访问器将返回 undefined 作为值。

提示 如果访问器返回的值是(或可能是) undefined ,您可能希望提供要使用的"默认"值。要做到这一点,一种简单快捷的方法是空值运算符。

要在结构中设置一个变量,你需要做以下工作

struct[$ "my_score"] = 100;

与获取值一样,提供要设置为字符串的变量的名称,并将其设置为给定的值。如果结构中不存在使用的变量名称,则将创建该变量名称并将其设置为给定值。

 

 

访问器的一个重要特征是它们可以被链接在一起。这意味着,如果您具有多个嵌套数据结构和/或数组,则不再需要使用各种函数来访问嵌套结构中的深层值。例如,假设您有一个数组,并且数组中的每个项目都是DS list,如下所示:

array = array_create(3);
for (var i = 0; i < 3; ++i;)
{
    array[i] = ds_list_create();
    switch(i)
    {
        case 0:
            with (obj_Wall) ds_list_add(array[i], id);
        break;

        case 1:
            with (obj_Door) ds_list_add(array[i], id);
        break;

        case 2:
            with (obj_Chest) ds_list_add(array[i], id);
        break;
    }
}

在上面的代码中,我们已经创建了一个3项数组,并为每个数组分配了一个DS list,然后我们用游戏中各种对象的实例ID填充了不同的列表。现在,为了访问其中一个列表中的ID,我们可以做以下工作。

var _list = array[0];
var _id = ds_list_find_value(_list, 0);

但是,你可以用更简洁的方式使用链式访问器做同样的事情,使用更少的代码:

var _id = array[0][| 0];

您可以通过这种方式将多个访问器链接在一起,它们可以是多种类型的,以访问存储在嵌套结构每个部分中的信息。以下是更多示例:

// Access a grid that has been added to a list that is part of a map:
var _a = data[? "lists"][| 0][# 0, 0];

// Access an array nested in a list from a script and modify it:
data[| 0][@ 10] = 100;

// Access a map nested in a grid nested in a list nested in an array:
data[0][| 10][# 3, 4][? "key"] = "hello world";

对事物使用链接访问器不仅意味着您可以编写更紧凑的代码,还允许您使用迭代(例如,使用for循环)和其他技术以更干净、更直观的方式访问数据。

值得注意的是,当以这种方式使用访问器时,您应该始终对数组使用@访问器,否则您将为正在执行的任何操作添加额外的开销。如上所述,默认情况下,数组通过引用传递到函数中,然后在修改时使用"写时复制"行为。但是,如果数组是链的一部分,则链中的前一项将使用复制的数组进行更新,并且"原始"项将被删除。例如,做这样的事情:

// In an object event
data[| 0][0] = 100;

// In a function
data[| 0][0] = 200;

获得与以下操作相同的结果:

// In an object event
data[| 0][0] = 100;

// In a function
data[| 0][@ 0] = 200;

但是,第二个示例更好,因为它没有先复制整个数组的不必要开销。