Behaviors are modular components that encapsulate specific functionality or logic.
All behaviors provide the following methods:
onEnable()
: Called when the behavior is enabled (attached to a game object).onDisable()
: Called when the behavior is disabled (removed from a game object).tick(deltaTime : float)
: Called every frame with the time that has passed since the last frame.abstract class Behavior {
protected onEnable(): void;
protected onDisable(): void;
tick(_deltaTime: number): void;
}
These behaviors are modular and enforce clear separation of concerns, improving maintainability and testability. You generally want to use these behaviors instead of parent Behavior class.
Aspect | InputBehavior | LogicBehavior | OutputBehavior |
---|---|---|---|
Primary Role | Capture, handle and propagate input. | Process and manage logic/state. | Reflect state externally. |
Data Handling | Generates events and calls logic. | Holds and processes data. | Observes logic's data/state. |
Dependencies | Likely depends on external system (like keyboard). | N/A Expose methods to be called from InputBehavior . |
Depends on LogicBehavior . |
Responsibilities:
LogicBehavior
.Characteristics:
LogicBehavior
by invoking specific public methods like jump()
when spacebar is pressed.abstract class InputBehavior extends Behavior {
protected getLogicBehavior<T extends LogicBehavior<any>>(...): T | null;
}
Example usage:
class KeyboardInputBehavior extends DeviceInputBehavior {
protected onKeyboardKeyDown(key: string): void {
if(key === 'a')
this.getLogicBehavior<PlayerLogicBehavior>()?.jump();
}
}
Responsibilities:
InputBehavior
and OutputBehavior
.Characteristics:
T
) that can be observed by OutputBehavior
. (T
is the type of data the behavior manages. It is strongly typed but can vary from different LogicBehaviors.)jump()
or onHover()
to modify its state.notifyDataChanged()
to allow OutputBehavior
to access its current state via event observation (onDataChanged
).class LogicBehavior<T> extends Behavior {
readonly onDataChanged: Event<T>;
protected data: T;
protected notifyDataChanged(): void;
}
Example usage:
class ScoreLogicBehavior extends LogicBehavior<number> {
public increaseScore(): void {
this.data += 1;
this.notifyDataChanged();
}
}
Responsibilities:
LogicBehavior
to reflect changes in the game state externally (e.g., rendering, audio, ...).LogicBehavior
for other external systems.Characteristics:
LogicBehavior
using observe
, with callbacks to handle data changes.GameObject
is exposed for manipulation.abstract class OutputBehavior extends Behavior {
protected observe<T extends LogicBehavior<U>, U>(observer: (data: U) => void): void;
}
Example usage:
this.observe(LogicBehavior<number>, (score) => {
this.text = `Score: ${score}`;
})
The “setup” and “detach” behaviors should not be called directly (nor should OnAttachedTo(gameEngine) for the main game engine components).
This mechanism is automatic when an object is attached to its parent (a game engine window for components or a game object for behaviors).
In most cases, the only useful methods for overriding children are onEnable and onDisable. This ensures the isolation of different types of behaviors.