English | 简体中文
Note
Bindora is currently in the development stage and the API is subject to change, so please use it with caution.
Bindora is a reactive data binding library for Godot 4.4. Based on Godot's design philosophy, it provides a declarative and component-based approach to help you manage relationships between nodes and data.
- Provide the
Ref
class as the foundation for various data types - Supports serialization and deserialization
- Automatic type conversion and checking
- Provides
signal
for data monitoring
TextBinding
、InputBinding
、RadioBinding
、CheckBoxBinding
、PropertyBinding
、VisibleBinding
、ShaderBinding
、ToggleBinding
、ListBinding
、ThemeOverrideBinding
、CustomBinding
Copy the bindora
folder into your Godot project.
Create a Label
node and set its text
to "Text is {{value}}"
. Then add a script to the node with the following code:
extends Label
# Declare data
var text_ref = RefString.new("Hello World")
# Create text binding
text_ref.bind_text(self)
# Create a watcher
text_ref.value_updated.connect(func(old_value,new_value):
print("Text changed to: ", new_value)
)
# Modify data
text_ref.value = "New Text"
# Or
text_ref.set_value("New Text") # Using set_value is recommended as it includes type checking
The Ref
class provides many convenient binding methods, which you can explore in the API Reference.
When you need more complex data binding, you can directly use Binding
.
extends Label
var text_ref = RefString.new("Hello")
var text_ref2 = RefString.new("World")
func _ready():->void:
var binding = TextBinding.new(self, {"value": text_ref, "value2": text_ref2}, "Text is {{value}} {{value2}}")
Create a resource class that extends ReactiveResource
and declare Ref
variables within it.
Note
Ref
variables declared in ReactiveResource
do not need to be exported with @export
. They are automatically handled and exported upon declaration. Using @export
may cause unexpected errors.
class MyResource extends ReactiveResource
var text_ref = RefString.new("Hello World")
Using with RefArray
.
var packed_scene = preload("res://path/to/your/packed_scene.tscn")
var array = RefArray.new()
array.bind_list($Container, packed_scene, func(item, data , index):
data.text_ref.bind_text(item)
)
for i in 3:
var new_item = MyResource.new()
new_item.text_ref.set_value("Item " + i)
array.append(new_item)
The ReactiveResource
class provides serialization and deserialization functionality. You can use to_dictionary
to convert it to a dictionary, or use from_dictionary
to update values from a dictionary.
var resource = MyResource.new()
var dict = resource.to_dictionary()
dict["text_ref"] = "New Text"
resource.from_dictionary(dict)
print(resource.text_ref.value) # New Text
The ReactiveResource
class also provides static serialization and deserialization methods, which can be used as follows:
var resource = MyResource.new()
resource.text_ref.set_value("Hello World")
var dict = ReactiveResource.serialize(resource)
var new_resource = ReactiveResource.reactive(dict,MyResource)
print(new_resource.text_ref.value) # Hello World
Refer to the examples in the test
folder.
Choose appropriate Ref
types for your data, such as RefString
, RefInt
, etc. Avoid directly using Ref
or other base classes to create variables.
Try to avoid using .value
to manipulate values, as it lacks type checking in the editor and may only report errors during runtime. Instead, use set_value()
and get_value()
functions which perform type checking at the editor stage.
Binding
will automatically recognize whether the node exists and recycle it. If you need to manually recycle it, you can use the destroy()
method.
For most cases, using Ref
will suffice. However, in some cases, using ReactiveResource
can provide better performance. Here are a few examples:
- When using
@export
to export properties, numerousRef
properties can make the inspector complex and unintuitive (because exported properties are wrapped).ReactiveResource
's automatic export feature can avoid this situation. - For content that needs serialization and deserialization,
ReactiveResource
can be transformed directly using built-in functions without additional operations. - When you want to use
RefDictionary
, you can useReactiveResource
instead, as it provides better type checking and autocomplete.
# Recommended
class MyResource extends ReactiveResource
var text_ref = RefString.new("Hello World")
var number_ref = RefInt.new(1)
# Optional
class MyResource extends Resource
@export var text_ref = RefString.new("Hello World")
@export var number_ref = RefInt.new(1)
# Not recommended
extends Node
var dict_ref = RefDictionary.new({"text": "Hello World", "number": 1})
Basic Variable Types - RefVariant
RefBool
, RefInt
, RefFloat
, RefString
, RefVector2
, RefVector2i
, RefVector3
, RefVector3i
, RefVector4
, RefVector4i
, RefRect2
, RefRect2i
, RefColor
Binding methods:
- bind_text(_node: CanvasItem, _keyword: String = "value",_template: String = "") -> TextBinding
- bind_input(_node: CanvasItem, _property: String = "") -> InputBinding
- bind_multi_input(_dict: Dictionary[CanvasItem, String]) -> Dictionary[CanvasItem, InputBinding]
- bind_property(_node: CanvasItem, _property: String, _use_node_data: bool = false) -> PropertyBinding
- bind_multi_property(_dict: Dictionary[CanvasItem, String]) -> Dictionary[CanvasItem, PropertyBinding]
- bind_radios(_nodes: Array[CanvasItem]) -> Dictionary[CanvasItem, RadioBinding]
- bind_radios_custom(_dict: Dictionary[CanvasItem, String]) -> Dictionary[CanvasItem, RadioBinding]
- bind_shader(_node: CanvasItem, _property: String) -> ShaderBinding
- bind_visible(_node: CanvasItem, _condition: Callable | Ref) -> VisibleBinding
- bind_theme_override(_node: CanvasItem, _property: String) -> ThemeOverrideBinding
- bind_toggle(_node: CanvasItem, _opposite: bool = false) -> ToggleBinding
- bind_multi_toggle(_dict: Dictionary[CanvasItem, bool]) -> Dictionary[CanvasItem, ToggleBinding]
- bind_custom(_node: CanvasItem, _callable: Callable) -> CustomBinding
- bind_text(_node: CanvasItem, _keyword: String = "value", _template: String = "") -> TextBinding
- bind_check_boxes(_nodes: Array[CanvasItem]) -> Dictionary[CanvasItem, CheckBoxBinding]
- bind_check_boxes_custom(_dict: Dictionary[CanvasItem, String]) -> Dictionary[CanvasItem, CheckBoxBinding]
- bind_list(_parent: Node, _packed_scene: PackedScene, _callable: Callable) -> ListBinding
- bind_text(_node: CanvasItem, _template: String = "") -> TextBinding
Resource Types - RefResource
RefFont
, RefLabelSettings
, RefMaterial
, RefStyleBox
, RefTexture
If you encounter any issues or have suggestions for improvements, feel free to open an issue or submit a pull request.
Bindora is an open-source project under the MIT license.