import {compose} from '@avocado/core'; import {Vector} from '@avocado/math'; import {EventEmitter} from '@avocado/mixins'; import {Trait} from '../trait'; 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. class PositionedBase extends Trait { static defaultState() { return { x: 0, y: 0, }; } initialize() { this.on('_positionChanged', (oldPosition, newPosition) => { 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); }); this.entity.emit('positionChanged', oldPosition, newPosition); }); this.on('serverPositionChanged', () => { this.serverPositionDirty = true; }); const x = this.state.get('x') / 4; const y = this.state.get('y') / 4; this._position = [x, y]; 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; } } 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); } listeners() { return { isTickingChanged: () => { // Snap position on ticking change. this._position = this.serverPosition; }, }; } 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)); } } export class Positioned extends decorate(PositionedBase) {}