avocado-old/packages/topdown/camera.js
2019-04-28 23:45:03 -05:00

109 lines
2.7 KiB
JavaScript

import {compose, EventEmitter, Property} from '@avocado/core';
import {Rectangle, Vector} from '@avocado/math';
const decorate = compose(
EventEmitter,
Vector.Mixin('areaSize', 'areaWidth', 'areaHeight', {
default: [0, 0],
track: true,
}),
Property('drag', {
default: 0.2,
}),
Vector.Mixin('position', 'x', 'y', {
default: [0, 0],
}),
Vector.Mixin('realOffset', 'realOffsetX', 'realOffsetY', {
default: [0, 0],
track: true,
}),
Vector.Mixin('realPosition', 'realX', 'realY', {
default: [0, 0],
track: true,
}),
Vector.Mixin('viewSize', 'viewWidth', 'viewHeight', {
default: [0, 0],
track: true,
}),
);
export class Camera extends decorate(class {}) {
constructor() {
super();
this.viewOrigin = [0, 0];
this.on('areaSizeChanged', this.onAreaSizeChanged, this);
this.on('realPositionChanged', this.onRealPositionChanged, this);
this.on('viewSizeChanged', this.onViewSizeChanged, this);
}
destroy() {
this.off('areaSizeChanged', this.onAreaSizeChanged);
this.off('realPositionChanged', this.onRealPositionChanged, this);
this.off('viewSizeChanged', this.onViewSizeChanged);
}
onAreaSizeChanged() {
this.position = this.position;
}
onRealPositionChanged() {
this.realOffset = Vector.sub(this.realPosition, this.viewOrigin);
}
onViewSizeChanged() {
this.position = this.position;
this.viewOrigin = Vector.scale(this.viewSize, 0.5);
this.realOffset = Vector.sub(this.realPosition, this.viewOrigin);
}
get position() {
return super.position;
}
set position(position) {
if (0 === Vector.area(this.areaSize)) {
return super.position = position;
}
if (0 === Vector.area(this.viewSize)) {
return super.position = position;
}
const viewOrigin = this.viewOrigin;
super.position = Vector.clamp(
position,
viewOrigin,
Vector.sub(this.areaSize, viewOrigin)
);
}
get rectangle() {
return Rectangle.compose(
Vector.sub(this.position, this.viewOrigin),
this.viewSize,
);
}
tick(elapsed) {
if (Vector.equals(this.position, this.realPosition)) {
return;
}
if (0 === this.drag) {
this.realPosition = this.position;
}
if (Vector.equalsClose(this.position, this.realPosition, 0.5)) {
this.realPosition = this.position;
return;
}
// Sanity check.
const k = elapsed / this.drag;
if (k >= 1) {
this.realPosition = this.position;
return;
}
const diff = Vector.sub(this.position, this.realPosition);
const magnitude = Vector.scale(diff, k);
this.realPosition = Vector.add(this.realPosition, magnitude);
}
}