109 lines
2.7 KiB
JavaScript
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);
|
|
}
|
|
|
|
}
|