2019-03-20 20:15:04 -05:00
|
|
|
import {compose} from '@avocado/core';
|
|
|
|
import {Image, Sprite} from '@avocado/graphics';
|
2019-03-21 20:07:32 -05:00
|
|
|
import {Rectangle, Vector} from '@avocado/math';
|
2019-03-20 20:15:04 -05:00
|
|
|
|
2019-03-23 23:24:18 -05:00
|
|
|
import {StateProperty, Trait} from '../trait';
|
2019-03-20 20:15:04 -05:00
|
|
|
|
|
|
|
const decorate = compose(
|
2019-03-23 23:24:18 -05:00
|
|
|
StateProperty('currentImage', {
|
2019-03-20 20:15:04 -05:00
|
|
|
track: true,
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
|
|
|
|
class PicturedBase extends Trait {
|
|
|
|
|
|
|
|
static defaultParams() {
|
|
|
|
return {
|
|
|
|
images: {},
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
static defaultState() {
|
|
|
|
return {
|
|
|
|
currentImage: 'initial',
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2019-03-20 23:23:34 -05:00
|
|
|
initialize() {
|
|
|
|
this.sprites = undefined;
|
2019-03-21 20:07:32 -05:00
|
|
|
// Bounding box update.
|
2019-03-26 17:17:09 -05:00
|
|
|
this.entity.emit('graphicalBoundingBoxesUpdated');
|
2019-03-20 23:23:34 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
destroy() {
|
|
|
|
if (this.sprites) {
|
|
|
|
for (const key in this.sprites) {
|
|
|
|
this.hideImage(key);
|
|
|
|
const sprite = this.sprites[key];
|
|
|
|
sprite.destroy();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-20 20:15:04 -05:00
|
|
|
hideImage(key) {
|
|
|
|
if (!this.sprites) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const sprite = this.sprites[key];
|
|
|
|
if (!sprite) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.entity.container.removeChild(sprite);
|
|
|
|
}
|
|
|
|
|
|
|
|
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) => {
|
2019-03-20 21:58:14 -05:00
|
|
|
const sprite = this.sprites[key] = new Sprite(image);
|
|
|
|
// Calculate any offset.
|
2019-03-21 20:07:32 -05:00
|
|
|
sprite.position = this.viewPositionFor(key);
|
2019-03-20 21:58:14 -05:00
|
|
|
// Set current image upfront.
|
2019-03-20 20:15:04 -05:00
|
|
|
const isCurrentImage = key === this.entity.currentImage;
|
|
|
|
if (isCurrentImage) {
|
|
|
|
this.showImage(key);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-21 20:07:32 -05:00
|
|
|
offsetFor(key) {
|
|
|
|
const images = this.params.get('images');
|
|
|
|
if (!images[key] || !images[key].offset) {
|
|
|
|
return [0, 0];
|
|
|
|
}
|
|
|
|
return images[key].offset;
|
|
|
|
}
|
|
|
|
|
2019-03-20 20:15:04 -05:00
|
|
|
showImage(key) {
|
|
|
|
if (!this.sprites) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const sprite = this.sprites[key];
|
|
|
|
if (!sprite) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.entity.container.addChild(sprite);
|
|
|
|
}
|
|
|
|
|
2019-03-21 20:07:32 -05:00
|
|
|
sizeFor(key) {
|
|
|
|
const images = this.params.get('images');
|
|
|
|
if (!images[key] || !images[key].size) {
|
|
|
|
return [0, 0];
|
|
|
|
}
|
|
|
|
return images[key].size;
|
|
|
|
}
|
|
|
|
|
|
|
|
viewPositionFor(key) {
|
|
|
|
const images = this.params.get('images');
|
|
|
|
const image = images[key];
|
|
|
|
if (!image) {
|
|
|
|
return [0, 0];
|
|
|
|
}
|
|
|
|
const size = this.sizeFor(key);
|
|
|
|
const halfway = Vector.scale(size, -0.5);
|
|
|
|
const offset = this.offsetFor(key);
|
|
|
|
return Vector.add(halfway, offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
hooks() {
|
|
|
|
return {
|
|
|
|
|
2019-03-26 17:17:09 -05:00
|
|
|
graphicalBoundingBoxes: () => {
|
2019-03-21 20:07:32 -05:00
|
|
|
const key = this.entity.currentImage;
|
|
|
|
const images = this.params.get('images');
|
|
|
|
const image = images[key];
|
|
|
|
if (!image) {
|
|
|
|
return [0, 0, 0, 0];
|
|
|
|
}
|
|
|
|
const viewPosition = this.viewPositionFor(key);
|
|
|
|
const position = Vector.add(this.entity.position, viewPosition);
|
|
|
|
return Rectangle.compose(position, this.sizeFor(key));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-20 20:15:04 -05:00
|
|
|
listeners() {
|
|
|
|
return {
|
|
|
|
currentImageChanged: (oldKey) => {
|
2019-03-21 20:07:32 -05:00
|
|
|
// Bounding box update.
|
2019-03-26 17:17:09 -05:00
|
|
|
this.entity.emit('graphicalBoundingBoxesUpdated');
|
2019-03-20 20:15:04 -05:00
|
|
|
// Only client/graphics.
|
|
|
|
if (!this.sprites) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Swap the image.
|
|
|
|
this.hideImage(oldKey);
|
|
|
|
this.showImage(this.entity.currentImage);
|
|
|
|
},
|
2019-03-21 00:15:15 -05:00
|
|
|
traitAdded: (type) => {
|
2019-03-20 20:15:04 -05:00
|
|
|
if (-1 === [
|
|
|
|
'graphical',
|
|
|
|
'pictured',
|
2019-03-21 00:15:15 -05:00
|
|
|
].indexOf(type)) {
|
2019-03-20 20:15:04 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.loadImagesIfPossible();
|
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
export class Pictured extends decorate(PicturedBase) {}
|