# Conflicts:
#	source/bin/framework.min.js
This commit is contained in:
yhh
2021-05-07 16:24:25 +08:00
9 changed files with 1125 additions and 59 deletions

View File

@@ -122,8 +122,8 @@ module es {
*/
public addImpulse(force: Vector2) {
if (!this.isImmovable) {
this.velocity = Vector2.add(this.velocity, Vector2.multiply(force, new Vector2(100000))
.multiply(new Vector2(this._inverseMass * Time.deltaTime)));
this.velocity = this.velocity.add(Vector2.multiplyScaler(force, 100000)
.multiplyScaler(this._inverseMass * Time.deltaTime * Time.deltaTime));
}
}
@@ -139,9 +139,9 @@ module es {
}
if (this.shouldUseGravity)
this.velocity = Vector2.add(this.velocity, Vector2.multiply(Physics.gravity, new Vector2(Time.deltaTime)));
this.velocity = this.velocity.add(Vector2.multiplyScaler(Physics.gravity, Time.deltaTime));
this.entity.transform.position = Vector2.add(this.entity.transform.position, Vector2.multiply(this.velocity, new Vector2(Time.deltaTime)));
this.entity.transform.position = this.entity.transform.position.add(Vector2.multiplyScaler(this.velocity, Time.deltaTime));
let collisionResult = new CollisionResult();
// 捞取我们在新的位置上可能会碰撞到的任何东西
@@ -154,16 +154,16 @@ module es {
if (this._collider.collidesWithNonMotion(neighbor, collisionResult)) {
// 如果附近有一个ArcadeRigidbody我们就会处理完整的碰撞响应。如果没有我们会根据附近是不可移动的来计算事情
let neighborRigidbody = neighbor.entity.getComponent<ArcadeRigidbody>(ArcadeRigidbody);
let neighborRigidbody = neighbor.entity.getComponent(ArcadeRigidbody);
if (neighborRigidbody != null) {
this.processOverlap(neighborRigidbody, collisionResult.minimumTranslationVector);
this.processCollision(neighborRigidbody, collisionResult.minimumTranslationVector);
} else {
// 没有ArcadeRigidbody所以我们假设它是不动的只移动我们自己的
this.entity.transform.position = Vector2.subtract(this.entity.transform.position, collisionResult.minimumTranslationVector);
this.entity.transform.position = this.entity.transform.position.subtract(collisionResult.minimumTranslationVector);
let relativeVelocity = this.velocity.clone();
this.calculateResponseVelocity(relativeVelocity, collisionResult.minimumTranslationVector, relativeVelocity);
this.velocity = Vector2.add(this.velocity, relativeVelocity);
this.velocity = this.velocity.add(relativeVelocity);
}
}
}
@@ -176,12 +176,12 @@ module es {
*/
public processOverlap(other: ArcadeRigidbody, minimumTranslationVector: Vector2) {
if (this.isImmovable) {
other.entity.transform.position = Vector2.add(other.entity.transform.position, minimumTranslationVector);
other.entity.transform.position = other.entity.transform.position.add(minimumTranslationVector);
} else if (other.isImmovable) {
this.entity.transform.position = Vector2.subtract(this.entity.transform.position, minimumTranslationVector);
this.entity.transform.position = this.entity.transform.position.subtract(minimumTranslationVector);
} else {
this.entity.transform.position = Vector2.subtract(this.entity.transform.position, Vector2.multiply(minimumTranslationVector, Vector2Ext.halfVector()));
other.entity.transform.position = Vector2.add(other.entity.transform.position, Vector2.multiply(minimumTranslationVector, Vector2Ext.halfVector()));
this.entity.transform.position = this.entity.transform.position.subtract(Vector2.multiplyScaler(minimumTranslationVector, 0.5));
other.entity.transform.position = other.entity.transform.position.add(Vector2.multiplyScaler(minimumTranslationVector, 0.5));
}
}
@@ -203,8 +203,8 @@ module es {
let ourResponseFraction = this._inverseMass / totalinverseMass;
let otherResponseFraction = other._inverseMass / totalinverseMass;
this.velocity = Vector2.add(this.velocity, new Vector2(relativeVelocity.x * ourResponseFraction, relativeVelocity.y * ourResponseFraction));
other.velocity = Vector2.subtract(other.velocity, new Vector2(relativeVelocity.x * otherResponseFraction, relativeVelocity.y * otherResponseFraction));
this.velocity = this.velocity.add(Vector2.multiplyScaler(relativeVelocity, ourResponseFraction));
other.velocity = other.velocity.subtract(Vector2.multiplyScaler(relativeVelocity, otherResponseFraction));
}
/**
@@ -215,14 +215,14 @@ module es {
*/
public calculateResponseVelocity(relativeVelocity: Vector2, minimumTranslationVector: Vector2, responseVelocity: Vector2 = new Vector2()) {
// 首先我们得到反方向的归一化MTV表面法线
let inverseMTV = Vector2.multiply(minimumTranslationVector, new Vector2(-1));
let inverseMTV = Vector2.multiplyScaler(minimumTranslationVector, -1);
let normal = Vector2.normalize(inverseMTV);
// 速度是沿碰撞法线和碰撞平面分解的。
// 弹性将影响沿法线的响应(法线速度分量),摩擦力将影响速度的切向分量(切向速度分量)
let n = Vector2.dot(relativeVelocity, normal);
let normalVelocityComponent = new Vector2(normal.x * n, normal.y * n);
let normalVelocityComponent = Vector2.multiplyScaler(normal, n);
let tangentialVelocityComponent = Vector2.subtract(relativeVelocity, normalVelocityComponent);
if (n > 0)
@@ -234,11 +234,8 @@ module es {
coefficientOfFriction = 1.01;
// 弹性影响速度的法向分量,摩擦力影响速度的切向分量
let t = Vector2.multiply(new Vector2((1 + this._elasticity)), normalVelocityComponent)
.multiply(new Vector2(-1))
.subtract(Vector2.multiply(new Vector2(coefficientOfFriction), tangentialVelocityComponent));
responseVelocity.x = t.x;
relativeVelocity.y = t.y;
responseVelocity = Vector2.multiplyScaler(normalVelocityComponent, -(1 + this._elasticity))
.subtract(Vector2.multiplyScaler(tangentialVelocityComponent, coefficientOfFriction));
}
}
}

View File

@@ -23,7 +23,7 @@ module es {
if (this._lastTime == -1)
this._lastTime = currentTime;
let dt = currentTime - this._lastTime;
let dt = (currentTime - this._lastTime) / 1000;
if (dt > this.maxDeltaTime)
dt = this.maxDeltaTime;
this.totalTime += dt;

View File

@@ -25,7 +25,36 @@ module es {
}
/**
* mapps值(在leftMin - leftMax范围内)到rightMin - rightMax范围内的值
* 返回由给定三角形和两个归一化重心(面积)坐标定义的点的一个轴的笛卡尔坐标
* @param value1
* @param value2
* @param value3
* @param amount1
* @param amount2
*/
public static barycentric(value1: number, value2: number, value3: number, amount1: number, amount2: number) {
return value1 + (value2 - value1) * amount1 + (value3 - value1) * amount2;
}
/**
* 使用指定位置执行Catmull-Rom插值
* @param value1
* @param value2
* @param value3
* @param value4
* @param amount
*/
public static catmullRom(value1: number, value2: number, value3: number, value4: number, amount: number) {
// 使用来自http://www.mvps.org/directx/articles/catmull/的公式
let amountSquared = amount * amount;
let amountCubed = amountSquared * amount;
return (0.5 * (2 * value2 + (value3 - value1) * amount +
(2 * value1 - 5 * value2 + 4 * value3 - value4) * amountSquared +
(3 * value2 - value1 - 3 * value3 + value4) * amountCubed));
}
/**
* 将值在leftMin-leftMax范围内映射到一个在rightMin-rightMax范围内的值
* @param value
* @param leftMin
* @param leftMax
@@ -36,6 +65,66 @@ module es {
return rightMin + (value - leftMin) * (rightMax - rightMin) / (leftMax - leftMin);
}
/**
* 将值从任意范围映射到0到1范围
* @param value
* @param min
* @param max
* @returns
*/
public static map01(value: number, min: number, max: number) {
return (value - min) * 1 / (max - min);
}
/**
* 将值从某个任意范围映射到1到0范围
* 这相当于map01的取反
* @param value
* @param min
* @param max
* @returns
*/
public static map10(value: number, min: number, max: number) {
return 1 - this.map01(value, min, max);
}
/**
* 使用三次方程在两个值之间进行插值
* @param value1
* @param value2
* @param amount
*/
public static smoothStep(value1: number, value2: number, amount: number) {
let result = this.clamp(amount, 0, 1);
result = MathHelper.hermite(value1, 0, value2, 0, result);
return result;
}
/**
* 将给定角度减小到π到-π之间的值
* @param angle
*/
public static wrapAngle(angle: number) {
if ((angle > -Math.PI) && (angle <= Math.PI))
return angle;
angle %= Math.PI * 2;
if (angle <= -Math.PI)
return angle + 2 * Math.PI;
if (angle > Math.PI)
return angle - 2 * Math.PI;
return angle;
}
/**
* 确定值是否以2为底
* @param value
* @returns
*/
public static isPowerOfTwo(value: number) {
return (value > 0) && ((value % (value - 1)) == 0);
}
public static lerp(from: number, to: number, t: number) {
return from + (to - from) * this.clamp01(t);
}
@@ -99,18 +188,26 @@ module es {
if (from < to) {
if (t < from)
return 0;
else if(t > to)
else if (t > to)
return 1;
} else {
if (t < to)
return 1;
else if(t > from)
else if (t > from)
return 0;
}
return (t - from) / (to - from);
}
/**
* 在两个值之间线性插值
* 此方法是MathHelper.Lerp的效率较低更精确的版本。
*/
public static lerpPrecise(value1: number, value2: number, amount: number) {
return ((1 - amount) * value1) + (value2 * amount);
}
public static clamp(value: number, min: number, max: number) {
if (value < min)
return min;
@@ -145,6 +242,27 @@ module es {
return value % 2 == 0;
}
/**
* 如果值是奇数则返回true
* @param value
* @returns
*/
public static isOdd(value: number) {
return value % 2 != 0;
}
/**
* 将值四舍五入并返回它和四舍五入后的数值
* @param value
* @param roundedAmount
* @returns
*/
public static roundWithRoundedAmount(value: number, roundedAmount: Ref<number>) {
let rounded = Math.round(value);
roundedAmount.value = value - (rounded * Math.round(value / rounded));
return rounded;
}
/**
* 数值限定在0-1之间
* @param value
@@ -180,6 +298,41 @@ module es {
return t;
}
/**
* 递减t并确保其始终大于或等于0且小于长度
* @param t
* @param length
* @returns
*/
public static decrementWithWrap(t: number, length: number) {
t--;
if (t < 0)
return length - 1;
return t;
}
/**
* 返回sqrtx * x + y * y
* @param x
* @param y
* @returns
*/
public static hypotenuse(x: number, y: number) {
return Math.sqrt(x * x + y * y);
}
public static closestPowerOfTwoGreaterThan(x: number) {
x--;
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
return (x + 1);
}
/**
* 以roundToNearest为步长将值舍入到最接近的数字。例如在125中找到127到最近的5个结果
* @param value
@@ -269,6 +422,17 @@ module es {
return num;
}
/**
* 检查值是否介于最小值/最大值(包括最小值/最大值)之间
* @param value
* @param min
* @param max
* @returns
*/
public static between(value: number, min: number, max: number) {
return value >= min && value <= max;
}
/**
* 计算以弧度为单位的两个给定角度之间的最短差
* @param current
@@ -375,16 +539,56 @@ module es {
* @param oscillationInterval
* @returns
*/
public static lissajouDamped(xFrequency: number = 2, yFrequency: number = 3, xMagnitude: number = 1,
public static lissajouDamped(xFrequency: number = 2, yFrequency: number = 3, xMagnitude: number = 1,
yMagnitude: number = 1, phase: number = 0.5, damping: number = 0,
oscillationInterval: number = 5) {
let wrappedTime = this.pingPong(Time.totalTime, oscillationInterval);
let damped = Math.pow(Math.E, -damping * wrappedTime);
let wrappedTime = this.pingPong(Time.totalTime, oscillationInterval);
let damped = Math.pow(Math.E, -damping * wrappedTime);
let x = damped * Math.sin(Time.totalTime * xFrequency + phase) * xMagnitude;
let y = damped * Math.cos(Time.totalTime * yFrequency) * yMagnitude;
let x = damped * Math.sin(Time.totalTime * xFrequency + phase) * xMagnitude;
let y = damped * Math.cos(Time.totalTime * yFrequency) * yMagnitude;
return new Vector2(x, y);
return new Vector2(x, y);
}
/**
* 执行Hermite样条插值
* @param value1
* @param tangent1
* @param value2
* @param tangent2
* @param amount
* @returns
*/
public static hermite(value1: number, tangent1: number, value2: number, tangent2: number, amount: number) {
let v1 = value1, v2 = value2, t1 = tangent1, t2 = tangent2, s = amount, result;
let sCubed = s * s * s;
let sSquared = s * s;
if (amount == 0)
result = value1;
else if (amount == 1)
result = value2;
else
result = (2 * v1 - 2 * v2 + t2 + t1) * sCubed +
(3 * v2 - 3 * v1 - 2 * t1 - t2) * sSquared +
t1 * s +
v1;
return result;
}
/**
* 此函数用于确保数不是NaN或无穷大
* @param x
* @returns
*/
public static isValid(x: number) {
if (Number.isNaN(x)) {
return false;
}
return !Number.isFinite(x);
}
}
}

View File

@@ -66,6 +66,19 @@ module es {
return result;
}
/**
*
* @param value1
* @param value2
* @returns
*/
public static multiplyScaler(value1: Vector2, value2: number) {
let result = new Vector2(0, 0);
result.x = value1.x * value2;
result.y = value1.x * value2;
return result;
}
/**
*
* @param value1
@@ -132,6 +145,18 @@ module es {
return new Vector2(MathHelper.lerp(value1.x, value2.x, amount), MathHelper.lerp(value1.y, value2.y, amount));
}
/**
* 创建一个新的Vector2其中包含指定矢量的线性插值
* @param value1
* @param value2
* @param amount
* @returns
*/
public static lerpPrecise(value1: Vector2, value2: Vector2, amount: number) {
return new Vector2(MathHelper.lerpPrecise(value1.x, value2.x, amount),
MathHelper.lerpPrecise(value1.y, value2.y, amount));
}
/**
* 创建一个新的Vector2该Vector2包含了通过指定的Matrix进行的二维向量变换。
* @param position
@@ -142,6 +167,16 @@ module es {
(position.x * matrix.m12) + (position.y * matrix.m22) + matrix.m32);
}
/**
* 创建一个新的Vector2其中包含由指定的Matrix转换的指定法线
* @param normal
* @param matrix
*/
public static transformNormal(normal: Vector2, matrix: Matrix) {
return new Vector2((normal.x * matrix.m11) + (normal.y * matrix.m21),
(normal.x * matrix.m12) + (normal.y * matrix.m22));
}
/**
* 返回两个向量之间的距离
* @param value1
@@ -176,6 +211,32 @@ module es {
return value;
}
/**
* 创建一个新的Vector2其中包含给定矢量和法线的反射矢量
* @param vector
* @param normal
* @returns
*/
public static reflect(vector: Vector2, normal: Vector2) {
let result: Vector2 = new Vector2();
let val = 2 * ((vector.x * normal.x) + (vector.y * normal.y));
result.x = vector.x - (normal.x * val);
result.y = vector.y - (normal.y * val);
return result;
}
/**
* 创建一个新的Vector2其中包含指定矢量的三次插值
* @param value1
* @param value2
* @param amount
* @returns
*/
public static smoothStep(value1: Vector2, value2: Vector2, amount: number) {
return new Vector2(MathHelper.smoothStep(value1.x, value2.x, amount),
MathHelper.smoothStep(value1.y, value2.y, amount));
}
/**
*
* @param value
@@ -206,6 +267,17 @@ module es {
return this;
}
/**
*
* @param value
* @returns
*/
public multiplyScaler(value: number): Vector2 {
this.x *= value;
this.y *= value;
return this;
}
/**
* 从当前Vector2减去一个Vector2
* @param value 要减去的Vector2
@@ -270,6 +342,46 @@ module es {
return false;
}
public isValid(): boolean {
return MathHelper.isValid(this.x) && MathHelper.isValid(this.y);
}
/**
* 创建一个新的Vector2其中包含来自两个向量的最小值
* @param value1
* @param value2
* @returns
*/
public static min(value1: Vector2, value2: Vector2) {
return new Vector2(value1.x < value2.x ? value1.x : value2.x,
value1.y < value2.y ? value1.y : value2.y);
}
/**
* 创建一个新的Vector2其中包含两个向量的最大值
* @param value1
* @param value2
* @returns
*/
public static max(value1: Vector2, value2: Vector2) {
return new Vector2(value1.x > value2.x ? value1.x : value2.x,
value1.y > value2.y ? value1.y : value2.y);
}
/**
* 创建一个新的Vector2其中包含Hermite样条插值
* @param value1
* @param tangent1
* @param value2
* @param tangent2
* @param amount
* @returns
*/
public static hermite(value1: Vector2, tangent1: Vector2, value2: Vector2, tangent2: Vector2, amount: number){
return new Vector2(MathHelper.hermite(value1.x, tangent1.x, value2.x, tangent2.x, amount),
MathHelper.hermite(value1.y, tangent1.y, value2.y, tangent2.y, amount));
}
public clone(): Vector2 {
return new Vector2(this.x, this.y);
}

View File

@@ -104,7 +104,7 @@ module es {
let maxX = Number.NEGATIVE_INFINITY;
let maxY = Number.NEGATIVE_INFINITY;
for (let i = 0; i < points.length; i ++) {
for (let i = 0; i < points.length; i++) {
let pt = points[i];
if (pt.x < minX)
@@ -136,7 +136,7 @@ module es {
* @param deltaX
* @param deltaY
*/
public static getSweptBroadphaseBounds(rect: Rectangle, deltaX: number, deltaY: number){
public static getSweptBroadphaseBounds(rect: Rectangle, deltaX: number, deltaY: number) {
let broadphasebox = Rectangle.empty;
broadphasebox.x = deltaX > 0 ? rect.x : rect.x + deltaX;
@@ -216,5 +216,134 @@ module es {
return new Vector2(depthX, depthY);
}
public static getClosestPointOnBoundsToOrigin(rect: Rectangle) {
let max = this.getMax(rect);
let minDist = Math.abs(rect.location.x);
let boundsPoint = new Vector2(rect.location.x, 0);
if (Math.abs(max.x) < minDist) {
minDist = Math.abs(max.x);
boundsPoint.x = max.x;
boundsPoint.y = 0;
}
if (Math.abs(max.y) < minDist) {
minDist = Math.abs(max.y);
boundsPoint.x = 0;
boundsPoint.y = max.y;
}
if (Math.abs(rect.location.y) < minDist) {
minDist = Math.abs(rect.location.y);
boundsPoint.x = 0;
boundsPoint.y = rect.location.y;
}
return boundsPoint;
}
/**
* 将Rectangle中或上的最接近点返回给定点
* @param rect
* @param point
*/
public static getClosestPointOnRectangleToPoint(rect: Rectangle, point: Vector2) {
// 对于每个轴,如果该点在盒子外面,则将在盒子上,否则不理会它
let res = new Vector2();
res.x = MathHelper.clamp(point.x, rect.left, rect.right)
res.y = MathHelper.clamp(point.y, rect.top, rect.bottom);
return res;
}
/**
* 获取矩形边界上与给定点最接近的点
* @param rect
* @param point
*/
public static getClosestPointOnRectangleBorderToPoint(rect: Rectangle, point: Vector2) {
// 对于每个轴,如果该点在盒子外面,则将在盒子上,否则不理会它
let res = new Vector2();
res.x = MathHelper.clamp(point.x, rect.left, rect.right)
res.y = MathHelper.clamp(point.y, rect.top, rect.bottom);
// 如果点在矩形内我们需要将res推到边框因为它将在矩形内
if (rect.contains(res.x, res.y)) {
let dl = rect.x - rect.left;
let dr = rect.right - res.x;
let dt = res.y - rect.top;
let db = rect.bottom - res.y;
let min = Math.min(dl, dr, dt, db);
if (min == dt)
res.y = rect.top;
else if (min == db)
res.y = rect.bottom;
else if (min == dl)
res.x == rect.left;
else
res.x = rect.right;
}
return res;
}
public static getMax(rect: Rectangle) {
return new Vector2(rect.right, rect.bottom);
}
/**
* 以Vector2的形式获取矩形的中心点
* @param rect
* @returns
*/
public static getCenter(rect: Rectangle) {
return new Vector2(rect.x + rect.width / 2, rect.y + rect.height / 2);
}
/**
* 给定多边形的点即可计算边界
* @param points
*/
public static boundsFromPolygonPoints(points: Vector2[]) {
// 我们需要找到最小/最大x / y值
let minX = Number.POSITIVE_INFINITY;
let minY = Number.POSITIVE_INFINITY;
let maxX = Number.NEGATIVE_INFINITY;
let maxY = Number.NEGATIVE_INFINITY;
for (let i = 0; i < points.length; i++) {
let pt = points[i];
if (pt.x < minX)
minX = pt.x;
if (pt.x > maxX)
maxX = pt.x
if (pt.y < minY)
minY = pt.y;
if (pt.y > maxY)
maxY = pt.y;
}
return this.fromMinMaxVector(new Vector2(minX, minY), new Vector2(maxX, maxY));
}
/**
* 缩放矩形
* @param rect
* @param scale
*/
public static scale(rect: Rectangle, scale: Vector2) {
rect.x = rect.x * scale.x;
rect.y = rect.y * scale.y;
rect.width = rect.width * scale.x;
rect.height = rect.height * scale.y;
}
public static translate(rect: Rectangle, vec: Vector2) {
rect.location.add(vec);
}
}
}

View File

@@ -51,6 +51,18 @@ module es {
return Math.acos(MathHelper.clamp(Vector2.dot(from, to), -1, 1)) * MathHelper.Rad2Deg;
}
/**
* 返回以自度为中心的左右角度
* @param self
* @param left
* @param right
*/
public static angleBetween(self: Vector2, left: Vector2, right: Vector2) {
let one = Vector2.subtract(left, self);
let two = Vector2.subtract(right, self);
return this.angle(one, two);
}
/**
* 给定两条直线(ab和cd),求交点
* @param a