import {compose} from '@avocado/core'; import {hasGraphics, Container} from '@avocado/graphics'; import {Rectangle, Vector} from '@avocado/math'; import {StateProperty, Trait} from '../trait'; const decorate = compose( StateProperty('isVisible', { track: true, }), ); export class Graphical extends decorate(Trait) { static defaultParams() { return { trackPosition: true, }; } static defaultState() { return { isVisible: true, }; } initialize() { if (hasGraphics) { this._container = new Container(); this._container.isVisible = this.entity.isVisible; } this.trackPosition = this.params.get('trackPosition'); } destroy() { if (this._container) { this._container.destroy(); } } get container() { return this._container; } get graphicalBoundingBox() { // Collect all bounding boxes. const graphicalBoundingBoxes = this.entity.invokeHookFlat( 'graphicalBoundingBoxes' ); if (0 === graphicalBoundingBoxes.length) { return [0, 0, 0, 0]; } let unifiedBoundingBox = [0, 0, 0, 0]; for (const graphicalBoundingBox of graphicalBoundingBoxes) { unifiedBoundingBox = Rectangle.united( unifiedBoundingBox, graphicalBoundingBox, ); } return unifiedBoundingBox; } shouldSynchronizePosition() { return this._container && this.trackPosition; } synchronizePosition() { if (!this.entity.is('positioned')) { return; } this.entity.container.position = this.entity.position; this.entity.container.zIndex = this.entity.y; } listeners() { const listeners = { isVisibleChanged: () => { this.entity.container.visible = this.entity.isVisible; }, }; if (this.shouldSynchronizePosition()) { listeners.traitAdded = (type) => { if (-1 === [ 'graphical', 'positioned', ].indexOf(type)) { return; } this.synchronizePosition(); }; } return listeners; } tick(elapsed) { if (this.shouldSynchronizePosition()) { this.synchronizePosition(); } } }