Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

表达式估值

Godot 提供了 Expression 类,可以用来对表达式进行估值。

表达式可以是:

  • 类似 (2 + 4) * 16/4.0 的数学表达式。

  • A built-in method call like deg_to_rad(90).

  • 调用 Expression.execute() 时如果 base_instancenull,那么调用用户提供脚本的方法,比如 update_health()

备注

Expression 类是独立于 GDScript 的。即便禁用 GDScript 模块编译 Godot 也能使用。

基本用法

要对数学表达式求值,请使用:

var expression = Expression.new()
expression.parse("20 + 10*2 - 5/2.0")
var result = expression.execute()
print(result)  # 37.5

可以使用以下操作符:

操作符

注意

+

还可以用于连接字符串和数组:- "hello" + " world" = hello world - [1, 2] + [3, 4] = [1, 2, 3, 4]

减(-

乘(*

除(/

两个操作数都是整数时执行整数除法。如果至少有一个是浮点数,就会返回浮点值。

求余(%

返回整数除法的余数。

操作符周围的空格是可选的。另外请记住,此处适用一般的运算次序。必要时请使用括号来覆盖运算符的次序。

Godot 所支持的所有 Variant 类型都可以使用:整数、浮点数、字符串、数组、字典、颜色、向量……

数组与字典的索引方法与 GDScript 一致:

# Returns 1.
[1, 2][0]

# Returns 3. Negative indices can be used to count from the end of the array.
[1, 3][-1]

# Returns "green".
{"favorite_color": "green"}["favorite_color"]

# All 3 lines below return 7.0 (Vector3 is floating-point).
Vector3(5, 6, 7)[2]
Vector3(5, 6, 7)["z"]
Vector3(5, 6, 7).z

向表达式传递变量

你可以将变量传入表达式。这些变量就会进入这个表达式的“上下文”,在表达式中使用就会被替换:

var expression = Expression.new()
# Define the variable names first in the second parameter of `parse()`.
# In this example, we use `x` for the variable name.
expression.parse("20 + 2 * x", ["x"])
# Then define the variable values in the first parameter of `execute()`.
# Here, `x` is assigned the integer value 5.
var result = expression.execute([5])
print(result)  # 30

变量的名称和变量的值都必须以数组的形式指定,即便只定义一个变量也是如此。而且,变量名是大小写敏感的。

为表达式设置基础实例

表达式默认的基础实例是 null。这意味着该表达式没有关联基础实例。

调用 Expression.execute() 时,你可以将参数 base_instance 的值设为 self、另一个脚本实例、单例等特定对象的实例:

func double(number):
    return number * 2


func _ready():
    var expression = Expression.new()
    expression.parse("double(10)")

    # This won't work since we're not passing the current script as the base instance.
    var result = expression.execute([], null)
    print(result)  # null

    # This will work since we're passing the current script (i.e. self)
    # as the base instance.
    result = expression.execute([], self)
    print(result)  # 20

关联基础实例可以实现以下功能:

  • 在表达式中引用实例的常量(const)。

  • 在表达式中引用实例的成员变量(var)。

  • 在表达式中调用定义在实例上的方法,并使用其返回值。

警告

将基础实例设为非 null 值,就可以引用常量、成员变量、调用定义在该实例的附加脚本中的方法。允许用户输入表达式可能会导致在你的游戏出现作弊,如果你允许任意客户的在其他玩家的设备上运行表达式的话,甚至还可能引入安全隐患。

示例脚本

下面的脚本演示的是 Expression 类的功能:

const DAYS_IN_YEAR = 365
var script_member_variable = 1000


func _ready():
    # Constant mathexpression.
    evaluate("2 + 2")
    # Math expression with variables.
    evaluate("x + y", ["x", "y"], [60, 100])

    # Call built-in method (built-in math function call).
    evaluate("deg_to_rad(90)")

    # Call user method (defined in the script).
    # We can do this because the expression execution is bound to `self`
    # in the `evaluate()` method.
    # Since this user method returns a value, we can use it in math expressions.
    evaluate("call_me() + DAYS_IN_YEAR + script_member_variable")
    evaluate("call_me(42)")
    evaluate("call_me('some string')")


func evaluate(command, variable_names = [], variable_values = []) -> void:
    var expression = Expression.new()
    var error = expression.parse(command, variable_names)
    if error != OK:
        push_error(expression.get_error_text())
        return

    var result = expression.execute(variable_values, self)

    if not expression.has_execute_failed():
        print(str(result))


func call_me(argument = null):
    print("\nYou called 'call_me()' in the expression text.")
    if argument:
        print("Argument passed: %s" % argument)

    # The method's return value is also the expression's return value.
    return 0

脚本的输出将会是:

4
160
1.5707963267949

You called 'call_me()' in the expression text.
1365

You called 'call_me()' in the expression text.
Argument passed: 42
0

You called 'call_me()' in the expression text.
Argument passed: some string
0

内置函数

All methods in the Global Scope are available in the Expression class, even if no base instance is bound to the expression. The same parameters and return types are available.

然而,与 GDScript 不同,参数始终是必须的,即使类参考中说明此参数为可选。不过,为表达式绑定了基础实例时,用户定义函数的参数没有此限制。