优化matrix

This commit is contained in:
yhh
2020-07-23 13:25:10 +08:00
parent 1b52bc5fd1
commit e61dd0c16b
12 changed files with 1009 additions and 494 deletions

View File

@@ -4,6 +4,13 @@ module es {
cameraWindow,
}
export class CameraInset {
public left: number;
public right: number;
public top: number;
public bottom: number;
}
export class Camera extends Component {
/**
* 对entity.transform.position的快速访问
@@ -89,10 +96,61 @@ module es {
}
/**
* 相机的边框
* 相机的世界-空间边界
*/
public get bounds(){
return new Rectangle(0, 0, SceneManager.stage.stageWidth, SceneManager.stage.stageHeight);
if (this._areMatrixedDirty)
this.updateMatrixes();
if (this._areBoundsDirty){
// 旋转或非旋转的边界都需要左上角和右下角
let topLeft = this.screenToWorldPoint(new Vector2(this._inset.left, this._inset.top));
let bottomRight = this.screenToWorldPoint(new Vector2(SceneManager.stage.stageWidth - this._inset.right,
SceneManager.stage.stageHeight - this._inset.bottom));
if (this.entity.transform.rotation != 0){
// 特别注意旋转的边界。我们需要找到绝对的最小/最大值并从中创建边界
let topRight = this.screenToWorldPoint(new Vector2(SceneManager.stage.stageWidth - this._inset.right,
this._inset.top));
let bottomLeft = this.screenToWorldPoint(new Vector2(this._inset.left,
SceneManager.stage.stageHeight - this._inset.bottom));
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 = maxX - minY;
} 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;
}
/**
* 用于从世界坐标转换到屏幕
*/
public get transformMatrix(): Matrix2D {
if (this._areMatrixedDirty)
this.updateMatrixes();
return this._transformMatrix;
}
/**
* 用于从屏幕坐标到世界的转换
*/
public get inverseTransformMatrix(): Matrix2D {
if (this._areMatrixedDirty)
this.updateMatrixes();
return this._inverseTransformMatrix;
}
public get origin() {
@@ -102,13 +160,23 @@ module es {
public set origin(value: Vector2) {
if (this._origin != value) {
this._origin = value;
this._areMatrixedDirty = true;
}
}
private _zoom;
private _minimumZoom = 0.3;
private _maximumZoom = 3;
private _origin: Vector2 = Vector2.zero;
public _zoom;
public _minimumZoom = 0.3;
public _maximumZoom = 3;
public _bounds: Rectangle;
public _inset: CameraInset;
public _transformMatrix: Matrix2D = new Matrix2D().identity();
public _inverseTransformMatrix: Matrix2D = new Matrix2D().identity();
public _origin: Vector2 = Vector2.zero;
public _areMatrixedDirty: boolean = true;
public _areBoundsDirty: boolean = true;
public _isProjectionMatrixDirty = true;
/**
* 如果相机模式为cameraWindow 则会进行缓动移动
* 该值为移动速度
@@ -158,6 +226,50 @@ module es {
this.entity.transform.position = Vector2.add(this.entity.transform.position, Vector2.subtract(this._origin, oldOrigin));
}
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(this._origin.x, this._origin.y);
this._transformMatrix =this._transformMatrix.multiply(tempMat);
this._inverseTransformMatrix = this._transformMatrix.invert();
// 无论何时矩阵改变边界都是无效的
this._areBoundsDirty = true;
this._areMatrixedDirty = false;
}
/**
* 设置用于从视口边缘插入摄像机边界的量
* @param left
* @param right
* @param top
* @param bottom
*/
public setInset(left: number, right: number, top: number, bottom: number): Camera {
this._inset = new CameraInset();
this._inset.left = left;
this._inset.right = right;
this._inset.top = top;
this._inset.bottom = bottom;
this._areBoundsDirty = true;
return this;
}
/**
* 对entity.transform.setPosition快速访问
* @param position
@@ -190,9 +302,8 @@ module es {
} else {
this._zoom = MathHelper.map(newZoom, 0, 1, 1, this._maximumZoom);
}
this._areMatrixedDirty = true;
SceneManager.scene.scaleX = this._zoom;
SceneManager.scene.scaleY = this._zoom;
return this;
}
@@ -201,6 +312,11 @@ module es {
* @param minZoom
*/
public setMinimumZoom(minZoom: number): Camera {
if (minZoom <= 0) {
console.error("minimumZoom must be greater than zero");
return;
}
if (this._zoom < minZoom)
this._zoom = this.minimumZoom;
@@ -225,6 +341,10 @@ module es {
return this;
}
public onEntityTransformChanged(comp: transform.Component) {
this._areMatrixedDirty = true;
}
public zoomIn(deltaZoom: number) {
this.zoom += deltaZoom;
}
@@ -233,6 +353,33 @@ module es {
this.zoom -= deltaZoom;
}
/**
* 将一个点从世界坐标转换到屏幕
* @param worldPosition
*/
public worldToScreenPoint(worldPosition: Vector2): Vector2{
this.updateMatrixes();
worldPosition = Vector2.transform(worldPosition, this._transformMatrix);
return worldPosition;
}
/**
* 将点从屏幕坐标转换为世界坐标
* @param screenPosition
*/
public screenToWorldPoint(screenPosition: Vector2): Vector2{
this.updateMatrixes();
screenPosition = Vector2.transform(screenPosition, this._inverseTransformMatrix);
return screenPosition;
}
/**
* 返回鼠标在世界空间中的位置
*/
public mouseToWorldPoint(): Vector2{
return this.screenToWorldPoint(Input.touchPosition);
}
public onAddedToEntity() {
this.follow(this._targetEntity, this._cameraStyle);
}

View File

@@ -4,11 +4,12 @@ module es {
* 对撞机的基本形状
*/
public shape: Shape;
/**
* 将localOffset添加到实体。获取碰撞器几何图形的最终位置。
* 允许向一个实体添加多个碰撞器并分别定位,还允许你设置缩放/旋转
*/
public get localOffset(): Vector2{
public get localOffset(): Vector2 {
return this._localOffset;
}
@@ -17,21 +18,21 @@ module es {
* 允许向一个实体添加多个碰撞器并分别定位,还允许你设置缩放/旋转
* @param value
*/
public set localOffset(value: Vector2){
public set localOffset(value: Vector2) {
this.setLocalOffset(value);
}
/**
* 镖师碰撞器的绝对位置
*/
public get absolutePosition(): Vector2{
public get absolutePosition(): Vector2 {
return Vector2.add(this.entity.transform.position, this._localOffset);
}
/**
* 封装变换。如果碰撞器没和实体一起旋转 则返回transform.rotation
*/
public get rotation(): number{
public get rotation(): number {
if (this.shouldColliderScaleAndRotateWithTransform && this.entity)
return this.entity.transform.rotation;
@@ -58,7 +59,10 @@ module es {
public shouldColliderScaleAndRotateWithTransform = true;
public get bounds(): Rectangle {
this.shape.recalculateBounds(this);
if (this._isPositionDirty || this._isRotationDirty){
this.shape.recalculateBounds(this);
this._isPositionDirty = this._isRotationDirty = false;
}
return this.shape.bounds;
}
@@ -81,16 +85,20 @@ module es {
*/
protected _isColliderRegistered;
public _isPositionDirty: boolean = true;
public _isRotationDirty: boolean = true;
/**
* 将localOffset添加到实体。获取碰撞器的最终位置。
* 这允许您向一个实体添加多个碰撞器并分别定位它们。
* @param offset
*/
public setLocalOffset(offset: Vector2): Collider{
if (this._localOffset != offset){
public setLocalOffset(offset: Vector2): Collider {
if (this._localOffset != offset) {
this.unregisterColliderWithPhysicsSystem();
this._localOffset = offset;
this._localOffsetLength = this._localOffset.length();
this._isPositionDirty = true;
this.registerColliderWithPhysicsSystem();
}
@@ -103,6 +111,7 @@ module es {
*/
public setShouldColliderScaleAndRotateWithTransform(shouldColliderScaleAndRotationWithTransform: boolean): Collider {
this.shouldColliderScaleAndRotateWithTransform = shouldColliderScaleAndRotationWithTransform;
this._isPositionDirty = this._isRotationDirty = true;
return this;
}
@@ -121,7 +130,7 @@ module es {
let width = bounds.width / this.entity.scale.x;
let height = bounds.height / this.entity.scale.y;
// 圆碰撞器需要特别注意原点
if (this instanceof CircleCollider){
if (this instanceof CircleCollider) {
let circleCollider = this as CircleCollider;
circleCollider.radius = Math.max(width, height) * 0.5;
} else {
@@ -146,12 +155,25 @@ module es {
}
public onEntityTransformChanged(comp: transform.Component) {
switch (comp) {
case transform.Component.position:
this._isPositionDirty = true;
break;
case transform.Component.scale:
this._isPositionDirty = true;
break;
case transform.Component.rotation:
this._isRotationDirty = true;
break;
}
if (this._isColliderRegistered)
Physics.updateCollider(this);
}
public onEnabled() {
this.registerColliderWithPhysicsSystem();
this._isPositionDirty = this._isRotationDirty = true;
}
public onDisabled() {
@@ -206,5 +228,15 @@ module es {
return result;
}
public clone(): Component{
let collider = ObjectUtils.clone<Collider>(this);
collider.entity = null;
if (this.shape)
collider.shape = this.shape.clone();
return collider;
}
}
}

View File

@@ -2,218 +2,140 @@ module es {
/**
* 表示右手3 * 3的浮点矩阵可以存储平移、缩放和旋转信息。
*/
export class Matrix2D {
public m11: number = 0;
public m12: number = 0;
public m21: number = 0;
public m22: number = 0;
public m31: number = 0;
public m32: number = 0;
private static _identity: Matrix2D = new Matrix2D(1, 0, 0, 1, 0, 0);
/**
* 单位矩阵
*/
public static get identity(){
return Matrix2D._identity;
export class Matrix2D extends egret.Matrix{
public get m11(): number{
return this.a;
}
public set m11(value: number){
this.a = value;
}
public get m12(): number{
return this.b;
}
public set m12(value: number){
this.b = value;
}
public get m21(): number{
return this.c;
}
public set m21(value: number){
this.c = value;
}
public get m22(): number{
return this.d;
}
public set m22(value: number){
this.d = value;
}
public get m31(): number {
return this.tx;
}
public set m31(value: number){
this.tx = value;
}
public get m32(): number{
return this.ty;
}
public set m32(value: number){
this.ty = value;
}
constructor(m11?: number, m12?: number, m21?: number, m22?: number, m31?: number, m32?: number){
this.m11 = m11 ? m11 : 1;
this.m12 = m12 ? m12 : 0;
this.m21 = m21 ? m21 : 0;
this.m22 = m22 ? m22 : 1;
this.m31 = m31 ? m31 : 0;
this.m32 = m32 ? m32 : 0;
public static create(): Matrix2D{
return egret.Matrix.create() as Matrix2D;
}
/** 存储在这个矩阵中的位置 */
public get translation(){
return new Vector2(this.m31, this.m32);
public identity(): Matrix2D{
super.identity();
return this;
}
public set translation(value: Vector2){
this.m31 = value.x;
this.m32 = value.y;
public translate(dx: number, dy: number): Matrix2D {
super.translate(dx, dy);
return this;
}
/** 以弧度表示的旋转存储在这个矩阵中 */
public get rotation(){
return Math.atan2(this.m21, this.m11);
public scale(sx: number, sy: number): Matrix2D {
super.scale(sx, sy);
return this;
}
public set rotation(value: number){
let val1 = Math.cos(value);
let val2 = Math.sin(value);
this.m11 = val1;
this.m12 = val2;
this.m21 = -val2;
this.m22 = val1;
public rotate(angle: number): Matrix2D {
super.rotate(angle);
return this;
}
/**
* 以度为单位的旋转存储在这个矩阵中
*/
public get rotationDegrees(){
return MathHelper.toDegrees(this.rotation);
}
public set rotationDegrees(value: number){
this.rotation = MathHelper.toRadians(value);
}
public get scale(){
return new Vector2(this.m11, this.m22);
}
public set scale(value: Vector2){
this.m11 = value.x;
this.m12 = value.y;
public invert(): Matrix2D {
super.invert();
return this;
}
/**
* 创建一个新的matrix, 它包含两个矩阵的和。
* @param matrix1
* @param matrix2
* @param matrix
*/
public static add(matrix1: Matrix2D, matrix2: Matrix2D){
matrix1.m11 += matrix2.m11;
matrix1.m12 += matrix2.m12;
public add(matrix: Matrix2D): Matrix2D{
this.m11 += matrix.m11;
this.m12 += matrix.m12;
matrix1.m21 += matrix2.m21;
matrix1.m22 += matrix2.m22;
this.m21 += matrix.m21;
this.m22 += matrix.m22;
matrix1.m31 += matrix2.m31;
matrix1.m32 += matrix2.m32;
this.m31 += matrix.m31;
this.m32 += matrix.m32;
return matrix1;
return this;
}
public static divide(matrix1: Matrix2D, matrix2: Matrix2D){
matrix1.m11 /= matrix2.m11;
matrix1.m12 /= matrix2.m12;
public substract(matrix: Matrix2D): Matrix2D {
this.m11 -= matrix.m11;
this.m12 -= matrix.m12;
matrix1.m21 /= matrix2.m21;
matrix1.m22 /= matrix2.m22;
this.m21 -= matrix.m21;
this.m22 -= matrix.m22;
matrix1.m31 /= matrix2.m31;
matrix1.m32 /= matrix2.m32;
this.m31 -= matrix.m31;
this.m32 -= matrix.m32;
return matrix1;
return this;
}
public static multiply(matrix1: Matrix2D, matrix2: Matrix2D){
let result = new Matrix2D();
public divide(matrix: Matrix2D): Matrix2D{
this.m11 /= matrix.m11;
this.m12 /= matrix.m12;
let m11 = ( matrix1.m11 * matrix2.m11 ) + ( matrix1.m12 * matrix2.m21 );
let m12 = ( matrix1.m11 * matrix2.m12 ) + ( matrix1.m12 * matrix2.m22 );
this.m21 /= matrix.m21;
this.m22 /= matrix.m22;
let m21 = ( matrix1.m21 * matrix2.m11 ) + ( matrix1.m22 * matrix2.m21 );
let m22 = ( matrix1.m21 * matrix2.m12 ) + ( matrix1.m22 * matrix2.m22 );
this.m31 /= matrix.m31;
this.m32 /= matrix.m32;
let m31 = ( matrix1.m31 * matrix2.m11 ) + ( matrix1.m32 * matrix2.m21 ) + matrix2.m31;
let m32 = ( matrix1.m31 * matrix2.m12 ) + ( matrix1.m32 * matrix2.m22 ) + matrix2.m32;
result.m11 = m11;
result.m12 = m12;
result.m21 = m21;
result.m22 = m22;
result.m31 = m31;
result.m32 = m32;
return result;
return this;
}
public static multiplyTranslation(matrix: Matrix2D, x: number, y: number){
let trans = Matrix2D.createTranslation(x, y);
return Matrix2D.multiply(matrix, trans);
public multiply(matrix: Matrix2D): Matrix2D{
let m11 = ( this.m11 * matrix.m11 ) + ( this.m12 * matrix.m21 );
let m12 = ( this.m11 * matrix.m12 ) + ( this.m12 * matrix.m22 );
let m21 = ( this.m21 * matrix.m11 ) + ( this.m22 * matrix.m21 );
let m22 = ( this.m21 * matrix.m12 ) + ( this.m22 * matrix.m22 );
let m31 = ( this.m31 * matrix.m11 ) + ( this.m32 * matrix.m21 ) + matrix.m31;
let m32 = ( this.m31 * matrix.m12 ) + ( this.m32 * matrix.m22 ) + matrix.m32;
this.m11 = m11;
this.m12 = m12;
this.m21 = m21;
this.m22 = m22;
this.m31 = m31;
this.m32 = m32;
return this;
}
public determinant(){
return this.m11 * this.m22 - this.m12 * this.m21;
}
public static invert(matrix: Matrix2D, result: Matrix2D = new Matrix2D()){
let det = 1 / matrix.determinant();
result.m11 = matrix.m22 * det;
result.m12 = -matrix.m12 * det;
result.m21 = -matrix.m21 * det;
result.m22 = matrix.m11 * det;
result.m31 = (matrix.m32 * matrix.m21 - matrix.m31 * matrix.m22) * det;
result.m32 = -(matrix.m32 * matrix.m11 - matrix.m31 * matrix.m12) * det;
return result;
}
/**
* 创建一个新的tranlation
* @param xPosition
* @param yPosition
*/
public static createTranslation(xPosition: number, yPosition: number){
let result = new Matrix2D();
result.m11 = 1;
result.m12 = 0;
result.m21 = 0;
result.m22 = 1;
result.m31 = xPosition;
result.m32 = yPosition;
return result;
}
/**
* 根据position 创建一个translation
* @param position
*/
public static createTranslationVector(position: Vector2){
return this.createTranslation(position.x, position.y);
}
public static createRotation(radians: number, result?: Matrix2D){
result = new Matrix2D();
let val1 = Math.cos(radians);
let val2 = Math.sin(radians);
result.m11 = val1;
result.m12 = val2;
result.m21 = -val2;
result.m22 = val1;
return result;
}
public static createScale(xScale: number, yScale: number, result: Matrix2D = new Matrix2D()){
result.m11 = xScale;
result.m12 = 0;
result.m21 = 0;
result.m22 = yScale;
result.m31 = 0;
result.m32 = 0;
return result;
}
public toEgretMatrix(): egret.Matrix{
let matrix = new egret.Matrix(this.m11, this.m12, this.m21, this.m22, this.m31, this.m32);
return matrix;
}
}
}

View File

@@ -34,6 +34,46 @@ module es {
this.y = y ? y : this.x;
}
/**
*
* @param value
*/
public add(value: Vector2): Vector2{
this.x += value.x;
this.y += value.y;
return this;
}
/**
*
* @param value
*/
public divide(value: Vector2): Vector2{
this.x /= value.x;
this.y /= value.y;
return this;
}
/**
*
* @param value
*/
public multiply(value: Vector2): Vector2{
this.x *= value.x;
this.y *= value.y;
return this;
}
/**
*
* @param value
*/
public subtract(value: Vector2){
this.x -= value.x;
this.y -= value.y;
return this;
}
/**
*
* @param value1

View File

@@ -177,7 +177,43 @@ module es {
this.center = collider.localOffset;
if (collider.shouldColliderScaleAndRotateWithTransform){
let hasUnitScale = true;
let tempMat: Matrix2D;
let combinedMatrix = Matrix2D.create().translate(-this._polygonCenter.x, -this._polygonCenter.y);
if (collider.entity.transform.scale != Vector2.zero){
tempMat = Matrix2D.create().scale(collider.entity.transform.scale.x, collider.entity.transform.scale.y);
combinedMatrix = combinedMatrix.multiply(tempMat);
hasUnitScale = false;
// 缩放偏移量并将其设置为中心。如果我们有旋转,它会在下面重置
this.center = Vector2.multiply(collider.localOffset, collider.entity.transform.scale);
}
if (collider.entity.transform.rotation != 0){
tempMat = Matrix2D.create().rotate(collider.entity.transform.rotation);
combinedMatrix = combinedMatrix.multiply(tempMat);
// 为了处理偏移原点的旋转我们只需要将圆心在(0,0)附近移动
// 我们的偏移使角度为0我们还需要处理这里的比例所以我们先对偏移进行缩放以得到合适的长度。
let offsetAngle = Math.atan2(collider.localOffset.y, collider.localOffset.x);
let offsetLength = hasUnitScale ? collider._localOffsetLength :
Vector2.multiply(collider.localOffset, collider.entity.transform.scale).length();
this.center = MathHelper.pointOnCirlce(Vector2.zero, offsetLength,
collider.entity.transform.rotation + offsetAngle);
}
tempMat = Matrix2D.create().translate(this._polygonCenter.x, this._polygonCenter.y);
combinedMatrix = combinedMatrix.multiply(tempMat);
// 最后变换原始点
Vector2Ext.transform(this._originalPoints, combinedMatrix, this.points);
this.isUnrotated = collider.entity.transform.rotation == 0;
// 如果旋转的话,我们只需要重建边的法线
if (collider._isRotationDirty)
this._areEdgeNormalsDirty = true;
}
this.position = Vector2.add(collider.entity.transform.position, this.center);

View File

@@ -19,5 +19,9 @@ module es {
public abstract pointCollidesWithShape(point: Vector2): CollisionResult;
public abstract overlaps(other: Shape);
public abstract collidesWithShape(other: Shape): CollisionResult;
public clone(): Shape{
return ObjectUtils.clone<Shape>(this);
}
}
}