diff --git a/packages/entity/traits/pictured.js b/packages/entity/traits/pictured.js new file mode 100644 index 0000000..7bedb90 --- /dev/null +++ b/packages/entity/traits/pictured.js @@ -0,0 +1,106 @@ +import {compose} from '@avocado/core'; +import {Image, Sprite} from '@avocado/graphics'; +import {Vector} from '@avocado/math'; + +import {simpleState, Trait} from '../trait'; + +const decorate = compose( + simpleState('currentImage', { + track: true, + }), +); + +class PicturedBase extends Trait { + + static defaultParams() { + return { + images: {}, + }; + } + + static defaultState() { + return { + currentImage: 'initial', + }; + } + + hideImage(key) { + if (!this.sprites) { + return; + } + const sprite = this.sprites[key]; + if (!sprite) { + return; + } + this.entity.container.removeChild(sprite); + } + + initialize() { + this.sprites = undefined; + } + + loadImagesIfPossible() { + if (!this.entity.container) { + return; + } + if (this.sprites) { + return; + } + const images = this.params.get('images'); + // Load all images. + this.sprites = {}; + for (const key in images) { + const {uri} = images[key]; + Image.load(uri).then((image) => { + this.sprites[key] = new Sprite(image); + const isCurrentImage = key === this.entity.currentImage; + if (isCurrentImage) { + this.showImage(key); + } + }); + } + } + + showImage(key) { + if (!this.sprites) { + return; + } + const sprite = this.sprites[key]; + if (!sprite) { + return; + } + const images = this.params.get('images'); + const {offset} = images[key]; + const {image} = sprite; + const size = image.size; + const halfway = Vector.scale(size, -0.5); + sprite.position = Vector.add(halfway, offset); + this.entity.container.addChild(sprite); + } + + listeners() { + return { + currentImageChanged: (oldKey) => { + // Only client/graphics. + if (!this.sprites) { + return; + } + // Swap the image. + this.hideImage(oldKey); + this.showImage(this.entity.currentImage); + }, + traitAdded: (trait) => { + if (-1 === [ + 'graphical', + 'pictured', + ].indexOf(trait.constructor.type())) { + return; + } + this.loadImagesIfPossible(); + }, + }; + } + +} + +export class Pictured extends decorate(PicturedBase) {}