mirror of
https://github.com/godotengine/godot-docs.git
synced 2026-01-04 14:11:02 +03:00
Add a page on evaluating expressions using the Expression class
This is a 3.4 backport (with identical contents) of the `master` branch page, with fixes included.
This commit is contained in:
208
tutorials/scripting/evaluating_expressions.rst
Normal file
208
tutorials/scripting/evaluating_expressions.rst
Normal file
@@ -0,0 +1,208 @@
|
||||
.. _doc_evaluating_expressions:
|
||||
|
||||
Evaluating expressions
|
||||
======================
|
||||
|
||||
Godot provides an :ref:`class_Expression` class you can use to evaluate expressions.
|
||||
|
||||
An expression can be:
|
||||
|
||||
- A mathematical expression such as ``(2 + 4) * 16/4.0``.
|
||||
- A built-in method call like ``deg2rad(90)``.
|
||||
- A method call on an user-provided script like ``update_health()``,
|
||||
if ``base_instance`` is set to a value other than ``null`` when calling
|
||||
:ref:`Expression.execute() <class_Expression_method_execute>`.
|
||||
|
||||
.. note::
|
||||
|
||||
The Expression class is independent from GDScript.
|
||||
It's available even if you compile Godot with the GDScript module disabled.
|
||||
|
||||
Basic usage
|
||||
-----------
|
||||
|
||||
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
|
||||
|
||||
The following operators are available:
|
||||
|
||||
+------------------------+-------------------------------------------------------------------------------------+
|
||||
| Operator | Notes |
|
||||
+========================+=====================================================================================+
|
||||
| Addition ``+`` | Can also be used to concatenate strings and arrays: |
|
||||
| | - ``"hello" + " world"`` = ``hello world`` |
|
||||
| | - ``[1, 2] + [3, 4]`` = ``[1, 2, 3, 4]`` |
|
||||
+------------------------+-------------------------------------------------------------------------------------+
|
||||
| Subtraction (``-``) | |
|
||||
+------------------------+-------------------------------------------------------------------------------------+
|
||||
| Multiplication (``*``) | |
|
||||
+------------------------+-------------------------------------------------------------------------------------+
|
||||
| Division (``/``) | Performs and integer division if both operands are integers. |
|
||||
| | If at least one of them is a floating-point number, returns a floating-point value. |
|
||||
+------------------------+-------------------------------------------------------------------------------------+
|
||||
| Modulo (``%``) | Returns the remainder of an integer division. |
|
||||
+------------------------+-------------------------------------------------------------------------------------+
|
||||
|
||||
Spaces around operators are optional. Also, keep in mind the usual
|
||||
`order of operations <https://en.wikipedia.org/wiki/Order_of_operations>`__
|
||||
applies. Use parentheses to override the order of operations if needed.
|
||||
|
||||
All the Variant types supported in Godot can be used: integers, floating-point
|
||||
numbers, strings, arrays, dictionaries, colors, vectors, …
|
||||
|
||||
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
|
||||
|
||||
Passing variables to an expression
|
||||
----------------------------------
|
||||
|
||||
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
|
||||
|
||||
Both the variable names and variable values **must** be specified as an array,
|
||||
even if you only define one variable. Also, variable names are **case-sensitive**.
|
||||
|
||||
Setting a base instance for the expression
|
||||
------------------------------------------
|
||||
|
||||
By default, an expression has a base instance of ``null``. This means the
|
||||
expression has no base instance associated to it.
|
||||
|
||||
When calling :ref:`Expression.execute() <class_Expression_method_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
|
||||
|
||||
Associating a base instance allows doing the following:
|
||||
|
||||
- Reference the instance's constants (``const``) in the expression.
|
||||
- Reference the instance's member variables (``var``) in the expression.
|
||||
- Call methods defined in the instance and use their return values in the expression.
|
||||
|
||||
.. warning::
|
||||
|
||||
Setting a base instance to a value other than ``null`` allows referencing
|
||||
constants, member variables, and calling all methods defined in the script
|
||||
attached to the instance. Allowing users to enter expressions may allow
|
||||
cheating in your game, or may even introduce security vulnerabilities if you
|
||||
allow arbitrary clients to run expressions on other players' devices.
|
||||
|
||||
Example script
|
||||
--------------
|
||||
|
||||
The script below demonstrates what the Expression class is capable of::
|
||||
|
||||
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 (hardcoded in the Expression class).
|
||||
evaluate("deg2rad(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::
|
||||
|
||||
4
|
||||
160
|
||||
1.570796
|
||||
|
||||
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
|
||||
|
||||
Built-in functions
|
||||
------------------
|
||||
|
||||
Most methods available in the :ref:`class_@GDScript` 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.
|
||||
|
||||
However, unlike GDScript, parameters are **always required** even if they're
|
||||
specified as being optional in the class reference. In contrast, this
|
||||
restriction on arguments doesn't apply to user-made functions when you bind a
|
||||
base instance to the expression.
|
||||
@@ -43,6 +43,7 @@ below will help you make the most of Godot.
|
||||
overridable_functions
|
||||
cross_language_scripting
|
||||
creating_script_templates
|
||||
evaluating_expressions
|
||||
change_scenes_manually
|
||||
instancing_with_signals
|
||||
pausing_games
|
||||
|
||||
Reference in New Issue
Block a user