Evaluando expresiones

Godot proporciona una clase Expression que puedes usar para evaluar expresiones.

Una expresión puede ser:

  • Una expresión matemática como (2 + 4) * 16/4.0.

  • A boolean expression such as true && false.

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

  • A method call on a user-provided script like update_health(), if base_instance is set to a value other than null when calling Expression.execute().

Nota

La clase Expression es independiente de GDScript. Está disponible incluso si compilas Godot con el módulo GDScript desactivado.

Uso básico

To evaluate a mathematical expression, use:

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

Los siguientes operadores estan disponibles:

Operador

Notas

Adición +

Correcto, también se puede utilizar para concatenar strings y arrays: - "hello" + " world" = hello world- [1, 2] + [3, 4] = [1, 2, 3, 4]

Sustacción (-)

Multiplicación (*)

División (/)

Realiza una división entera si ambos operandos son enteros. Si al menos uno de ellos es un número de punto flotante, devuelve un valor de punto flotante.

Remainder (%)

Returns the remainder of an integer division (modulo). The result will always have the sign of the dividend.

Conjunction (&&)

Returns the result of a boolean AND.

Disjunction (||)

Returns the result of a boolean OR.

Negation (!)

Returns the result of a boolean NOT.

Los espacios alrededor de los operadores son opcionales. Además, ten en cuenta que se aplica el orden habitual de las operaciones. Utiliza paréntesis para anular el orden de las operaciones si es necesario.

Todos los tipos de variantes admitidos en Godot se pueden usar: enteros, números de punto flotante, strings, arrays, diccionarios, colores, vectores, entre otros…

Arrays and dictionaries can be indexed like in 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

Pasando variables a una expresión

You can pass variables to an expression. These variables will then become available in the expression's "context" and will be substituted when used in the expression:

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

Tanto los nombres de las variables como los valores de las variables deben especificarse como un arreglo, incluso si solo defines una variable. Además, los nombres de las variables son sensibles a mayúsculas y minúsculas.

Configurando una instancia base para la expresión

Por defecto, una expresión tiene una instancia base de null. Esto significa que la expresión no tiene ninguna instancia base asociada a ella.

When calling Expression.execute(), you can set the value of the base_instance parameter to a specific object instance such as self, another script instance or even a singleton:

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

Asociar una instancia base permite hacer lo siguiente:

  • Referenciar las constantes (const) de la instancia en la expresión.

  • Referenciar las variables miembro (var) de la instancia en la expresión.

  • Llamar a los métodos definidos en la instancia y utilizar sus valores de retorno en la expresión.

Advertencia

Establecer una instancia base con un valor distinto de null permite hacer referencia a constantes, variables miembro y llamar a todos los métodos definidos en el script adjunto a la instancia. Permitir que los usuarios ingresen expresiones puede permitir trampas en tu juego, o incluso introducir vulnerabilidades de seguridad si permites que clientes arbitrarios ejecuten expresiones en los dispositivos de otros jugadores. Por lo tanto, debes tener cuidado al permitir que los usuarios ingresen expresiones y asegurarte de validar y filtrar adecuadamente cualquier entrada para evitar posibles problemas.

Script de ejemplo

The script below demonstrates what the Expression class is capable of:

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

The output from the script will be:

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

Funciones integradas

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.

Sin embargo, a diferencia de GDScript, los parámetros siempre son requeridos, incluso si se especifican como opcionales en la referencia de clase. En contraste, esta restricción en los argumentos no se aplica a las funciones hechas por el usuario cuando se vincula una instancia base a la expresión.