2020-12-31 18:35:06 -06:00
|
|
|
import {StateProperty, Trait} from '@avocado/traits';
|
2021-01-16 09:17:08 -06:00
|
|
|
import {Rectangle, Vector} from '@avocado/math';
|
2020-12-31 18:35:06 -06:00
|
|
|
import {compose} from '@latus/core';
|
2020-12-28 21:18:54 -06:00
|
|
|
|
|
|
|
import Container from '../container';
|
|
|
|
|
|
|
|
// eslint-disable-next-line no-bitwise
|
|
|
|
const AUTO_ZINDEX = 1 << 16;
|
|
|
|
|
|
|
|
const decorate = compose(
|
|
|
|
StateProperty('isVisible', {
|
|
|
|
track: true,
|
|
|
|
}),
|
|
|
|
StateProperty('opacity', {
|
|
|
|
track: true,
|
|
|
|
}),
|
|
|
|
StateProperty('rotation', {
|
|
|
|
track: true,
|
|
|
|
}),
|
|
|
|
StateProperty('visibleScale', {
|
|
|
|
track: true,
|
|
|
|
}),
|
|
|
|
StateProperty('zIndex', {
|
|
|
|
track: true,
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
|
2021-01-13 00:05:33 -06:00
|
|
|
export default () => class Visible extends decorate(Trait) {
|
2020-12-28 21:18:54 -06:00
|
|
|
|
2021-01-16 09:17:08 -06:00
|
|
|
#container;
|
|
|
|
|
|
|
|
#rawVisibleAabb = [0, 0, 0, 0];
|
|
|
|
|
|
|
|
#scheduledBoundingBoxUpdate = true;
|
|
|
|
|
|
|
|
#usingAutoZIndex = true;
|
|
|
|
|
|
|
|
#visibleScale = [0, 0];
|
|
|
|
|
|
|
|
constructor() {
|
|
|
|
super();
|
|
|
|
if ('client' === process.env.SIDE) {
|
|
|
|
this.#container = new Container();
|
|
|
|
}
|
|
|
|
({
|
|
|
|
visibleScale: this.#visibleScale,
|
|
|
|
} = this.constructor.defaultState());
|
|
|
|
}
|
|
|
|
|
|
|
|
acceptPacket(packet) {
|
|
|
|
if ('TraitUpdateVisible' === packet.constructor.type) {
|
|
|
|
this.entity.isVisible = packet.data.isVisible;
|
|
|
|
this.entity.opacity = packet.data.opacity;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-28 21:18:54 -06:00
|
|
|
static behaviorTypes() {
|
|
|
|
return {
|
|
|
|
updateVisibleBoundingBox: {
|
|
|
|
advanced: true,
|
|
|
|
type: 'void',
|
|
|
|
label: 'Update the visible bounding box.',
|
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
static defaultParams() {
|
|
|
|
return {
|
|
|
|
filter: undefined,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
static defaultState() {
|
|
|
|
return {
|
|
|
|
isVisible: true,
|
|
|
|
opacity: 1,
|
|
|
|
rotation: 0,
|
|
|
|
visibleScale: [1, 1],
|
|
|
|
zIndex: AUTO_ZINDEX,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
static describeParams() {
|
|
|
|
return {
|
|
|
|
filter: {
|
|
|
|
type: 'object',
|
|
|
|
label: 'Filter',
|
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
static describeState() {
|
|
|
|
return {
|
|
|
|
isVisible: {
|
|
|
|
type: 'bool',
|
|
|
|
label: 'Is visible',
|
|
|
|
},
|
|
|
|
opacity: {
|
|
|
|
type: 'number',
|
|
|
|
label: 'Opacity',
|
|
|
|
},
|
|
|
|
rotation: {
|
|
|
|
type: 'number',
|
|
|
|
label: 'Rotation',
|
|
|
|
},
|
|
|
|
visibleScale: {
|
|
|
|
type: 'vector',
|
|
|
|
label: 'Scale',
|
|
|
|
},
|
|
|
|
zIndex: {
|
|
|
|
type: 'number',
|
|
|
|
label: 'Z index',
|
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-01-16 09:17:08 -06:00
|
|
|
destroy() {
|
|
|
|
if (this.#container) {
|
|
|
|
this.#container.destroy();
|
2020-12-28 21:18:54 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-16 09:17:08 -06:00
|
|
|
get container() {
|
|
|
|
return this.#container;
|
2020-12-28 21:18:54 -06:00
|
|
|
}
|
|
|
|
|
2021-01-17 11:07:55 -06:00
|
|
|
forceUpdateBoundingBox() {
|
|
|
|
// Collect all bounding boxes.
|
|
|
|
const visibleAabbs = this.entity.invokeHookFlat('visibleAabbs');
|
|
|
|
if (0 === visibleAabbs.length) {
|
|
|
|
this.#rawVisibleAabb = [0, 0, 0, 0];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
let unifiedBoundingBox = [0, 0, 0, 0];
|
|
|
|
for (let i = 0; i < visibleAabbs.length; ++i) {
|
|
|
|
const visibleAabb = visibleAabbs[i];
|
|
|
|
unifiedBoundingBox = Rectangle.united(
|
|
|
|
unifiedBoundingBox,
|
|
|
|
visibleAabb,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
this.#rawVisibleAabb = unifiedBoundingBox;
|
|
|
|
}
|
|
|
|
this.translateVisibleAabb();
|
|
|
|
this.#scheduledBoundingBoxUpdate = false;
|
|
|
|
}
|
|
|
|
|
2021-01-16 09:17:08 -06:00
|
|
|
listeners() {
|
|
|
|
return {
|
|
|
|
|
|
|
|
isVisibleChanged: () => {
|
|
|
|
if (!this.#container) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.#container.visible = this.entity.isVisible;
|
|
|
|
},
|
|
|
|
|
|
|
|
opacityChanged: () => {
|
|
|
|
if (!this.#container) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.#container.alpha = this.entity.opacity;
|
|
|
|
},
|
|
|
|
|
|
|
|
positionChanged: () => {
|
|
|
|
this.translateVisibleAabb();
|
|
|
|
},
|
|
|
|
|
|
|
|
rotationChanged: () => {
|
|
|
|
if (!this.#container) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.#container.rotation = this.entity.rotation;
|
|
|
|
},
|
|
|
|
|
2021-01-17 11:18:15 -06:00
|
|
|
traitAdded: () => {
|
2021-01-16 09:17:08 -06:00
|
|
|
this.synchronizePosition();
|
|
|
|
},
|
|
|
|
|
|
|
|
updateVisibleBoundingBox: () => {
|
|
|
|
this.#scheduledBoundingBoxUpdate = true;
|
|
|
|
},
|
|
|
|
|
|
|
|
visibleScaleChanged: () => {
|
|
|
|
this.#visibleScale = Vector.copy(this.entity.visibleScale);
|
|
|
|
if (this.#container) {
|
|
|
|
this.#container.scale = this.#visibleScale;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
zIndexChanged: (old, zIndex) => {
|
|
|
|
this.onZIndexChanged(zIndex);
|
|
|
|
},
|
|
|
|
|
|
|
|
};
|
2020-12-28 21:18:54 -06:00
|
|
|
}
|
|
|
|
|
2021-01-16 09:17:08 -06:00
|
|
|
load(json) {
|
|
|
|
super.load(json);
|
|
|
|
if ('client' === process.env.SIDE) {
|
|
|
|
const {filter} = this.params;
|
|
|
|
if (filter) {
|
|
|
|
this.#container.setFilter(filter);
|
|
|
|
}
|
|
|
|
this.#container.isVisible = this.state.isVisible;
|
|
|
|
}
|
|
|
|
this.#visibleScale = Vector.copy(this.state.visibleScale);
|
|
|
|
this.onZIndexChanged(this.state.zIndex);
|
|
|
|
this.entity.emit('updateVisibleBoundingBox');
|
2020-12-28 21:18:54 -06:00
|
|
|
}
|
|
|
|
|
2021-01-17 11:07:55 -06:00
|
|
|
methods() {
|
|
|
|
return {
|
|
|
|
|
|
|
|
forceUpdateBoundingBox: () => {
|
|
|
|
this.forceUpdateBoundingBox();
|
|
|
|
},
|
|
|
|
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-12-28 21:18:54 -06:00
|
|
|
onZIndexChanged(zIndex) {
|
2021-01-16 09:17:08 -06:00
|
|
|
this.#usingAutoZIndex = AUTO_ZINDEX === zIndex;
|
|
|
|
if (!this.#usingAutoZIndex) {
|
|
|
|
if (this.#container) {
|
|
|
|
this.#container.zIndex = zIndex;
|
2020-12-28 21:18:54 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
packets() {
|
|
|
|
const {isVisible, opacity} = this.stateDifferences();
|
|
|
|
if (isVisible || opacity) {
|
2021-01-14 01:22:47 -06:00
|
|
|
return [[
|
|
|
|
'TraitUpdateVisible',
|
2020-12-28 21:18:54 -06:00
|
|
|
{
|
|
|
|
isVisible: this.state.isVisible,
|
|
|
|
opacity: this.state.opacity,
|
|
|
|
},
|
2021-01-14 01:22:47 -06:00
|
|
|
]];
|
2020-12-28 21:18:54 -06:00
|
|
|
}
|
2021-01-16 09:17:08 -06:00
|
|
|
return [];
|
2020-12-28 21:18:54 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
get rawVisibleScale() {
|
2021-01-16 09:17:08 -06:00
|
|
|
return this.#visibleScale;
|
2020-12-28 21:18:54 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
set rawVisibleScale(scale) {
|
|
|
|
this.entity.visibleScale = scale;
|
|
|
|
}
|
|
|
|
|
2021-01-16 09:17:08 -06:00
|
|
|
renderTick() {
|
|
|
|
this.synchronizePosition();
|
|
|
|
}
|
|
|
|
|
2020-12-28 21:18:54 -06:00
|
|
|
synchronizePosition() {
|
2021-01-17 11:18:15 -06:00
|
|
|
if (!this.entity.is('Positioned')) {
|
2020-12-28 21:18:54 -06:00
|
|
|
return;
|
|
|
|
}
|
2021-01-16 09:17:08 -06:00
|
|
|
if (!this.#container) {
|
2020-12-28 21:18:54 -06:00
|
|
|
return;
|
|
|
|
}
|
2021-01-16 09:17:08 -06:00
|
|
|
this.#container.position = this.entity.position;
|
|
|
|
if (this.#usingAutoZIndex) {
|
|
|
|
if (this.#container) {
|
|
|
|
this.#container.zIndex = this.entity.y;
|
2020-12-28 21:18:54 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
get visibleScaleX() {
|
|
|
|
return this.state.visibleScale[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
set visibleScaleX(x) {
|
|
|
|
this.rawVisibleScale = [x, this.visibleScaleY];
|
|
|
|
}
|
|
|
|
|
|
|
|
get visibleScaleY() {
|
|
|
|
return this.state.visibleScale[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
set visibleScaleY(y) {
|
|
|
|
this.rawVisibleScale = [this.visibleScaleX, y];
|
|
|
|
}
|
|
|
|
|
|
|
|
tick() {
|
2021-01-14 01:22:47 -06:00
|
|
|
if ('client' !== process.env.SIDE) {
|
2021-01-16 09:17:08 -06:00
|
|
|
if (this.#scheduledBoundingBoxUpdate) {
|
2021-01-17 11:07:55 -06:00
|
|
|
this.forceUpdateBoundingBox();
|
2020-12-28 21:18:54 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-16 09:17:08 -06:00
|
|
|
translateVisibleAabb() {
|
|
|
|
const visibleAabb = Rectangle.translated(
|
|
|
|
this.#rawVisibleAabb,
|
|
|
|
this.entity.position,
|
|
|
|
);
|
|
|
|
/* eslint-disable prefer-destructuring */
|
|
|
|
this.entity.visibleAabb[0] = visibleAabb[0];
|
|
|
|
this.entity.visibleAabb[1] = visibleAabb[1];
|
|
|
|
this.entity.visibleAabb[2] = visibleAabb[2];
|
|
|
|
this.entity.visibleAabb[3] = visibleAabb[3];
|
|
|
|
/* eslint-enable prefer-destructuring */
|
|
|
|
this.entity.emit('visibleAabbChanged');
|
|
|
|
}
|
|
|
|
|
2021-01-13 00:05:33 -06:00
|
|
|
};
|