UNPKG

gibbon.js

Version:

Actor/Component system for use with pixi.js.

229 lines (188 loc) 4.96 kB
import type { Actor } from "./actor"; import { Constructor } from '../utils/types'; import type { DisplayObject } from 'pixi.js'; import type { Game } from "@/game"; import { EngineEvent } from '../events/engine-events'; export const BasePriority = 3000; export class Component<T extends DisplayObject = DisplayObject, G extends Game = Game> { public readonly _isComponent = true; /** * @property game */ get game(): G | undefined { return this.actor!.game; } /** * @property {Engine} engine */ get engine() { return this.game?.engine; } /** * @property {number} flags - Convenience accessor for Actor.flags. */ get flags() { return this.actor!.flags; } set flags(v) { this.actor!.flags = v; } /** * Group controlling the component's Actor, if any. */ get group() { return this.actor?.group; } /** * @property {boolean} enabled - Whether the component is enabled. */ get enabled() { return this._enabled; } set enabled(v) { if (this._enabled === v) { return; } this._enabled = v; if (v === true) { this.onEnable?.(); } else { this.onDisable?.(); } } /** * @property {number} x */ get x() { return this.actor?.x ?? 0; } set x(v) { if (this.actor) { this.actor.x = v; } } /** * @property {number} y */ get y(): number { return this.actor?.y ?? 0; } set y(v) { if (this.actor != null) this.actor.y = v; } /** * @property {number} rotation - underlying clip rotation in radians. */ get rotation(): number { return this.actor?.rotation ?? 0; } set rotation(v: number) { if (this.actor) { this.actor.rotation = v; } } /** * @property position - only usable after init() */ get position() { return this.actor!.position; } set position(v) { this.actor!.position = v; } /** * Indicates the component has been marked for disposal and should no longer * be referenced. * @property {Boolean} isDestroyed */ get isDestroyed() { return this._destroyed; } /** * Priority of component. Higher priority components' * update functions are updated before lower priority. * (0 is lowest priority.) * Priority should not be changed once a component is * added to an Actor. */ priority: number = BasePriority; /** * @property - Game object containing this component. */ actor?: Actor<T, G>; /** * @private */ _enabled: boolean = true; /** * @private */ _destroyed: boolean = false; /** * @property clip - Convenience accessor of Actor clip. */ get clip() { return this.actor?.clip; } /** * Constructor intentionally empty so components can be * instantiated and added to Actors without * knowledge of the underlying game system. * @note component properties such as actor, clip, and game, * are not available until init() is called by the Engine. */ constructor() { } /** * Private initializer calls subclassed init() * @param {Actor} actor */ _init(actor: Actor<T, G>) { this.actor = actor; this.init?.(); if (this.enabled) { this.onEnable?.(); } } /** * Called when actor.active is set to true. */ onActivate?(): void; /** * Called when actor.active is set to false. */ onDeactivate?(): void; /** * Override in subclass to initialize component. * Basic component properties are now available. * This component is also now in the gameObjects own component map. */ init?(): void; onEnable?(): void; onDisable?(): void; /** * * @param delta - Tick time in seconds. */ update?(delta: number): void; /** * Emit event through owning actor's emitter.. * @param evt * @param args */ emit(evt: string, ...args: any[]) { this.actor!.emit(evt, ...args); } /** * Add a component already instantiated. * @param {Component} comp * @returns {Component} The added component instance. */ add<C extends Component>(comp: C | Constructor<C>, cls?: Constructor<C>): C { return this.actor!.add(comp, cls); } /** * * @param {class} cls - wrapper for actor get() * @returns {Component|null} */ get<C extends Component>(cls: Constructor<C>): C | undefined { return this.actor!.get(cls); } /** * Wraps Actor require(). * @param {*} cls * @returns {Component} */ require<C extends Component>(cls: Constructor<C>): C { return this.actor!.require(cls); } /** * Override in subclasses to clean up before component destroyed. */ onDestroy?(): void; /** * Use to destroy a Component. * override onDestroy() to clean up your components. */ destroy() { if (this._destroyed === true) { return; } this.enabled = false; this.actor?.emit( EngineEvent.ComponentDestroyed, this); this.onDestroy?.(); this._destroyed = true; this.actor = undefined; } }