Files
godot-shader-experiments/addons/gecs/ecs/ecs.gd
2026-01-15 15:27:48 +01:00

103 lines
4.0 KiB
GDScript

## ECS ([Entity] [Component] [System]) Singleton[br]
## The ECS class acts as the central manager for the entire ECS framework
##
## The [_ECS] class maintains the current active [World] and provides access to [QueryBuilder] for fetching [Entity]s based on their [Component]s.
##[br]
## This singleton allows any part of the game to interact with the ECS system seamlessly.
## [codeblock]
## var entities = ECS.world.query.with_all([Transform, Velocity]).execute()
## for entity in entities:
## entity.get_component(Transform).position += entity.get_component(Velocity).direction * delta
## [/codeblock]
## This is also where you control the setup of the world and process loop of the ECS system.
##[codeblock]
##
## func _read(delta):
## ECS.world = world
##
## func _process(delta):
## ECS.process(delta)
##[/codeblock]
## or in the physics loop
##[codeblock]
## func _physics_process(delta):
## ECS.process(delta)
##[/codeblock]
class_name _ECS
extends Node
## Emitted when the world is changed with a ref to the new world
signal world_changed(world: World)
## Emitted when the world is exited
signal world_exited
## The Current active [World] Instance[br]
## Holds a reference to the currently active [World], allowing access to the [member World.query] instance and any [Entity]s and [System]s within it.
var world: World:
get:
return world
set(value):
# Add the new world to the scenes
world = value
if world:
if not world.is_inside_tree():
# Add the world to the tree if it is not already
get_tree().root.get_node("./Root").add_child(world)
if not world.is_connected("tree_exited", _on_world_exited):
world.connect("tree_exited", _on_world_exited)
world_changed.emit(world)
assert(GECSEditorDebuggerMessages.set_world(world) if debug else true, 'Debug Data')
## Are we in debug mode? Controlled by project setting gecs/debug_mode
var debug := ProjectSettings.get_setting(GecsSettings.SETTINGS_DEBUG_MODE, false)
## This is an array of functions that get called on the entities when they get added to the world (after they are ready)
var entity_preprocessors: Array[Callable] = []
## This is an array of functions that get called on the entities right before they get removed from the world
var entity_postprocessors: Array[Callable] = []
## A Wildcard for use in relatonship queries. Indicates can be any value for a relation
## or a target in a Relationship Pair ECS.wildcard
var wildcard = null
## This is called to process the current active [World] instance and the [System]s within it.
## You would call this in _process or _physics_process to update the [_ECS] system.[br]
## If you provide a group name it will run just that group otherwise it runs all groups[br]
## Example:
## [codeblock]ECS.world.process(world, 'my-system-group')[/codeblock]
func process(delta: float, group: String = "") -> void:
world.process(delta, group)
## Get all components of a specific type from a list of entities[br]
## If the component does not exist on the entity it will return the default_component if provided or assert
func get_components(entities, component_type, default_component = null) -> Array:
var components = []
for entity in entities:
var component = entity.components.get(component_type.resource_path, null)
if not component and not default_component:
assert(component, "Entity does not have component: " + str(component_type))
if not component and default_component:
component = default_component
components.append(component)
return components
## Called when the world is exited
func _on_world_exited() -> void:
world = null
world_exited.emit()
assert(GECSEditorDebuggerMessages.exit_world() if debug else true, 'Debug Data')
func serialize(query: QueryBuilder, config: GECSSerializeConfig = null) -> GecsData:
return GECSIO.serialize(query, config)
func save(gecs_data: GecsData, filepath: String, binary: bool = false) -> bool:
return GECSIO.save(gecs_data, filepath, binary)
func deserialize(gecs_filepath: String) -> Array[Entity]:
return GECSIO.deserialize(gecs_filepath)