103 lines
4.0 KiB
GDScript
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)
|