Files
esengine/source/src/ECS/Components/Camera.ts

370 lines
12 KiB
TypeScript
Raw Normal View History

2020-07-22 20:07:14 +08:00
module es {
2020-10-27 18:08:49 +08:00
export interface CameraInset {
left: number, right: number, top: number, bottom: number
2020-07-23 13:25:10 +08:00
}
2020-07-22 20:07:14 +08:00
export class Camera extends Component {
2020-10-27 18:08:49 +08:00
public _inset: CameraInset = {left: 0, right: 0, top: 0, bottom: 0};
2020-07-28 16:25:20 +08:00
public _areMatrixedDirty: boolean = true;
public _areBoundsDirty: boolean = true;
public _isProjectionMatrixDirty = true;
constructor() {
super();
2020-07-28 16:25:20 +08:00
this.setZoom(0);
}
/**
* entity.transform.position的快速访问
*/
public get position() {
return this.entity.transform.position;
}
2020-07-22 20:07:14 +08:00
/**
* entity.transform.position的快速访问
* @param value
*/
public set position(value: Vector2) {
this.entity.transform.position = value;
}
2020-07-22 20:07:14 +08:00
/**
* entity.transform.rotation的快速访问
2020-07-22 20:07:14 +08:00
*/
public get rotation(): number {
return this.entity.transform.rotation;
}
/**
* entity.transform.rotation的快速访问
* @param value
*/
public set rotation(value: number) {
this.entity.transform.rotation = value;
}
/**
* 1
*/
public get rawZoom(){
return this._zoom;
}
/**
* 1
* @param value
*/
public set rawZoom(value: number){
if (value != this._zoom){
this._zoom = value;
this._areMatrixedDirty = true;
}
}
public _zoom: number = 0;
2020-07-28 16:25:20 +08:00
/**
* -11minimumZoom转换为maximumZoom
* /使-11
*/
public get zoom() {
2020-07-22 20:07:14 +08:00
if (this._zoom == 0)
return 1;
if (this._zoom < 1)
return MathHelper.map(this._zoom, this._minimumZoom, 1, -1, 0);
return MathHelper.map(this._zoom, 1, this._maximumZoom, 0, 1);
}
/**
* -11minimumZoom转换为maximumZoom
* /使-11
* @param value
*/
public set zoom(value: number) {
2020-07-22 20:07:14 +08:00
this.setZoom(value);
}
2020-07-28 16:25:20 +08:00
public _minimumZoom = 0.3;
/**
* 0-number.max0.3
*/
public get minimumZoom() {
2020-07-22 20:07:14 +08:00
return this._minimumZoom;
}
/**
* 0-number.max0.3
* @param value
*/
public set minimumZoom(value: number) {
2020-07-22 20:07:14 +08:00
this.setMinimumZoom(value);
}
2020-07-28 16:25:20 +08:00
public _maximumZoom = 3;
/**
* 0-number.max3
*/
public get maximumZoom() {
2020-07-22 20:07:14 +08:00
return this._maximumZoom;
}
/**
* 0-number.max3
* @param value
*/
public set maximumZoom(value: number) {
2020-07-22 20:07:14 +08:00
this.setMaximumZoom(value);
}
2020-07-28 16:25:20 +08:00
public _bounds: Rectangle = new Rectangle();
/**
2020-07-23 13:25:10 +08:00
* -
*/
2020-07-28 16:25:20 +08:00
public get bounds() {
2020-07-23 13:25:10 +08:00
if (this._areMatrixedDirty)
this.updateMatrixes();
2020-07-28 16:25:20 +08:00
if (this._areBoundsDirty) {
2020-07-23 13:25:10 +08:00
// 旋转或非旋转的边界都需要左上角和右下角
let topLeft = this.screenToWorldPoint(new Vector2(this._inset.left, this._inset.top));
let bottomRight = this.screenToWorldPoint(new Vector2(Core.graphicsDevice.viewport.width - this._inset.right,
Core.graphicsDevice.viewport.height - this._inset.bottom));
2020-07-23 13:25:10 +08:00
2020-07-28 16:25:20 +08:00
if (this.entity.transform.rotation != 0) {
2020-07-23 13:25:10 +08:00
// 特别注意旋转的边界。我们需要找到绝对的最小/最大值并从中创建边界
let topRight = this.screenToWorldPoint(new Vector2(Core.graphicsDevice.viewport.width - this._inset.right,
2020-07-23 13:25:10 +08:00
this._inset.top));
let bottomLeft = this.screenToWorldPoint(new Vector2(this._inset.left,
Core.graphicsDevice.viewport.height - this._inset.bottom));
2020-07-23 13:25:10 +08:00
let minX = Math.min(topLeft.x, bottomRight.x, topRight.x, bottomLeft.x);
let maxX = Math.max(topLeft.x, bottomRight.x, topRight.x, bottomLeft.x);
let minY = Math.min(topLeft.y, bottomRight.y, topRight.y, bottomLeft.y);
let maxY = Math.max(topLeft.y, bottomRight.y, topRight.y, bottomLeft.y);
this._bounds.location = new Vector2(minX, minY);
this._bounds.width = maxX - minX;
this._bounds.height = maxY - minY;
2020-07-23 13:25:10 +08:00
} else {
this._bounds.location = topLeft;
this._bounds.width = bottomRight.x - topLeft.x;
this._bounds.height = bottomRight.y - topLeft.y;
}
this._areBoundsDirty = false;
}
return this._bounds;
}
2020-07-28 16:25:20 +08:00
public _transformMatrix: Matrix2D = new Matrix2D().identity();
2020-07-23 13:25:10 +08:00
/**
*
*/
public get transformMatrix(): Matrix2D {
if (this._areMatrixedDirty)
this.updateMatrixes();
return this._transformMatrix;
}
2020-07-28 16:25:20 +08:00
public _inverseTransformMatrix: Matrix2D = new Matrix2D().identity();
2020-07-23 13:25:10 +08:00
/**
*
*/
public get inverseTransformMatrix(): Matrix2D {
if (this._areMatrixedDirty)
this.updateMatrixes();
return this._inverseTransformMatrix;
}
2020-07-28 16:25:20 +08:00
public _origin: Vector2 = Vector2.zero;
public get origin() {
2020-07-22 20:07:14 +08:00
return this._origin;
}
public set origin(value: Vector2) {
if (this._origin != value) {
2020-07-22 20:07:14 +08:00
this._origin = value;
2020-07-23 13:25:10 +08:00
this._areMatrixedDirty = true;
2020-07-22 20:07:14 +08:00
}
}
2020-06-19 09:16:49 +08:00
2020-07-23 13:25:10 +08:00
/**
*
* @param left
* @param right
* @param top
* @param bottom
*/
public setInset(left: number, right: number, top: number, bottom: number): Camera {
2020-10-27 18:08:49 +08:00
this._inset = {left: left, right: right, top: top, bottom: bottom};
2020-07-23 13:25:10 +08:00
this._areBoundsDirty = true;
return this;
}
/**
* entity.transform.setPosition快速访问
* @param position
*/
public setPosition(position: Vector2) {
this.entity.transform.setPosition(position.x, position.y);
2020-07-22 20:07:14 +08:00
return this;
}
/**
* entity.transform.setRotation的快速访问
* @param rotation
*/
public setRotation(rotation: number): Camera {
this.entity.transform.setRotation(rotation);
2020-07-22 20:07:14 +08:00
return this;
}
/**
* -11minimumZoom转换为maximumZoom
* /使-11
* @param zoom
*/
public setZoom(zoom: number): Camera {
2020-07-22 20:07:14 +08:00
let newZoom = MathHelper.clamp(zoom, -1, 1);
if (newZoom == 0) {
2020-07-22 20:07:14 +08:00
this._zoom = 1;
} else if (newZoom < 0) {
2020-07-22 20:07:14 +08:00
this._zoom = MathHelper.map(newZoom, -1, 0, this._minimumZoom, 1);
} else {
this._zoom = MathHelper.map(newZoom, 0, 1, 1, this._maximumZoom);
}
2020-07-23 13:25:10 +08:00
this._areMatrixedDirty = true;
2020-07-22 20:07:14 +08:00
return this;
}
2020-06-08 16:23:48 +08:00
/**
* 0-number.max 0.3
* @param minZoom
*/
public setMinimumZoom(minZoom: number): Camera {
2020-07-23 13:25:10 +08:00
if (minZoom <= 0) {
console.error("minimumZoom must be greater than zero");
return;
}
if (this._zoom < minZoom)
this._zoom = this.minimumZoom;
this._minimumZoom = minZoom;
2020-07-22 20:07:14 +08:00
return this;
}
2020-06-08 16:23:48 +08:00
/**
* 0-number.max 3
* @param maxZoom
*/
public setMaximumZoom(maxZoom: number): Camera {
if (maxZoom <= 0) {
console.error("maximumZoom must be greater than zero");
return;
}
if (this._zoom > maxZoom)
this._zoom = maxZoom;
2020-06-08 11:49:45 +08:00
this._maximumZoom = maxZoom;
2020-07-22 20:07:14 +08:00
return this;
2020-07-01 14:19:40 +08:00
}
2020-06-19 00:38:37 +08:00
public forceMatrixUpdate(){
// 弄脏矩阵也会自动弄脏边界
this._areMatrixedDirty = true;
}
2020-07-23 13:25:10 +08:00
public onEntityTransformChanged(comp: transform.Component) {
this._areMatrixedDirty = true;
}
public zoomIn(deltaZoom: number) {
this.zoom += deltaZoom;
}
public zoomOut(deltaZoom: number) {
this.zoom -= deltaZoom;
}
2020-07-22 20:07:14 +08:00
2020-07-23 13:25:10 +08:00
/**
*
* @param worldPosition
*/
2020-07-28 16:25:20 +08:00
public worldToScreenPoint(worldPosition: Vector2): Vector2 {
2020-07-23 13:25:10 +08:00
this.updateMatrixes();
Vector2Ext.transformR(worldPosition, this._transformMatrix, worldPosition);
2020-07-23 13:25:10 +08:00
return worldPosition;
}
/**
*
* @param screenPosition
*/
2020-07-28 16:25:20 +08:00
public screenToWorldPoint(screenPosition: Vector2): Vector2 {
2020-07-23 13:25:10 +08:00
this.updateMatrixes();
Vector2Ext.transformR(screenPosition, this._inverseTransformMatrix, screenPosition);
2020-07-23 13:25:10 +08:00
return screenPosition;
}
/**
*
* @param newWidth
* @param newHeight
*/
public onSceneRenderTargetSizeChanged(newWidth: number, newHeight: number){
this._isProjectionMatrixDirty = true;
let oldOrigin = this._origin;
this.origin = new Vector2(newWidth / 2, newHeight / 2);
this.entity.transform.position.add(Vector2.subtract(this._origin, oldOrigin));
}
/**
*
*/
public mouseToWorldPoint(): Vector2 {
return this.screenToWorldPoint(Input.touchPosition);
}
2020-07-28 16:25:20 +08:00
protected updateMatrixes() {
if (!this._areMatrixedDirty)
return;
let tempMat: Matrix2D;
this._transformMatrix = Matrix2D.create().translate(-this.entity.transform.position.x, -this.entity.transform.position.y);
if (this._zoom != 1) {
tempMat = Matrix2D.create().scale(this._zoom, this._zoom);
this._transformMatrix = this._transformMatrix.multiply(tempMat);
}
if (this.entity.transform.rotation != 0) {
tempMat = Matrix2D.create().rotate(this.entity.transform.rotation);
this._transformMatrix = this._transformMatrix.multiply(tempMat);
}
tempMat = Matrix2D.create().translate(Math.floor(this._origin.x), Math.floor(this._origin.y));
2020-07-28 16:25:20 +08:00
this._transformMatrix = this._transformMatrix.multiply(tempMat);
this._inverseTransformMatrix = this._transformMatrix.invert();
// 无论何时矩阵改变边界都是无效的
this._areBoundsDirty = true;
this._areMatrixedDirty = false;
}
2020-07-22 20:07:14 +08:00
}
}