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
Refclass as the foundation for various data types - Supports serialization and deserialization
- Automatic type conversion and checking
- Provides
signalfor 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 checkingThe 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 TextThe 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 WorldRefer 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
@exportto export properties, numerousRefproperties 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,
ReactiveResourcecan be transformed directly using built-in functions without additional operations. - When you want to use
RefDictionary, you can useReactiveResourceinstead, 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.