观察者 (Observer) 入门

观察者 是一种监听原版数据,并同步到数据节点的 关系

观察者观察目标对象的某个属性或者子节点,当观察对象发生改变, 并且向观察者发送信号通知改变时,观察者会读取被观察对象的数据,写入关联的数据节点。

所以一个观察者有三个基本要素,源数据、目标数据节点、改变信号。

改变信号是一个无参数信号。

观察者默认有四种类型,都继承自观察者基类 Observer

属性型(Property)

ObserverProperty

属性型只监听一个属性,既支持基础数据类型,也支持对象、字典和数组类型。

下面这个例子就是用一个DataNodeVariant来监听一个TestObj的 a 属性。

signal changed

class TestObj:
  var a: int

# ...

func _ready():
  var source_obj := TestObj.new()
  var target_data_node := DataNodeVariant.new(null)
  prints(target_data_node.value()) # null
  var _observer := ObserverProperty.new(source_obj, ^"a", target_data_node, changed)

  source_obj.a = 1
  changed.emit()
  prints(target_data_node.value()) # 1

监听的是对象时,属性监听的值是对这个对象引用的改变。

如果监听的属性留空,则监听的是这个对象本身,同步数据就是将对象本身渲染到目标数据节点上。

func _ready():
  var source_obj := TestObj.new()
  var target_data_node := DataNodeStruct.new()
  target_data_node.add_property("a", DataNodeInt.new(0))
  prints(target_data_node.value()) # {"a": 0}
  var _observer := ObserverProperty.new(source_obj, ^"", target_data_node, changed)

  source_obj.a = 1
  changed.emit()
  await get_tree().process_frame # Struct updates asynchronously
  prints(target_data_node.value()) # {"a": 1}

如果监听的数组和字典的元素不需要加监听者,也用属性型来监听。

signal changed
class ObjWithArray:
  var array: Array

func _ready():
  var source_obj := ObjWithArray.new()
  var target_data_node := DataNodeList.new(TYPE_INT, func(): return DataNodeInt.new(0))
  prints(target_data_node.value()) # []
  var _observer := ObserverProperty.new(source_obj, ^"array", target_data_node, changed)

  source_obj.array = [1, 2, 3]
  changed.emit()
  prints(target_data_node.value()) # [1, 2, 3]

这一般用于数组的元素以及字典的值不是对象时。如果是对象,应该用下面两种。

属性数组型(PropertyArray)

ObserverPropertyArray

监听对象的数组属性,这会为数组的每一个元素创建对应的子观察者。

signal changed

class TestList:
  var test_array: Array[TestObj]

class TestObj:
  signal changed
  var a: int:
    set(value):
      a = value
      changed.emit()

func _ready():
  var source_obj := TestList.new()
  var target_data_node := DataNodeList.new(TYPE_INT, func(): return DataNodeInt.new(0))
  var _observer := ObserverPropertyArray.new(
    source_obj,
    ^":test_array",
    target_data_node,
    changed,
    func(source_element: Object, target_element: DataNode) -> Array:
      return [ObserverProperty.new(source_element, ^":a", target_element, source_element.changed)]
  )
  prints(target_data_node.size()) # 0
  var foo_element := TestObj.new()
  source_obj.test_array.append(foo_element)
  changed.emit()
  await get_tree().process_frame # 异步,等一帧
  prints(target_data_node.value()) # [0]
  prints(target_data_node.size()) # 1
  foo_element.a = 1
  await get_tree().process_frame # 异步,等一帧
  prints(target_data_node.value()) # [1]

属性字典型(PropertyDictionary)

ObserverPropertyDictionary

监听对象的字典属性,这会为字典的每一个值创建对应的子观察者。

signal changed

class TestDict:
  var test_dictionary: Dictionary[StringName, TestObj]

class TestObj:
  signal changed
  var a: int:
    set(value):
      a = value
      changed.emit()

func _ready() -> void:
  var source_obj := TestDict.new()
  var target_data_node := DataNodeDict.new(TYPE_STRING_NAME, TYPE_INT, func(): return DataNodeInt.new(0))
  var _observer := ObserverPropertyDictionary.new(
    source_obj,
    ^":test_dictionary",
    target_data_node,
    changed,
    func(source_element: Object, target_element: DataNode) -> Array:
      return [ObserverProperty.new(source_element, ^":a", target_element, source_element.changed)]
  )
  prints(target_data_node.size()) # 0
  var foo_element := TestObj.new()
  source_obj.test_dictionary["new_element"] = foo_element
  changed.emit()
  await get_tree().process_frame # 异步,等一帧
  prints(target_data_node.value()) # {&"new_element": 0}
  prints(target_data_node.size()) # 1
  foo_element.a = 1
  await get_tree().process_frame # 异步,等一帧
  prints(target_data_node.value()) # {&"new_element": 1}

节点型(Node)

ObserverNode

监听节点的子节点,会为每一个子节点创建观察者。

因为节点自带子节点变化的信号,所以不需要手动指定变化信号。

class TestSuperNode extends Node:
  pass

class TestSubNode extends Node:
  signal changed
  var a: int:
    set(value):
      a = value
      changed.emit()

func _ready() -> void:
  var source_obj := TestSuperNode.new()
  var target_data_node := DataNodeList.new(TYPE_INT, func(): return DataNodeInt.new(0))
  var _observer := ObserverNode.new(
    source_obj,
    target_data_node,
    func(source_child: Object, target_element: DataNode) -> Array:
      return [ObserverProperty.new(source_child, ^":a", target_element, source_child.changed)]
  )
  prints(target_data_node.size()) # 0
  var foo_child := TestSubNode.new()
  source_obj.add_child(foo_child)
  await get_tree().process_frame # 异步,等一帧
  prints(target_data_node.value()) # [0]
  prints(target_data_node.size()) # 1
  foo_child.a = 1
  await get_tree().process_frame # 异步,等一帧
  prints(target_data_node.value()) # [1]
  source_obj.queue_free()