convex-pixel
Version:
The library for creating pseudo 3d interactive scenes based on webgl
203 lines • 7.22 kB
JavaScript
import { TweenMax, Expo, Sine } from "gsap";
import * as PIXI from "pixi.js";
import * as SonarUtils from "../utils/sonar";
import { CameraControllerManager, CameraControllerEventTypes } from "./controller";
import { Vector2D } from "../utils/geom";
const DEFAULT_BOUNDS = new PIXI.Rectangle(0, 0, 640, 480);
export class Camera extends PIXI.utils.EventEmitter {
constructor(_room, _viewport = DEFAULT_BOUNDS, config) {
super();
this._room = _room;
this._viewport = _viewport;
this._x = 0;
this._y = 0;
this._cameraPosition = Vector2D.new();
this._pov = Vector2D.new();
this._maxZoom = 1;
this._handlerCameraMove = (target) => {
const needAnimation = this.normalizeCameraMove(target);
if (!needAnimation) {
this._handlePivotUpdate();
return;
}
if (this._tweenPivot) {
this._tweenPivot.updateTo({ x: target.x, y: target.y }, true);
}
else {
this._tweenPivot = TweenMax.to(this._cameraPosition, 2, {
x: target.x,
y: target.y,
onUpdate: this._handlePivotUpdate,
ease: Sine.easeOut,
});
}
target.free();
};
this._handlerCameraPOV = (target) => {
this.normalizeCameraPOV(target);
if (this._tweenPOV) {
this._tweenPOV.updateTo({ x: target.x, y: target.y }, true);
}
else {
this._tweenPOV = TweenMax.to(this._pov, 0.5, {
x: target.x,
y: target.y,
onUpdate: this._handlePOVUpdate,
ease: Expo.easeOut,
});
}
target.free();
};
this._handlePivotUpdate = () => {
this._x = this._cameraPosition.x;
this._y = this._cameraPosition.y;
this.emit(CameraControllerEventTypes.MOVE, this._cameraPosition);
};
this._handlePOVUpdate = () => {
this.emit(CameraControllerEventTypes.POV, this._pov);
};
this._handlerCameraZoom = (zoom) => {
this.emit(CameraControllerEventTypes.ZOOM, zoom);
};
this._handlerCameraRotate = (rotation) => {
this.emit(CameraControllerEventTypes.ROTATE, rotation);
};
this._povFactor = config.pov || 1;
this._dof = (1 / (config.dof || 35)) * 30;
this._maxXOffset = config.maxXOffset || 100;
this._maxYOffset = config.maxYOffset || 100;
this._xOffset = config.xOffset || 10;
this._yOffset = config.yOffset || 10;
this._float = config.float || false;
this.createControllerManager();
this._sonarViewport = new SonarUtils.SonarDetector(this._viewport, ["x", "y", "width", "height"], "change");
this._sonarViewport.addListener("change", () => {
// this.emit("change-bound", { ...this._bounds });
});
}
get room() {
return this._room;
}
set maxZoom(v) {
this._maxZoom = v;
this.emit(CameraControllerEventTypes.ZOOM, { maxZoom: this._maxZoom });
// reposition the camera target
TweenMax.killTweensOf(this._cameraPosition);
this.normalizeCameraMove(this._cameraPosition);
this._handlePivotUpdate();
// reset pov factor
TweenMax.killTweensOf(this._pov);
this.normalizeCameraPOV(this._pov);
this._handlePOVUpdate();
}
get maxZoom() {
return this._maxZoom;
}
/**
* If you change the properties of the Bound then the Sonar will
* begin to check it for changes.
*/
get viewport() {
return this._viewport;
}
get float() {
return this._float;
}
/**
* Returns PointOfView
*/
get pov() {
return this._pov;
}
get dof() {
return this._dof;
}
get controllers() {
return this._controllers;
}
get x() {
return this._x;
}
get y() {
return this._y;
}
get povFactor() {
return this._povFactor;
}
get maxXOffset() {
return this._maxXOffset;
}
get maxYOffset() {
return this._maxYOffset;
}
get xOffset() {
return this._xOffset;
}
get yOffset() {
return this._yOffset;
}
destroy() {
if (this._tweenPivot) {
this._tweenPivot.kill();
this._tweenPivot = undefined;
}
this.removeControllerManager();
this._sonarViewport.destroy();
this._cameraPosition.free();
this._pov.free();
}
/**
* Normalize and modify the target
*/
normalizeCameraMove(target) {
const sceneBounds = this._room.roomBound;
const sWidth = sceneBounds.width * this._room.scale.x;
const sHeight = sceneBounds.height * this._room.scale.y;
const maxX = sWidth - this._viewport.width;
const maxY = sHeight - this._viewport.height;
if (maxX <= 0) {
target.x = maxX * 0.5;
}
else {
if (target.x > maxX)
target.x = maxX;
else if (target.x < 0)
target.x = 0;
}
if (maxY <= 0) {
target.y = maxY * 0.5;
}
else {
if (target.y > maxY)
target.y = maxY;
else if (target.y < 0)
target.y = 0;
}
return true;
}
normalizeCameraPOV(target) {
/*if (this._maxXOffset && Math.abs(target.x) > this._maxXOffset) {
target.x = this._maxXOffset * Math.sign(target.x);
}
if (this._maxYOffset && Math.abs(target.y) > this._maxYOffset) {
target.y = this._maxYOffset * Math.sign(target.y);
}*/
}
createControllerManager() {
this._controllers = new CameraControllerManager(this);
this._controllers.addListener(CameraControllerEventTypes.MOVE, this._handlerCameraMove);
this._controllers.addListener(CameraControllerEventTypes.POV, this._handlerCameraPOV);
this._controllers.addListener(CameraControllerEventTypes.ZOOM, this._handlerCameraZoom);
this._controllers.addListener(CameraControllerEventTypes.ROTATE, this._handlerCameraRotate);
}
removeControllerManager() {
if (this._controllers) {
this._controllers.removeListener(CameraControllerEventTypes.MOVE, this._handlerCameraMove);
this._controllers.removeListener(CameraControllerEventTypes.POV, this._handlerCameraPOV);
this._controllers.removeListener(CameraControllerEventTypes.ZOOM, this._handlerCameraZoom);
this._controllers.removeListener(CameraControllerEventTypes.ROTATE, this._handlerCameraRotate);
this._controllers.destroy();
}
}
}
//# sourceMappingURL=camera.js.map