静态变量

脚本函数方法变量的一个有趣功能是它们可以具有静态变量

静态变量在第一次调用函数时定义,并且从那时起将保持其值。它只能在原始函数内部更改,返回它只会为您提供其值的副本 - 本质上共享静态变量只能由包含它的函数更改。

警告不能在函数外部声明静态变量

要创建静态变量,您需要使用static关键字定义它,如以下简单示例所示:

counter = function()
{
    static num = 0;
    return num++;
}

上面的例子中,变量 num 是一个静态变量,所以在第一次调用函数时将被定义为 0,但之后每次调用函数时,变量的初始化都会被忽略。因此,如果你再这样调用这个函数:

repeat (10)
{
    show_debug_message(counter());
}

输出将为:

0
1
2
3
4
5
6
7
8
9

如果您没有在此处使用static关键字,则循环每次迭代的输出将仅为0,因为变量num每次都会被定义为0返回函数之前调用该函数的时间。

初始化顺序

当调用一个函数时,其静态变量首先被初始化,然后才执行函数体的其余部分。

这意味着即使在定义静态变量的那一行之前,也可以访问该静态变量,因为它已经被初始化,即使在第一次调用时也是如此:

function static_test()
{
    show_debug_message(static_variable);
    static static_variable = 1000;
}

然而,不建议这样做,如果你在静态变量的初始化行之前尝试访问它,Feather 会显示一个 GM2043 警告。

这也意味着你不能有条件地定义静态变量,因为它们在整个函数体中始终存在。例如,如果你在 if 条件块中初始化一个静态变量,那么无论条件的结果如何,它都会在顶部被初始化。

在构造函数中使用静态变量

还可以在构造函数中使用静态变量。这些函数用于创建包含函数中定义的变量的新结构。

构造函数中的静态变量只为该构造函数初始化一次,并且不会为从该构造函数生成的每个新结构复制它们。

这意味着无论从构造函数创建多少个结构,它们都将为它们拥有的每个静态变量共享相同的值

function weapon() constructor
{
    static number_of_weapons = 0;
    number_of_weapons++;
}

var _weapon1 = new weapon();
var _weapon2 = new weapon();

show_debug_message(_weapon1.number_of_weapons); // Prints 2

在上面的示例中,weapons 构造函数包含一个名为 number_of_weapons 的静态变量,该变量在其所有结构中共享。每次新调用 weapons 构造函数时,number_of_weapons 值就会增加 1。

在被调用两次之后,该变量的值变成了 2,可以从它的任何结构中读取,也可以通过编写 weapon.number_of_weapons 直接从构造函数中读取。

父子构造函数中的静态

一般来说,静态变量的作用域为您定义它们的函数。在构造函数的层次结构中,静态变量的作用域为您使用static关键字定义它的构造函数:

function item() constructor
{
    static number = 0;
}
function weapon() : item() constructor
{
    static types = ["sword", "bow", "hammer"];
}

my_weapon = new weapon();

这里,静态变量number属于item,静态变量types属于weapon

您可以通过从weapon创建的结构访问这两个静态变量:

show_debug_message(my_weapon.number); // 0
show_debug_message(my_weapon.types);  // ["sword", "bow", "hammer"]

注意在更复杂的构造函数层次结构中,您可能需要遍历静态链

初始化顺序

当在构造函数中使用继承时,子构造函数中的任何静态变量只有在父构造函数完全执行完后才会被初始化。请参见以下示例:

function parent() constructor
{
    static value = 10;
    show_debug_message(value);
}

function child() : parent() constructor
{
    static value = 20;
    show_debug_message(value);
}

var _child = new child();

调用 child() 构造函数会将以下内容打印到输出日志:

10
20

第一个值来自父构造函数,第二个值来自子构造函数。这表明子对象的静态变量value直到父构造函数完成后才初始化。

访问静态变量

您可以使用 <function_name>.<static_variable> 语法读取函数的静态值。

比方说,对于一个名为 count 的函数,您有一个静态变量 count。您可以在它的第一次调用之后输入 counter.count 来访问它。

function counter() {
    static count = 0;
    return count ++;
}

repeat (10) 
{
    counter()
}

show_debug_message(counter.count);

警告您无法从从未调用过的函数访问静态变量,因为静态变量是在第一次调用函数时初始化的。尝试这样做将会出现错误并导致游戏崩溃。

对于构造函数,可以直接从构造函数访问静态变量,也可以从构造函数创建的任何结构访问静态变量:

function weapon() constructor
{
    static number_of_weapons = 0;
    number_of_weapons ++;
}

var _weapon1 = new weapon();
var _weapon2 = new weapon();

show_debug_message(weapon.number_of_weapons);   // Accessing from constructor directly
show_debug_message(_weapon1.number_of_weapons); // Accessing from a struct
show_debug_message(_weapon2.number_of_weapons); // Accessing from a struct

上面的所有三个 show_debug_message() 调用都将打印相同的值,因为它们读取的是完全相同的变量。

就像使用常规函数一样,如果构造函数从未被调用过,则不能从该构造函数访问该静态变量。

静态结构

属于一个函数的所有静态变量都存储在一个结构中,您可以使用 static_get 检索该结构。您可以使用 static_set 修改函数的静态结构以更改其拥有的静态变量,但此函数仅用于反序列化目的的结构。

静态结构主要用于从构造函数创建的结构。请参阅:静态结构

静态方法

你也可以在一个函数中使用static关键字来创建一个static函数,这和变量一样,只是意味着该函数只被定义一次,也就是第一次调用该函数的时候,例如。

function(_x, _y) Vector2 constructor
{
    x = _x;
    y = _y;

    static Add = function( _other )
    {
        x += _other.x;
        y += _other.y;
    }
}

在上面的例子中,构造函数 Vector2可以用来创建一个结构体,该结构体将有一些变量,其中一个是方法变量Add。由于这个变量被定义为静态的,它所包含的函数只会在第一次调用Vector2函数时被初始化一次,并且用这个构造函数创建的所有其他结构将引用最初创建的函数Add,而不是为每个结构创建一个新函数(有关结构和构造函数关键字的更多信息,请参阅结构 & 构造函数)。