求值顺序


在使用 GML 编写游戏的时候,你会注意到函数调用参数的顺序并非固定的。这也就意味着在你的代码中函数的顺序会依照平台的不同而发生变化,因此你需要以一种明确的方式来进行编写。这是不同目标平台之间的优化差异导致的,比如说在 Windows 目标平台上函数是从右到左求值的,而在 HTML5 平台上则是从左到右的。因此,为避免出现任何问题,最好不要在函数调用的参数中调用多个函数,因为它可能依赖于求值顺序。

要用一个例子说明这意味着什么,请考虑下面的代码,该代码调用多个函数并将它们用作脚本的参数:

buffer_seek(buff, buffer_seek_start, 0);
scr_buffer_get_info(buffer_read(buff, buffer_s8), buffer_read(buff, buffer_s16),buffer_read(buff, buffer_s16));

现在,问题是在某些平台上, 最后的 buffer_read 将被 第一个 调用,所以脚本的所有参数都是错误的,因为正如你所感觉的那样,以 “反向” 顺序从缓冲区读取数据。对于 buffer_read 函数,它具有影响所有其他值的连锁效应,所以传递给这个脚本的所有参数都是错误的!

为了解决这个问题你应该 明确地 按照所需顺序调用函数并将返回的值存储在变量中,如下所示:

var val[0] = buffer_read(buff, buffer_s8);
var val[1] = buffer_read(buff, buffer_s16);
var val[2] = buffer_read(buff, buffer_s16);
scr_buffer_get_info(val[0], val[1], val[2]);

虽然它看起来似乎是一种更冗长的方法,但它可以保持一切清晰,并避免求值顺序出现任何可能的问题。

在使用表达式时也应该小心,因为它们的计算顺序将根据你要编译的目标平台而改变。因此在代码中使用表达式的时候,请确保合理使用圆括号来控制运算符顺序。这对于确保游戏在所有目标平台的行为正确上非常重要,尤其 必要 的是 JavaScript平台。比如说,考虑如下代码:

a = b == c || d;

不同平台的编译器用不同的顺序执行运算,如果没有明确体现,可能会导致得出一个奇怪的结果,而影响游戏的体验。为了避免这个问题,可以用圆括号 () 将各部分分开,如下所示:

a = (b == c || d);   //较好
a = ((b == c) || d); //最好