497 lines
16 KiB
TypeScript
497 lines
16 KiB
TypeScript
module transform {
|
||
export enum Component {
|
||
position,
|
||
scale,
|
||
rotation,
|
||
}
|
||
}
|
||
|
||
module es {
|
||
export enum DirtyType {
|
||
clean = 0,
|
||
positionDirty = 1,
|
||
scaleDirty = 2,
|
||
rotationDirty = 4,
|
||
}
|
||
|
||
export class Transform {
|
||
/** 与此转换关联的实体 */
|
||
public readonly entity: Entity;
|
||
public hierarchyDirty: DirtyType;
|
||
public _localDirty: boolean;
|
||
public _localPositionDirty: boolean;
|
||
public _localScaleDirty: boolean;
|
||
public _localRotationDirty: boolean;
|
||
public _positionDirty: boolean;
|
||
public _worldToLocalDirty: boolean;
|
||
public _worldInverseDirty: boolean;
|
||
/**
|
||
* 值会根据位置、旋转和比例自动重新计算
|
||
*/
|
||
public _localTransform: Matrix2D;
|
||
/**
|
||
* 值将自动从本地和父矩阵重新计算。
|
||
*/
|
||
public _worldTransform = Matrix2D.identity;
|
||
public _rotationMatrix: Matrix2D = Matrix2D.identity;
|
||
public _translationMatrix: Matrix2D = Matrix2D.identity;
|
||
public _scaleMatrix: Matrix2D;
|
||
public _children: Transform[] = [];
|
||
|
||
constructor(entity: Entity) {
|
||
this.entity = entity;
|
||
this.scale = this._localScale = Vector2.one;
|
||
}
|
||
|
||
/**
|
||
* 这个转换的所有子元素
|
||
*/
|
||
public get childCount() {
|
||
return this._children.length;
|
||
}
|
||
|
||
/**
|
||
* 变换在世界空间的旋转度
|
||
*/
|
||
public get rotationDegrees(): number {
|
||
return MathHelper.toDegrees(this._rotation);
|
||
}
|
||
|
||
/**
|
||
* 变换在世界空间的旋转度
|
||
* @param value
|
||
*/
|
||
public set rotationDegrees(value: number) {
|
||
this.setRotation(MathHelper.toRadians(value));
|
||
}
|
||
|
||
/**
|
||
* 旋转相对于父变换旋转的角度
|
||
*/
|
||
public get localRotationDegrees(): number {
|
||
return MathHelper.toDegrees(this._localRotation);
|
||
}
|
||
|
||
/**
|
||
* 旋转相对于父变换旋转的角度
|
||
* @param value
|
||
*/
|
||
public set localRotationDegrees(value: number) {
|
||
this.localRotation = MathHelper.toRadians(value);
|
||
}
|
||
|
||
public get localToWorldTransform(): Matrix2D {
|
||
this.updateTransform();
|
||
return this._worldTransform;
|
||
}
|
||
|
||
public _parent: Transform;
|
||
|
||
/**
|
||
* 获取此转换的父转换
|
||
*/
|
||
public get parent() {
|
||
return this._parent;
|
||
}
|
||
|
||
/**
|
||
* 设置此转换的父转换
|
||
* @param value
|
||
*/
|
||
public set parent(value: Transform) {
|
||
this.setParent(value);
|
||
}
|
||
|
||
public _worldToLocalTransform = Matrix2D.identity;
|
||
|
||
public get worldToLocalTransform(): Matrix2D {
|
||
if (this._worldToLocalDirty) {
|
||
if (!this.parent) {
|
||
this._worldToLocalTransform = Matrix2D.identity;
|
||
} else {
|
||
this.parent.updateTransform();
|
||
this._worldToLocalTransform = Matrix2D.invert(this.parent._worldTransform);
|
||
}
|
||
|
||
this._worldToLocalDirty = false;
|
||
}
|
||
|
||
return this._worldToLocalTransform;
|
||
}
|
||
|
||
public _worldInverseTransform = Matrix2D.identity;
|
||
|
||
public get worldInverseTransform(): Matrix2D {
|
||
this.updateTransform();
|
||
if (this._worldInverseDirty) {
|
||
this._worldInverseTransform = Matrix2D.invert(this._worldTransform);
|
||
this._worldInverseDirty = false;
|
||
}
|
||
|
||
return this._worldInverseTransform;
|
||
}
|
||
|
||
public _position: Vector2 = Vector2.zero;
|
||
|
||
/**
|
||
* 变换在世界空间中的位置
|
||
*/
|
||
public get position(): Vector2 {
|
||
this.updateTransform();
|
||
if (this._positionDirty) {
|
||
if (this.parent == null) {
|
||
this._position = this._localPosition;
|
||
} else {
|
||
this.parent.updateTransform();
|
||
Vector2Ext.transformR(this._localPosition, this.parent._worldTransform, this._position);
|
||
}
|
||
|
||
this._positionDirty = false;
|
||
}
|
||
|
||
return this._position;
|
||
}
|
||
|
||
/**
|
||
* 变换在世界空间中的位置
|
||
* @param value
|
||
*/
|
||
public set position(value: Vector2) {
|
||
this.setPosition(value.x, value.y);
|
||
}
|
||
|
||
public _scale: Vector2 = Vector2.one;
|
||
|
||
/**
|
||
* 变换在世界空间的缩放
|
||
*/
|
||
public get scale(): Vector2 {
|
||
this.updateTransform();
|
||
return this._scale;
|
||
}
|
||
|
||
/**
|
||
* 变换在世界空间的缩放
|
||
* @param value
|
||
*/
|
||
public set scale(value: Vector2) {
|
||
this.setScale(value);
|
||
}
|
||
|
||
public _rotation: number = 0;
|
||
|
||
/**
|
||
* 在世界空间中以弧度旋转的变换
|
||
*/
|
||
public get rotation(): number {
|
||
this.updateTransform();
|
||
return this._rotation;
|
||
}
|
||
|
||
/**
|
||
* 变换在世界空间的旋转度
|
||
* @param value
|
||
*/
|
||
public set rotation(value: number) {
|
||
this.setRotation(value);
|
||
}
|
||
|
||
public _localPosition: Vector2 = Vector2.zero;
|
||
|
||
/**
|
||
* 转换相对于父转换的位置。如果转换没有父元素,则与transform.position相同
|
||
*/
|
||
public get localPosition(): Vector2 {
|
||
this.updateTransform();
|
||
return this._localPosition;
|
||
}
|
||
|
||
/**
|
||
* 转换相对于父转换的位置。如果转换没有父元素,则与transform.position相同
|
||
* @param value
|
||
*/
|
||
public set localPosition(value: Vector2) {
|
||
this.setLocalPosition(value);
|
||
}
|
||
|
||
public _localScale: Vector2 = Vector2.one;
|
||
|
||
/**
|
||
* 转换相对于父元素的比例。如果转换没有父元素,则与transform.scale相同
|
||
*/
|
||
public get localScale(): Vector2 {
|
||
this.updateTransform();
|
||
return this._localScale;
|
||
}
|
||
|
||
/**
|
||
* 转换相对于父元素的比例。如果转换没有父元素,则与transform.scale相同
|
||
* @param value
|
||
*/
|
||
public set localScale(value: Vector2) {
|
||
this.setLocalScale(value);
|
||
}
|
||
|
||
public _localRotation: number = 0;
|
||
|
||
/**
|
||
* 相对于父变换的旋转,变换的旋转。如果转换没有父元素,则与transform.rotation相同
|
||
*/
|
||
public get localRotation(): number {
|
||
this.updateTransform();
|
||
return this._localRotation;
|
||
}
|
||
|
||
/**
|
||
* 相对于父变换的旋转,变换的旋转。如果转换没有父元素,则与transform.rotation相同
|
||
* @param value
|
||
*/
|
||
public set localRotation(value: number) {
|
||
this.setLocalRotation(value);
|
||
}
|
||
|
||
/**
|
||
* 返回在索引处的转换子元素
|
||
* @param index
|
||
*/
|
||
public getChild(index: number): Transform {
|
||
return this._children[index];
|
||
}
|
||
|
||
/**
|
||
* 设置此转换的父转换
|
||
* @param parent
|
||
*/
|
||
public setParent(parent: Transform): Transform {
|
||
if (this._parent == parent)
|
||
return this;
|
||
|
||
if (!this._parent) {
|
||
let children = new es.List(this._parent._children);
|
||
children.remove(this);
|
||
children.add(this);
|
||
}
|
||
|
||
this._parent = parent;
|
||
this.setDirty(DirtyType.positionDirty);
|
||
|
||
return this;
|
||
}
|
||
|
||
/**
|
||
* 设置转换在世界空间中的位置
|
||
* @param x
|
||
* @param y
|
||
*/
|
||
public setPosition(x: number, y: number): Transform {
|
||
let position = new Vector2(x, y);
|
||
if (position.equals(this._position))
|
||
return this;
|
||
|
||
this._position = position;
|
||
if (this.parent != null) {
|
||
this.localPosition = Vector2.transform(this._position, this._worldToLocalTransform);
|
||
} else {
|
||
this.localPosition = position;
|
||
}
|
||
this._positionDirty = false;
|
||
|
||
return this;
|
||
}
|
||
|
||
/**
|
||
* 设置转换相对于父转换的位置。如果转换没有父元素,则与transform.position相同
|
||
* @param localPosition
|
||
*/
|
||
public setLocalPosition(localPosition: Vector2): Transform {
|
||
if (localPosition.equals(this._localPosition))
|
||
return this;
|
||
|
||
this._localPosition = localPosition;
|
||
this._localDirty = this._positionDirty = this._localPositionDirty = this._localRotationDirty = this._localScaleDirty = true;
|
||
this.setDirty(DirtyType.positionDirty);
|
||
|
||
return this;
|
||
}
|
||
|
||
|
||
/**
|
||
* 设置变换在世界空间的旋转度
|
||
* @param radians
|
||
*/
|
||
public setRotation(radians: number): Transform {
|
||
this._rotation = radians;
|
||
if (this.parent) {
|
||
this.localRotation = this.parent.rotation + radians;
|
||
} else {
|
||
this.localRotation = radians;
|
||
}
|
||
|
||
return this;
|
||
}
|
||
|
||
/**
|
||
* 设置变换在世界空间的旋转度
|
||
* @param degrees
|
||
*/
|
||
public setRotationDegrees(degrees: number): Transform {
|
||
return this.setRotation(MathHelper.toRadians(degrees));
|
||
}
|
||
|
||
/**
|
||
* 旋转精灵的顶部,使其朝向位置
|
||
* @param pos
|
||
*/
|
||
public lookAt(pos: Vector2) {
|
||
let sign = this.position.x > pos.x ? -1 : 1;
|
||
let vectorToAlignTo = Vector2.normalize(Vector2.subtract(this.position, pos));
|
||
this.rotation = sign * Math.acos(Vector2.dot(vectorToAlignTo, Vector2.unitY));
|
||
}
|
||
|
||
/**
|
||
* 相对于父变换的旋转设置变换的旋转。如果转换没有父元素,则与transform.rotation相同
|
||
* @param radians
|
||
*/
|
||
public setLocalRotation(radians: number) {
|
||
this._localRotation = radians;
|
||
this._localDirty = this._positionDirty = this._localPositionDirty = this._localRotationDirty = this._localScaleDirty = true;
|
||
this.setDirty(DirtyType.rotationDirty);
|
||
|
||
return this;
|
||
}
|
||
|
||
/**
|
||
* 相对于父变换的旋转设置变换的旋转。如果转换没有父元素,则与transform.rotation相同
|
||
* @param degrees
|
||
*/
|
||
public setLocalRotationDegrees(degrees: number): Transform {
|
||
return this.setLocalRotation(MathHelper.toRadians(degrees));
|
||
}
|
||
|
||
/**
|
||
* 设置变换在世界空间中的缩放
|
||
* @param scale
|
||
*/
|
||
public setScale(scale: Vector2): Transform {
|
||
this._scale = scale;
|
||
if (this.parent) {
|
||
this.localScale = Vector2.divide(scale, this.parent._scale);
|
||
} else {
|
||
this.localScale = scale;
|
||
}
|
||
return this;
|
||
}
|
||
|
||
/**
|
||
* 设置转换相对于父对象的比例。如果转换没有父元素,则与transform.scale相同
|
||
* @param scale
|
||
*/
|
||
public setLocalScale(scale: Vector2): Transform {
|
||
this._localScale = scale;
|
||
this._localDirty = this._positionDirty = this._localScaleDirty = true;
|
||
this.setDirty(DirtyType.scaleDirty);
|
||
|
||
return this;
|
||
}
|
||
|
||
/**
|
||
* 对精灵坐标进行四舍五入
|
||
*/
|
||
public roundPosition() {
|
||
this.position = Vector2Ext.round(this._position);
|
||
}
|
||
|
||
public updateTransform() {
|
||
if (this.hierarchyDirty != DirtyType.clean) {
|
||
if (this.parent != null)
|
||
this.parent.updateTransform();
|
||
|
||
if (this._localDirty) {
|
||
if (this._localPositionDirty) {
|
||
this._translationMatrix = Matrix2D.createTranslation(this._localPosition.x, this._localPosition.y);
|
||
this._localPositionDirty = false;
|
||
}
|
||
|
||
if (this._localRotationDirty) {
|
||
this._rotationMatrix = Matrix2D.createRotation(this._localRotation);
|
||
this._localRotationDirty = false;
|
||
}
|
||
|
||
if (this._localScaleDirty) {
|
||
this._scaleMatrix = Matrix2D.createScale(this._localScale.x, this._localScale.y);
|
||
this._localScaleDirty = false;
|
||
}
|
||
|
||
this._localTransform = this._scaleMatrix.multiply(this._rotationMatrix);
|
||
this._localTransform = this._localTransform.multiply(this._translationMatrix);
|
||
|
||
if (this.parent == null) {
|
||
this._worldTransform = this._localTransform;
|
||
this._rotation = this._localRotation;
|
||
this._scale = this._localScale;
|
||
this._worldInverseDirty = true;
|
||
}
|
||
|
||
this._localDirty = false;
|
||
}
|
||
|
||
if (this.parent != null) {
|
||
this._worldTransform = this._localTransform.multiply(this.parent._worldTransform);
|
||
|
||
this._rotation = this._localRotation + this.parent._rotation;
|
||
this._scale = Vector2.multiply(this.parent._scale, this._localScale);
|
||
this._worldInverseDirty = true;
|
||
}
|
||
|
||
this._worldToLocalDirty = true;
|
||
this._positionDirty = true;
|
||
this.hierarchyDirty = DirtyType.clean;
|
||
}
|
||
}
|
||
|
||
public setDirty(dirtyFlagType: DirtyType) {
|
||
if ((this.hierarchyDirty & dirtyFlagType) == 0) {
|
||
this.hierarchyDirty |= dirtyFlagType;
|
||
|
||
switch (dirtyFlagType) {
|
||
case es.DirtyType.positionDirty:
|
||
this.entity.onTransformChanged(transform.Component.position);
|
||
break;
|
||
case es.DirtyType.rotationDirty:
|
||
this.entity.onTransformChanged(transform.Component.rotation);
|
||
break;
|
||
case es.DirtyType.scaleDirty:
|
||
this.entity.onTransformChanged(transform.Component.scale);
|
||
break;
|
||
}
|
||
|
||
// 告诉子项发生了变换
|
||
for (let i = 0; i < this._children.length; i++)
|
||
this._children[i].setDirty(dirtyFlagType);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 从另一个transform属性进行拷贝
|
||
* @param transform
|
||
*/
|
||
public copyFrom(transform: Transform) {
|
||
this._position = transform.position;
|
||
this._localPosition = transform._localPosition;
|
||
this._rotation = transform._rotation;
|
||
this._localRotation = transform._localRotation;
|
||
this._scale = transform._scale;
|
||
this._localScale = transform._localScale;
|
||
|
||
this.setDirty(DirtyType.positionDirty);
|
||
this.setDirty(DirtyType.rotationDirty);
|
||
this.setDirty(DirtyType.scaleDirty);
|
||
}
|
||
|
||
public toString(): string {
|
||
return `[Transform: parent: ${this.parent}, position: ${this.position}, rotation: ${this.rotation},
|
||
scale: ${this.scale}, localPosition: ${this._localPosition}, localRotation: ${this._localRotation},
|
||
localScale: ${this._localScale}]`;
|
||
}
|
||
}
|
||
} |