Оценка выражений

Godot предоставляет класс Expression, который можно использовать для оценки выражений.

Выражение может быть:

  • Математическое выражение, такое как (2 + 4) * 16/4.0.

  • Булевое выражение, такое как true && false.

  • Встроенный вызов метода типа deg_to_rad(90).

  • Вызов метода в предоставленном пользователем скрипте, таком как update_health(), если base_instance установлено на значение, отличное от null при вызове Expression.execute().

Примечание

Класс Expression независим от GDScript. Он доступен даже при компиляции Godot с отключённым модулем GDScript.

Базовое использование

Для оценки математического выражения используйте:

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]

Вычитание (-)

Умножение (*)

Деление (/)

Выполняет целочисленное деление, если оба операнда — целые числа. Если хотя бы один из них — число с плавающей точкой, возвращает значение с плавающей точкой.

Остаток (%)

Возвращает остаток от деления целого числа (по модулю). Результат всегда будет иметь знак делимого.

Союз (&&)

Возвращает результат boolean AND (И).

Дизъюнкция (||)

Возвращает результат boolean OR (ИЛИ).

Отрицание (!)

Возвращает результат boolean NOT (НЕ).

Пробелы вокруг операторов необязательны. Также помните, что действует обычный порядок выполнения операций. При необходимости используйте скобки, чтобы переопределить порядок выполнения операций.

Можно использовать все типы Variant, поддерживаемые в Godot: целые числа (integers), числа с плавающей точкой (floating-point numbers), строки (strings), массивы (arrays), словари (dictionaries), цвета (colors), векторы (vectors), …

Массивы и словари можно индексировать как в 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 boolean expression.
    evaluate("true && false")
    # Boolean expression with variables.
    evaluate("!(a && b)", ["a", "b"], [true, false])

    # 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

Вывод скрипта будет следующим:

false
true
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

Встроенные функции

Все методы в Global Scope доступны в классе Expression, даже если к выражению не привязан ни один базовый экземпляр. Доступны те же параметры и типы возвращаемых значений.

Однако, в отличие от GDScript, параметры всегда обязательны, даже если они указаны как необязательные в ссылке на класс. В отличие от этого, это ограничение на аргументы не распространяется на пользовательские функции при привязке базового экземпляра к выражению.