Skip to main content

Unboxed Arguments

Unboxed arguments is a default-enabled property on a Sandbox node. It makes function calls into the Sandbox unwrap Variant arguments into primitive types or class wrappers when available. These class wrappers aim to provide the functionality of both GDScript and godot-cpp when it makes sense to do so.

Conversion table

When making a function call into a Sandbox program, sandbox.vmcall("my_function", ...) or sandbox.my_function(...), the arguments will translate into the column on the right:

VariantGDScript func argumentUnboxed type
NILnullN/A
BOOLtrue / falsebool
INT1234int, long
FLOAT5678.0double
STRING"Hello World!"String
VECTOR2Vector2(1, 2)Vector2
VECTOR2iVector2i(1, 2)Vector2i
VECTOR3Vector3(1, 2, 3)Vector3
VECTOR3iVector3i(1, 2, 3)Vector3i
TRANSFORM2DTransform2D(...)Transform2D
VECTOR4Vector4(1, 2, 3, 4)Vector4
VECTOR4iVector4i(1, 2, 3, 4)Vector4i
PLANEPlane(...)Plane
QUATERNIONQuaternion(...)Quaternion
AABBAABB(...)Variant
BASISBasis(...)Basis
TRANSFORM3DTransform3D(...)Transform3D
PROJECTIONProjection(...)Variant
COLORColor(...)Color
STRING_NAMEStringName(...)String
NODE_PATHNodePath(...)String
RIDRID()RID
OBJECTObject
CALLABLECallable
SIGNALVariant
DICTIONARYDictionary(...)Dictionary
ARRAYArray(...)Array
Packed ArrayGDScript func argumentUnboxed type
PACKED_BYTE_ARRAYPackedByteArray(...)PackedArray<uint8_t>
PACKED_INT32_ARRAYPackedInt32Array(...)PackedArray<int32_t>
PACKED_INT64_ARRAYPackedInt64Array(...)PackedArray<int64_t>
PACKED_FLOAT32_ARRAYPackedFloat32Array(...)PackedArray<float>
PACKED_FLOAT64_ARRAYPackedFloat64Array(...)PackedArray<double>
PACKED_STRING_ARRAYPackedStringArray(...)PackedArray<std::string>
PACKED_VECTOR2_ARRAYPackedVector2Array(...)PackedArray<Vector2>
PACKED_VECTOR3_ARRAYPackedVector3Array(...)PackedArray<Vector3>
PACKED_COLOR_ARRAYPackedColorArray(...)PackedArray<Color>

An astute reader will notice that whenever a wrapper class is not yet implemented, the Variant type is passed unchanged, as a Variant. Variants can use calls, and so even though many are already implemented as wrapper classes, here is an example of how to use any class through a Variant:

Variant plane = ...;
float distance = plane("distance_to", Vector3(1, 2, 3));

Variant quaternion = ...;
quaternion = quaternion("inverse");

And when there is a wrapper, it's designed to be passed by value as a function argument:

Variant my_plane(Plane p) {
return p.distance_to(Vector3(1, 2, 3));
}

Variant my_quaternion(Quaternion q) {
return q.inverse();
}
note

Sandboxed properties does NOT use unboxed arguments. All arguments and the return type are Variants. Function return values are always Variant.

Conversion table (Objects)

ClassGodot Sandbox API
ObjectObject
NodeNode
Node2DNode2D
Node3DNode3D

Nodes inherit from Object.

See the API sugaring documentation to see how to add your own wrapper classes.

Example function calls

A player node

func gdscript():
sandbox.vmcall("handle_player", get_node("Player"))

Which we can choose to receive as a Node2D (or Node or Object) in the Sandbox program:

extern "C" Variant handle_player_physics(CharacterBody2D player, double delta) {

Input input = Input::get_singleton();

// Handle jump.
Vector2 velocity = player.velocity();
if (input.is_action_just_pressed("jump") && player.is_on_floor())
velocity.y = jump_velocity;

// Get the input direction and handle the movement/deceleration.
float direction = input.get_axis("move_left", "move_right");
if (direction != 0)
velocity.x = direction * player_speed;
else
velocity.x = fmin(velocity.x, player_speed);
player.set_velocity(velocity);

return player.move_and_slide();
}

Since the Player node is a CharacterBody2D, we can use functions from it.

Inputs

We can handle inputs with _input directly, which passes an Object of some kind of Input-derivative as the first argument:

extern "C" Variant _input(InputEvent event) {
if (event.is_action_pressed("jump")) {
get_node().set("modulate", 0xFF6060FF);
} else if (event.is_action_released("jump")) {
get_node().set("modulate", 0xFFFFFFFF);
}
return Nil;
}

The above example modulates the current node based on the jump action. We know the functions provided by InputEvent from reading the Godot documentation on InputEvent. The current Node is our Node2D coin, and it can be modulated. We could cast it to a Node2D and do a Node2D(get_node()).set_modulate(0xFF6060FF);, but it was just easier to set the property using .set().

note

All Sandbox functions must return a Variant.