Open ZenithStar opened 9 months ago
I think this could be built on top of metadata (get_meta
, get_meta_list
, has_meta
, remove_meta
, set_meta
), you would to specify the type, have an updated callback, and syntactic sugar.
I think this could be built on top of metadata (
get_meta
,get_meta_list
,has_meta
,remove_meta
,set_meta
), you would to specify the type, have an updated callback, and syntactic sugar.
Yes. Someone else also informed me that I should be using metadata for this purpose. I had glossed over it before because I was under the impression it was editor only, but I had misread that. I refactored some of my project using metadata and this weakly typed Property
wrapper, and it turned out quite a bit cleaner.
class_name Property extends RefCounted
signal changed
var _value
var value:
get:
return _getter.call()
set(value):
return _setter.call(value)
var _getter: Callable
var _setter: Callable
func _default_get():
return _value
func _default_set(new_value):
if _value != new_value:
_value = new_value
changed.emit()
func _init(fget=_default_get, fset=_default_set):
_getter = fget
_setter = fset
An example from the usage side:
if not get_parent().has_meta("focus_target"):
get_parent().set_meta("focus_target", Property.new())
_target_property = get_parent().get_meta("focus_target")
_target_property.changed.connect(_on_target_changed)
_target_property.value = anything
This honestly isn't much worse than my worst case boilerplate that I wrote in my first post and comes with the advantages of being a Variant container, making it nullable https://github.com/godotengine/godot-proposals/issues/162 and able to directly use a Node reference, rather than a NodePath, since Variant.Type only includes NodePath.
Describe the project you are working on
I'm working on two main games at the moment, with a few potential side projects that all use similar systems. Of the main projects, one is turn-based tactics and one is real-time adventure, but they share many overlapping features (both 3D with the same art style animation and many of the same control schemes). Therefore, I am trying to write my game's logic as modular and reusable as possible. In the future if there is enough interest, I would also like to release parts of my framework as addons.
Describe the problem or limitation you are having in your project
GDScript describes itself as a dynamic language that leans towards a duck-typing philosophy. For implementing functionality following this philosophy, I have found
Object.add_user_signal
to be an incredibly powerful tool. This is perfect for dispatching one-shot events, but isn't sufficient when state is involved. One way to handle this would be to triggeruser_property_updated
signals each time state is updated and have each listener component maintain its own memory of the state. However, what about the case that a new component attaches itself to the entity and needs to know the last known state for this user property? The last known state still needs to be recorded somewhere. In dynamic languages like python and JavaScript, you can easily achieve this by dynamically creating new properties attached to the instance of a object, rather than the class itself.Describe the feature / enhancement and how it helps to overcome the problem or limitation
Currently, I've implemented this feature in my own project as a child component Node that needs to be added to any entity parent that needs this functionality.
To use this functionality, the very boilerplate syntax looks like:
Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams
Here's a few idealized implementations in order of increasing boilerplate
If this enhancement will not be used often, can it be worked around with a few lines of script?
For more complex projects, I believe this function will see frequent usage. I've posted my current workaround above, and I believe it exceeds "a few lines of script".
Is there a reason why this should be core and not an add-on in the asset library?
This requires adding functionality to the base Object class.