avocado-old/packages/entity/traits/positioned.trait.js

110 lines
2.5 KiB
JavaScript
Raw Normal View History

2019-03-17 23:45:48 -05:00
import {compose} from '@avocado/core';
2019-04-10 21:02:42 -05:00
import {Vector} from '@avocado/math';
import {EventEmitter} from '@avocado/mixins';
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() {
this.on('_positionChanged', (oldPosition, newPosition) => {
const x = Math.floor(newPosition[0]) * 4;
const y = Math.floor(newPosition[1]) * 4;
2019-04-11 06:49:49 -05:00
this.state = this.state.withMutations((state) => {
state.set('x', x).set('y', y);
});
2019-04-19 00:58:36 -05:00
this.isDirty = true;
2019-04-10 21:02:42 -05:00
this.entity.emit('positionChanged', oldPosition, newPosition);
});
2019-04-12 09:48:43 -05:00
this.on('serverPositionChanged', () => {
this.serverPositionDirty = true;
});
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-12 09:48:43 -05:00
this.serverPosition = this._position;
this.serverPositionDirty = false;
}
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;
}
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 {
isTickingChanged: () => {
// Snap position on ticking change.
this._position = this.serverPosition;
},
2019-04-12 09:48:43 -05:00
};
}
tick(elapsed) {
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);
this._position = Vector.add(this._position, Vector.scale(diff, .5));
}
2019-03-17 23:45:48 -05:00
}
export class Positioned extends decorate(PositionedBase) {}