You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

131 lines
3.8 KiB

import uuid
from typing import Optional, List, Dict, Callable
from base import Transform2D, Vector2D
from pygame import Surface
class Node:
def __init__(self, name: str = ""):
self._id = str(uuid.uuid4())
self.name = name or f"Node_{self._id[:8]}"
self.parent: Optional[Node] = None
self.children: List[Node] = []
self._is_in_tree = False
self._ready_called = False
self._process_enabled = False
self._physics_process_enabled = False
self.signals: Dict[str, List[Callable]] = {}
def _enter_tree(self):
self.enter_tree()
self._is_in_tree = True
for child in self.children:
child._enter_tree()
def _exit_tree(self):
self.exit_tree()
self._is_in_tree = False
for child in self.children:
child._exit_tree()
def _ready(self):
if not self._ready_called:
self._ready_called = True
self.ready()
for child in self.children:
child._ready()
def _process(self, delta: float):
if not self._process_enabled:
return
self.process(delta)
for child in self.children:
child._process(delta)
def _physics_process(self, delta: float):
if not self._process_enabled:
return
self.physics_process(delta)
for child in self.children:
child._physics_process(delta)
def _unhandled_input(self, event):pass
def _unhandled_key_input(self, event):pass
"""
def _draw(self, surface: Surface):
if self._visible:
self.draw(surface)
for child in self.children:
child._draw(surface)
"""
def enter_tree(self): pass
def exit_tree(self): pass
def ready(self): pass
def process(self, delta: float): pass
def physics_process(self, delta: float): pass
# def draw(self, surface: Surface): pass
def add_child(self, node: 'Node'):
if node.parent:
node.parent.remove_child(node)
self.children.append(node)
node.parent = self
def remove_child(self, node: 'Node'):
if node in self.children:
self.children.remove(node)
node.parent = None
def get_node(self, path: str) -> Optional['Node']:
if path == ".":
return self
parts = path.split("/")
current = self
for part in parts:
if part == "..":
current = current.parent
if not current:
return None
else:
found = False
for child in current.children:
if child.name == part:
current = child
found = True
break
if not found:
return None
return current
return current
def connect(self, signal: str, callback: Callable):
if signal not in self.signals:
self.signals[signal] = []
self.signals[signal].append(callback)
def emit(self, signal: str, *args):
if signal in self.signals:
for callback in self.signals[signal]:
callback(*args)
def to_dict(self) -> dict:
return {
"type": self.__class__.__name__,
"name": self.name,
"children": [child.to_dict() for child in self.children],
}
@classmethod
def from_dict(cls, data: dict) -> 'Node':
node = cls(data["name"])
for child_data in data["children"]:
child = Node.from_dict(child_data)
node.add_child(child)
return node