avocado-old/packages/entity/traits/positioned.trait.js
2019-10-10 23:50:31 -05:00

126 lines
3.0 KiB
JavaScript

import {compose, EventEmitter} from '@avocado/core';
import {Vector} from '@avocado/math';
import {Trait} from '../trait';
import {TraitUpdatePositionedPositionPacket} from '../packets/trait-update-positioned-position.packet';
const decorate = compose(
EventEmitter,
Vector.Mixin('_position', 'x', 'y', {
track: true,
}),
Vector.Mixin('serverPosition', 'serverX', 'serverY', {
track: true,
}),
);
// < 16768 will pack into 1 short per axe and give +/- 0.25 precision.
export class Positioned extends decorate(Trait) {
static defaultState() {
return {
x: 0,
y: 0,
};
}
static type() {
return 'positioned';
}
constructor(entity, params, state) {
super(entity, params, state);
this.on('_positionChanged', this.on_positionChanged, this);
const x = this.state.x;
const y = this.state.y;
this._position = [x, y];
this.entity.position[0] = x;
this.entity.position[1] = y;
if (AVOCADO_CLIENT) {
this.serverPosition = this._position;
this.serverPositionDirty = false;
this.on('serverPositionChanged', this.onServerPositionChanged, this);
}
}
destroy() {
this.off('_positionChanged', this.on_positionChanged);
if (AVOCADO_CLIENT) {
this.off('serverPositionChanged', this.onServerPositionChanged);
}
}
acceptPacket(packet) {
if (packet instanceof TraitUpdatePositionedPositionPacket) {
[this.serverX, this.serverY] = packet.data.position;
}
}
on_positionChanged(oldPosition, newPosition) {
this.entity.position[0] = newPosition[0];
this.entity.position[1] = newPosition[1];
if (AVOCADO_SERVER) {
this.state.x = newPosition[0];
this.state.y = newPosition[1];
this.entity._fastDirtyCheck = true;
this._fastDirtyCheck = true;
}
this.entity.emit('positionChanged', oldPosition, newPosition);
}
onServerPositionChanged() {
this.serverPositionDirty = true;
}
packets(informed) {
const {x, y} = this.stateDifferences();
if (x || y) {
return new TraitUpdatePositionedPositionPacket({
position: this.entity.position,
});
}
}
listeners() {
return {
isTickingChanged: () => {
// Snap position on ticking change.
if (AVOCADO_CLIENT) {
this._position = this.serverPosition;
}
},
};
}
methods() {
return {
setPosition: (position) => {
this._position = position;
},
};
}
renderTick(elapsed) {
if (!this.serverPositionDirty) {
return;
}
if (Vector.equals(this._position, this.serverPosition)) {
this.serverPositionDirty = false;
return;
}
if (Vector.equalsClose(this._position, this.serverPosition, 0.1)) {
this._position = this.serverPosition;
this.serverPositionDirty = false;
return;
}
const diff = Vector.sub(this.serverPosition, this._position);
const lerp = .5;
this._position = Vector.add(this._position, Vector.scale(diff, lerp));
}
}