💾 Archived View for devlog.thermokar.st › 2022-04-13.gmi captured on 2023-09-08 at 15:54:21. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-03-20)
-=-=-=-=-=-=-
Godot experiments
Playing around with ways to avoid the "editable children" pitfall in godot. Stay tuned.
Node tree for our custom node called "Thing":
Thing ├── Area2D │ └── CollisionShape2D └── Sprite
"Thing.gd":
tool extends Node2D export var sprite: Texture = null setget set_sprite export var collision_shape: Shape2D = null setget set_collision_shape onready var _sprite: Sprite = $Sprite onready var _collision_shape: CollisionShape2D = $Area2D/CollisionShape2D func _get_configuration_warning() -> String: var warnings = [] if sprite == null: warnings.append("missing sprite") if collision_shape == null: warnings.append("missing collision_shape") return PoolStringArray(warnings).join("; ") func set_sprite(value: Texture) -> void: sprite = value if not is_inside_tree(): yield(self, "ready") if _sprite != null: _sprite.texture = sprite func set_collision_shape(value: Shape2D) -> void: collision_shape = value if not is_inside_tree(): yield(self, "ready") if _collision_shape != null: _collision_shape.shape = collision_shape
The idea here is to encapsulate all of the "wiring" by exposing the public attributes as exported variables. In this case, two elements: the sprite texture (`Sprite`), as well as a collision box (`Area2D`, which requires some kind of `CollisionShape`-esque child).
A brief tour:
tool
This is necessary for running the script in the editor (which allows for live updates).
Godot docs: running code in the editor
export var ...
This allows for assigning instance variables via the editor UI.
func _get_configuration_warning(): -> String:
This allows for displaying a warning (in the editor and the console), basically I'm using it here to define required attrs.
Godot docs: _get_configuration_warning
The setter functions for the `sprite` and `collision_shape` attributes allows us to wire the custom nodes attributes into the private children, as necessary. One little "gotcha" here, the `yield` business is for handing the case when the setter is called during initial construction of the node, otherwise the wiring never actually happens. The `yield` lets us pause execution until the `ready` signal has fired, letting us know the base node has entered the editor tree.
I've got a few places I want to get some real-world practice with this particular pattern, so stay tuned for more info.
© 2023 Matthew Ryan Dillon