Skip to content

Component Lifecycle

Components provide lifecycle hooks that can be overridden to execute specific logic.

@ECSComponent('ExampleComponent')
class ExampleComponent extends Component {
private resource: SomeResource | null = null;
/**
* Called when component is added to entity
* Use for initializing resources, establishing references, etc.
*/
onAddedToEntity(): void {
console.log(`Component ${this.constructor.name} added, Entity ID: ${this.entityId}`);
this.resource = new SomeResource();
}
/**
* Called when component is removed from entity
* Use for cleaning up resources, breaking references, etc.
*/
onRemovedFromEntity(): void {
console.log(`Component ${this.constructor.name} removed`);
if (this.resource) {
this.resource.cleanup();
this.resource = null;
}
}
}
Entity created
addComponent() called
onAddedToEntity() triggered
Component in normal use...
removeComponent() or entity.destroy() called
onRemovedFromEntity() triggered
Component removed/destroyed
@ECSComponent('TextureComponent')
class TextureComponent extends Component {
private _texture: Texture | null = null;
texturePath: string = '';
onAddedToEntity(): void {
// Load texture resource
this._texture = TextureManager.load(this.texturePath);
}
onRemovedFromEntity(): void {
// Release texture resource
if (this._texture) {
TextureManager.release(this._texture);
this._texture = null;
}
}
get texture(): Texture | null {
return this._texture;
}
}
@ECSComponent('InputListener')
class InputListener extends Component {
private _boundHandler: ((e: KeyboardEvent) => void) | null = null;
onAddedToEntity(): void {
this._boundHandler = this.handleKeyDown.bind(this);
window.addEventListener('keydown', this._boundHandler);
}
onRemovedFromEntity(): void {
if (this._boundHandler) {
window.removeEventListener('keydown', this._boundHandler);
this._boundHandler = null;
}
}
private handleKeyDown(e: KeyboardEvent): void {
// Handle keyboard input
}
}
@ECSComponent('PhysicsBody')
class PhysicsBody extends Component {
private _body: PhysicsWorld.Body | null = null;
onAddedToEntity(): void {
// Create rigid body in physics world
this._body = PhysicsWorld.createBody({
entityId: this.entityId,
type: 'dynamic'
});
}
onRemovedFromEntity(): void {
// Remove rigid body from physics world
if (this._body) {
PhysicsWorld.removeBody(this._body);
this._body = null;
}
}
}

Avoid Accessing Other Components in Lifecycle

Section titled “Avoid Accessing Other Components in Lifecycle”
@ECSComponent('BadComponent')
class BadComponent extends Component {
onAddedToEntity(): void {
// ⚠️ Not recommended: Other components may not be added yet
const other = this.entity?.getComponent(OtherComponent);
if (other) {
// May be null
}
}
}
Section titled “Recommended: Use System to Handle Inter-Component Interactions”
@ECSSystem('InitializationSystem')
class InitializationSystem extends EntitySystem {
constructor() {
super(Matcher.all(ComponentA, ComponentB));
}
// Use onAdded event to ensure both components exist
onAdded(entity: Entity): void {
const a = entity.getComponent(ComponentA)!;
const b = entity.getComponent(ComponentB)!;
// Safely initialize interaction
a.linkTo(b);
}
onRemoved(entity: Entity): void {
// Cleanup
}
}
FeatureComponent LifecycleSystem Lifecycle
Trigger TimingWhen component added/removedWhen match conditions met
Use CaseResource init/cleanupBusiness logic processing
Access Other ComponentsNot recommendedSafe
Access SceneLimitedFull