2019-04-28 23:45:03 -05:00
|
|
|
import {compose, EventEmitter} from '@avocado/core';
|
2019-04-10 21:02:42 -05:00
|
|
|
import {Vector} from '@avocado/math';
|
2019-03-17 23:45:48 -05:00
|
|
|
|
2019-04-10 21:02:42 -05:00
|
|
|
import {Trait} from '../trait';
|
2019-03-17 23:45:48 -05:00
|
|
|
|
|
|
|
const decorate = compose(
|
2019-04-10 21:02:42 -05:00
|
|
|
EventEmitter,
|
|
|
|
Vector.Mixin('_position', 'x', 'y', {
|
2019-03-18 20:05:00 -05:00
|
|
|
track: true,
|
|
|
|
}),
|
2019-04-12 09:48:43 -05:00
|
|
|
Vector.Mixin('serverPosition', 'serverX', 'serverY', {
|
|
|
|
track: true,
|
|
|
|
}),
|
2019-03-17 23:45:48 -05:00
|
|
|
);
|
|
|
|
|
2019-04-10 21:02:42 -05:00
|
|
|
// < 16768 will pack into 1 short per axe and give +/- 0.25 precision.
|
2019-03-17 23:45:48 -05:00
|
|
|
class PositionedBase extends Trait {
|
|
|
|
|
|
|
|
static defaultState() {
|
|
|
|
return {
|
|
|
|
x: 0,
|
|
|
|
y: 0,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2019-04-10 21:02:42 -05:00
|
|
|
initialize() {
|
2019-04-30 17:11:41 -05:00
|
|
|
this.on('_positionChanged', this.on_positionChanged, this);
|
2019-04-10 21:02:42 -05:00
|
|
|
const x = this.state.get('x') / 4;
|
|
|
|
const y = this.state.get('y') / 4;
|
|
|
|
this._position = [x, y];
|
2019-04-23 16:57:42 -05:00
|
|
|
if (AVOCADO_CLIENT) {
|
2019-04-23 16:58:36 -05:00
|
|
|
this._relaxServerPositionConstraintIfNearerThan = 0;
|
2019-04-23 16:57:42 -05:00
|
|
|
this.serverPosition = this._position;
|
|
|
|
this.serverPositionDirty = false;
|
2019-04-30 17:11:41 -05:00
|
|
|
this.on('serverPositionChanged', this.onServerPositionChanged, this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
destroy() {
|
|
|
|
this.off('_positionChanged', this.on_positionChanged);
|
|
|
|
if (AVOCADO_CLIENT) {
|
|
|
|
this.off('serverPositionChanged', this.onServerPositionChanged);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
on_positionChanged(oldPosition, newPosition) {
|
|
|
|
if (AVOCADO_SERVER) {
|
|
|
|
const x = Math.floor(newPosition[0]) * 4;
|
|
|
|
const y = Math.floor(newPosition[1]) * 4;
|
|
|
|
this.state = this.state.withMutations((state) => {
|
|
|
|
state.set('x', x).set('y', y);
|
2019-04-23 16:57:42 -05:00
|
|
|
});
|
2019-04-30 17:11:41 -05:00
|
|
|
this.isDirty = true;
|
|
|
|
}
|
|
|
|
if (oldPosition[0] !== newPosition[0]) {
|
|
|
|
this.entity.emit('xChanged', oldPosition[0], newPosition[0]);
|
|
|
|
}
|
|
|
|
if (oldPosition[1] !== newPosition[1]) {
|
|
|
|
this.entity.emit('yChanged', oldPosition[1], newPosition[1]);
|
2019-04-23 16:57:42 -05:00
|
|
|
}
|
2019-04-30 17:11:41 -05:00
|
|
|
this.entity.emit('positionChanged', oldPosition, newPosition);
|
|
|
|
}
|
|
|
|
|
|
|
|
onServerPositionChanged() {
|
|
|
|
this.serverPositionDirty = true;
|
2019-04-12 09:48:43 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
patchStateStep(key, step) {
|
|
|
|
if ('state' !== key) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const stateKey = step.path.substr(1);
|
|
|
|
const value = this.transformPatchValue(stateKey, step.value);
|
|
|
|
switch (stateKey) {
|
|
|
|
case 'x':
|
|
|
|
this.serverX = value;
|
|
|
|
break;
|
|
|
|
case 'y':
|
|
|
|
this.serverY = value;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
super.patchStateStep(key, step);
|
|
|
|
break;
|
|
|
|
}
|
2019-04-10 21:02:42 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
get position() {
|
|
|
|
return this._position;
|
|
|
|
}
|
|
|
|
|
|
|
|
set position(position) {
|
|
|
|
this._position = position;
|
|
|
|
}
|
|
|
|
|
2019-04-23 16:58:36 -05:00
|
|
|
set relaxServerPositionConstraintIfNearerThan(nearerThan) {
|
|
|
|
this._relaxServerPositionConstraintIfNearerThan = nearerThan;
|
|
|
|
}
|
|
|
|
|
2019-04-10 21:02:42 -05:00
|
|
|
transformPatchValue(key, value) {
|
|
|
|
if (-1 !== ['x', 'y'].indexOf(key)) {
|
|
|
|
return value / 4;
|
|
|
|
}
|
|
|
|
super.transformPatchValue(key, value);
|
|
|
|
}
|
|
|
|
|
2019-04-12 09:48:43 -05:00
|
|
|
listeners() {
|
|
|
|
return {
|
|
|
|
|
2019-04-12 12:27:32 -05:00
|
|
|
isTickingChanged: () => {
|
|
|
|
// Snap position on ticking change.
|
2019-04-23 16:57:42 -05:00
|
|
|
if (AVOCADO_CLIENT) {
|
|
|
|
this._position = this.serverPosition;
|
|
|
|
}
|
2019-04-12 12:27:32 -05:00
|
|
|
},
|
|
|
|
|
2019-04-12 09:48:43 -05:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2019-04-23 16:56:47 -05:00
|
|
|
renderTick(elapsed) {
|
2019-04-12 13:05:30 -05:00
|
|
|
if (!this.serverPositionDirty) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (Vector.equals(this._position, this.serverPosition)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (Vector.equalsClose(this._position, this.serverPosition, 0.1)) {
|
|
|
|
this._position = this.serverPosition;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const diff = Vector.sub(this.serverPosition, this._position);
|
2019-04-23 17:41:37 -05:00
|
|
|
const nearerThan = this._relaxServerPositionConstraintIfNearerThan;
|
|
|
|
let lerp;
|
|
|
|
if (
|
|
|
|
nearerThan
|
|
|
|
&& Vector.equalsClose(this._position, this.serverPosition, nearerThan)
|
|
|
|
) {
|
|
|
|
lerp = .01;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
lerp = .5;
|
|
|
|
}
|
|
|
|
this._position = Vector.add(this._position, Vector.scale(diff, lerp));
|
2019-04-12 13:05:30 -05:00
|
|
|
}
|
|
|
|
|
2019-03-17 23:45:48 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
export class Positioned extends decorate(PositionedBase) {}
|