@ue-too/dynamics 0.5.2 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +9 -10
- package/.rollup.cache/home/runner/work/ue-too/ue-too/packages/dynamics/dist/collision.js +0 -330
- package/.rollup.cache/home/runner/work/ue-too/ue-too/packages/dynamics/dist/collision.js.map +0 -1
- package/.rollup.cache/home/runner/work/ue-too/ue-too/packages/dynamics/dist/constraint.js +0 -166
- package/.rollup.cache/home/runner/work/ue-too/ue-too/packages/dynamics/dist/constraint.js.map +0 -1
- package/.rollup.cache/home/runner/work/ue-too/ue-too/packages/dynamics/dist/index.js +0 -4
- package/.rollup.cache/home/runner/work/ue-too/ue-too/packages/dynamics/dist/index.js.map +0 -1
- package/.rollup.cache/home/runner/work/ue-too/ue-too/packages/dynamics/dist/quadtree.js +0 -124
- package/.rollup.cache/home/runner/work/ue-too/ue-too/packages/dynamics/dist/quadtree.js.map +0 -1
- package/.rollup.cache/home/runner/work/ue-too/ue-too/packages/dynamics/dist/rigidbody.js +0 -476
- package/.rollup.cache/home/runner/work/ue-too/ue-too/packages/dynamics/dist/rigidbody.js.map +0 -1
- package/.rollup.cache/home/runner/work/ue-too/ue-too/packages/dynamics/dist/world.js +0 -90
- package/.rollup.cache/home/runner/work/ue-too/ue-too/packages/dynamics/dist/world.js.map +0 -1
- package/dist/collision.d.ts +0 -36
- package/dist/constraint.d.ts +0 -35
- package/dist/dynamics.tsbuildinfo +0 -1
- package/dist/index.d.ts +0 -3
- package/dist/package.json +0 -22
- package/dist/quadtree.d.ts +0 -26
- package/dist/rigidbody.d.ts +0 -252
- package/dist/world.d.ts +0 -29
- package/jest.config.js +0 -18
- package/project.json +0 -33
- package/rollup.config.js +0 -20
- package/src/collision.ts +0 -359
- package/src/constraint.ts +0 -245
- package/src/index.ts +0 -3
- package/src/quadtree.ts +0 -145
- package/src/rigidbody.ts +0 -640
- package/src/world.ts +0 -116
- package/test/rigidbody.test.ts +0 -10
- package/tsconfig.json +0 -21
- package/tsconfig.spec.json +0 -12
- /package/{.rollup.cache/home/runner/work/ue-too/ue-too/packages/dynamics/dist/collision.d.ts → collision.d.ts} +0 -0
- /package/{.rollup.cache/home/runner/work/ue-too/ue-too/packages/dynamics/dist/constraint.d.ts → constraint.d.ts} +0 -0
- /package/{.rollup.cache/home/runner/work/ue-too/ue-too/packages/dynamics/dist/dynamics.tsbuildinfo → dynamics.tsbuildinfo} +0 -0
- /package/{.rollup.cache/home/runner/work/ue-too/ue-too/packages/dynamics/dist/index.d.ts → index.d.ts} +0 -0
- /package/{dist/index.js → index.js} +0 -0
- /package/{dist/index.js.map → index.js.map} +0 -0
- /package/{.rollup.cache/home/runner/work/ue-too/ue-too/packages/dynamics/dist/quadtree.d.ts → quadtree.d.ts} +0 -0
- /package/{.rollup.cache/home/runner/work/ue-too/ue-too/packages/dynamics/dist/rigidbody.d.ts → rigidbody.d.ts} +0 -0
- /package/{.rollup.cache/home/runner/work/ue-too/ue-too/packages/dynamics/dist/world.d.ts → world.d.ts} +0 -0
package/project.json
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "dynamics",
|
|
3
|
-
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
4
|
-
"sourceRoot": "packages/dynamics/src",
|
|
5
|
-
"projectType": "library",
|
|
6
|
-
"targets": {
|
|
7
|
-
"build": {
|
|
8
|
-
"executor": "nx:run-commands",
|
|
9
|
-
"options": {
|
|
10
|
-
"command": "pnpm build",
|
|
11
|
-
"cwd": "packages/dynamics"
|
|
12
|
-
}
|
|
13
|
-
},
|
|
14
|
-
"move-package": {
|
|
15
|
-
"executor": "nx:run-commands",
|
|
16
|
-
"options": {
|
|
17
|
-
"command": "node ../../scripts/move-package.mjs",
|
|
18
|
-
"cwd": "packages/dynamics"
|
|
19
|
-
}
|
|
20
|
-
},
|
|
21
|
-
"test": {
|
|
22
|
-
"executor": "nx:run-commands",
|
|
23
|
-
"options": {
|
|
24
|
-
"command": "pnpm test",
|
|
25
|
-
"cwd": "packages/dynamics"
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
},
|
|
29
|
-
"tags": [],
|
|
30
|
-
"implicitDependencies": [
|
|
31
|
-
"math"
|
|
32
|
-
]
|
|
33
|
-
}
|
package/rollup.config.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @type {import('rollup').RollupOptions}
|
|
3
|
-
*/
|
|
4
|
-
import typescript from '@rollup/plugin-typescript';
|
|
5
|
-
|
|
6
|
-
export default {
|
|
7
|
-
input: 'src/index.ts',
|
|
8
|
-
output: {
|
|
9
|
-
file: 'dist/index.js',
|
|
10
|
-
format: 'esm',
|
|
11
|
-
sourcemap: true
|
|
12
|
-
},
|
|
13
|
-
plugins: [
|
|
14
|
-
typescript({
|
|
15
|
-
tsconfig: 'tsconfig.json',
|
|
16
|
-
outputToFilesystem: true,
|
|
17
|
-
})
|
|
18
|
-
],
|
|
19
|
-
external: ['@ue-too/math']
|
|
20
|
-
};
|
package/src/collision.ts
DELETED
|
@@ -1,359 +0,0 @@
|
|
|
1
|
-
import { BaseRigidBody, RigidBody } from "./rigidbody";
|
|
2
|
-
import { PointCal, Point } from "@ue-too/math";
|
|
3
|
-
import { QuadTree } from "./quadtree";
|
|
4
|
-
|
|
5
|
-
export function resolveCollision(bodyA: RigidBody, bodyB: RigidBody, normal: Point): void {
|
|
6
|
-
// console.log("resolve");
|
|
7
|
-
if (bodyA.isStatic() && bodyB.isStatic()) {
|
|
8
|
-
return;
|
|
9
|
-
}
|
|
10
|
-
let restitution = 0.4;
|
|
11
|
-
let inverseMassA = bodyA.isStatic() || bodyA.isMovingStatic() ? 0 : 1 / bodyA.mass;
|
|
12
|
-
let inverseMassB = bodyB.isStatic() || bodyB.isMovingStatic() ? 0 : 1 / bodyB.mass;
|
|
13
|
-
// console.log("inverse mass a", inverseMassA);
|
|
14
|
-
// console.log("inverse mass b", inverseMassB);
|
|
15
|
-
|
|
16
|
-
let relativeVelocity = PointCal.subVector(bodyA.linearVelocity, bodyB.linearVelocity);
|
|
17
|
-
// console.log("relative velocity: ", relativeVelocity);
|
|
18
|
-
// console.log("linear velocity of a", bodyA.getLinearVelocity());
|
|
19
|
-
// console.log("linear veolcity of b", bodyB.getLinearVelocity());
|
|
20
|
-
let J = -(1 + restitution) * PointCal.dotProduct(relativeVelocity, normal);
|
|
21
|
-
J /= inverseMassA + inverseMassB;
|
|
22
|
-
|
|
23
|
-
let deltaVelocityA = PointCal.multiplyVectorByScalar(normal, J * inverseMassA);
|
|
24
|
-
let deltaVelocityB = PointCal.multiplyVectorByScalar(normal, J * inverseMassB);
|
|
25
|
-
// console.log("delta velocity A:", deltaVelocityA);
|
|
26
|
-
// console.log("delta velocity B:", deltaVelocityB);
|
|
27
|
-
|
|
28
|
-
bodyA.linearVelocity = PointCal.addVector(bodyA.linearVelocity, deltaVelocityA);
|
|
29
|
-
bodyB.linearVelocity = PointCal.subVector(bodyB.linearVelocity, deltaVelocityB);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function resolveCollisionWithRotation(bodyA: RigidBody, bodyB: RigidBody, contactManifold: {normal: Point, contactPoints: Point[]}){
|
|
33
|
-
// console.log("resolve");
|
|
34
|
-
if (bodyA.isStatic() && bodyB.isStatic()) {
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
let restitution = 0.4;
|
|
39
|
-
let inverseMassA = bodyA.isStatic() || bodyA.isMovingStatic() ? 0 : 1 / bodyA.mass;
|
|
40
|
-
let inverseMassB = bodyB.isStatic() || bodyB.isMovingStatic() ? 0 : 1 / bodyB.mass;
|
|
41
|
-
|
|
42
|
-
let inverseMMOIA = bodyA.isStatic() || bodyA.isMovingStatic() ? 0 : 1 / bodyA.momentOfInertia;
|
|
43
|
-
let inverseMMOIB = bodyB.isStatic() || bodyB.isMovingStatic() ? 0 : 1 / bodyB.momentOfInertia;
|
|
44
|
-
|
|
45
|
-
const Js: Point[] = [];
|
|
46
|
-
for(let index = 0; index < contactManifold.contactPoints.length; index++){
|
|
47
|
-
const contactPoint = contactManifold.contactPoints[index];
|
|
48
|
-
const rA = PointCal.subVector(contactPoint, bodyA.center);
|
|
49
|
-
const rB = PointCal.subVector(contactPoint, bodyB.center);
|
|
50
|
-
const rAPerpendicular = {x: -rA.y, y: rA.x};
|
|
51
|
-
const rBPerpendicular = {x: -rB.y, y: rB.x};
|
|
52
|
-
|
|
53
|
-
const angularVelocityA = PointCal.multiplyVectorByScalar(rAPerpendicular, bodyA.angularVelocity);
|
|
54
|
-
const angularVelocityB = PointCal.multiplyVectorByScalar(rBPerpendicular, bodyB.angularVelocity);
|
|
55
|
-
|
|
56
|
-
// console.log("inverse mass a", inverseMassA);
|
|
57
|
-
// console.log("inverse mass b", inverseMassB);
|
|
58
|
-
|
|
59
|
-
let relativeVelocity = PointCal.subVector(PointCal.addVector(bodyA.linearVelocity, angularVelocityA), PointCal.addVector(bodyB.linearVelocity, angularVelocityB));
|
|
60
|
-
// console.log("relative velocity: ", relativeVelocity);
|
|
61
|
-
// console.log("linear velocity of a", bodyA.getLinearVelocity());
|
|
62
|
-
// console.log("linear veolcity of b", bodyB.getLinearVelocity());
|
|
63
|
-
let relativeVelocityNormal = PointCal.dotProduct(relativeVelocity, contactManifold.normal);
|
|
64
|
-
const rAPerpendicularNormal = PointCal.dotProduct(rAPerpendicular, contactManifold.normal);
|
|
65
|
-
const rBPerpendicularNormal = PointCal.dotProduct(rBPerpendicular, contactManifold.normal);
|
|
66
|
-
|
|
67
|
-
const denominator = inverseMassA + inverseMassB + rAPerpendicularNormal * rAPerpendicularNormal * inverseMMOIA + rBPerpendicularNormal * rBPerpendicularNormal * inverseMMOIB;
|
|
68
|
-
let J = -(1 + restitution) * relativeVelocityNormal;
|
|
69
|
-
J /= denominator;
|
|
70
|
-
|
|
71
|
-
J /= contactManifold.contactPoints.length;
|
|
72
|
-
|
|
73
|
-
Js.push(PointCal.multiplyVectorByScalar(contactManifold.normal, J));
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
Js.forEach((impulse, index) => {
|
|
77
|
-
let deltaVelocityA = PointCal.multiplyVectorByScalar(impulse, inverseMassA);
|
|
78
|
-
let deltaVelocityB = PointCal.multiplyVectorByScalar(impulse, inverseMassB);
|
|
79
|
-
|
|
80
|
-
bodyA.linearVelocity = PointCal.addVector(bodyA.linearVelocity, deltaVelocityA);
|
|
81
|
-
let resA = PointCal.crossProduct(PointCal.subVector(contactManifold.contactPoints[index], bodyA.center), impulse).z;
|
|
82
|
-
resA = resA == undefined ? 0 : resA;
|
|
83
|
-
let resB = PointCal.crossProduct(PointCal.subVector(contactManifold.contactPoints[index], bodyB.center), impulse).z;
|
|
84
|
-
resB = resB == undefined ? 0 : resB;
|
|
85
|
-
bodyA.angularVelocity += resA * inverseMMOIA;
|
|
86
|
-
bodyB.angularVelocity -= resB * inverseMMOIB;
|
|
87
|
-
bodyB.linearVelocity = PointCal.subVector(bodyB.linearVelocity, deltaVelocityB);
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export function aabbIntersects(aabbA: {min: Point, max: Point}, aabbB: {min: Point, max: Point}): boolean{
|
|
92
|
-
if ((aabbA.min.x <= aabbB.max.x && aabbB.min.x <= aabbA.max.x) && (aabbA.min.y <= aabbB.max.y && aabbB.min.y <= aabbA.max.y)) {
|
|
93
|
-
return true;
|
|
94
|
-
}
|
|
95
|
-
return false;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export function intersects(bodyA: RigidBody, bodyB: RigidBody): {collision: boolean, depth?: number, normal?: Point}{
|
|
99
|
-
let axis: Point[] = [];
|
|
100
|
-
let bodyAAxes = bodyA.getCollisionAxes(bodyB);
|
|
101
|
-
let bodyBAxes = bodyB.getCollisionAxes(bodyA);
|
|
102
|
-
|
|
103
|
-
axis.push(...bodyAAxes);
|
|
104
|
-
axis.push(...bodyBAxes);
|
|
105
|
-
|
|
106
|
-
let collision = true;
|
|
107
|
-
let minDepth = Number.MAX_VALUE;
|
|
108
|
-
let minAxis = axis[0];
|
|
109
|
-
|
|
110
|
-
axis.forEach(projAxis => {
|
|
111
|
-
let bodyAInterval = bodyA.getMinMaxProjection(projAxis);
|
|
112
|
-
let bodyBInterval = bodyB.getMinMaxProjection(projAxis);
|
|
113
|
-
|
|
114
|
-
if (bodyAInterval.min >= bodyBInterval.max || bodyBInterval.min >= bodyAInterval.max) {
|
|
115
|
-
collision = false;
|
|
116
|
-
}else {
|
|
117
|
-
let depth = Math.abs(Math.min(bodyAInterval.max, bodyBInterval.max) - Math.max(bodyBInterval.min, bodyAInterval.min));
|
|
118
|
-
if (depth < minDepth) {
|
|
119
|
-
minDepth = depth;
|
|
120
|
-
minAxis = projAxis;
|
|
121
|
-
if (bodyAInterval.max < bodyBInterval.max) {
|
|
122
|
-
minAxis = PointCal.multiplyVectorByScalar(minAxis, -1);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
if (collision){
|
|
129
|
-
return {collision: collision, depth: minDepth, normal: minAxis};
|
|
130
|
-
}else {
|
|
131
|
-
return {collision: false, depth: undefined, normal: undefined};
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
export function narrowPhaseWithRigidBody(bodies: RigidBody[], combinationsToCheck: {bodyA: RigidBody, bodyB: RigidBody}[], resolveCollisionFlag: boolean): Point[]{
|
|
136
|
-
if (!resolveCollisionFlag) {
|
|
137
|
-
return [];
|
|
138
|
-
}
|
|
139
|
-
const contactPoints: Point[] = [];
|
|
140
|
-
combinationsToCheck.forEach(combination => {
|
|
141
|
-
let bodyA = combination.bodyA;
|
|
142
|
-
let bodyB = combination.bodyB;
|
|
143
|
-
if (bodyA == bodyB) {
|
|
144
|
-
// console.log("same body");
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
let bodyAZ = bodyA.center.z == undefined ? 0 : bodyA.center.z;
|
|
148
|
-
let bodyBZ = bodyB.center.z == undefined ? 0 : bodyB.center.z;
|
|
149
|
-
if(Math.abs(bodyAZ - bodyBZ) > 0.5){
|
|
150
|
-
// console.log("z-index difference is too large");
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
let {collision, depth, normal: normalAxis} = intersects(bodyA, bodyB);
|
|
154
|
-
if (collision && normalAxis !== undefined && depth !== undefined) {
|
|
155
|
-
// the normal axis points in the direction that push bodyA away from bodyB
|
|
156
|
-
|
|
157
|
-
let moveDisplacement = PointCal.multiplyVectorByScalar(normalAxis, depth / 2);
|
|
158
|
-
let revMoveDisplacement = PointCal.multiplyVectorByScalar(normalAxis, -depth / 2);
|
|
159
|
-
|
|
160
|
-
if (!bodyA.isStatic()) {
|
|
161
|
-
bodyA.move(moveDisplacement);
|
|
162
|
-
}
|
|
163
|
-
if (!bodyB.isStatic()) {
|
|
164
|
-
bodyB.move(revMoveDisplacement);
|
|
165
|
-
}
|
|
166
|
-
if (bodyA.isStatic()) {
|
|
167
|
-
// bodyA.move(revMoveDisplacement);
|
|
168
|
-
bodyB.move(revMoveDisplacement);
|
|
169
|
-
}
|
|
170
|
-
if (bodyB.isStatic()) {
|
|
171
|
-
bodyA.move(moveDisplacement);
|
|
172
|
-
// bodyB.move(moveDisplacement);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// finding the collision contact point(s)
|
|
176
|
-
const bodyASigNormal = bodyA.getNormalOfSignificantFace(PointCal.multiplyVectorByScalar(normalAxis, -1));
|
|
177
|
-
const bodyBSigNormal = bodyB.getNormalOfSignificantFace(normalAxis);
|
|
178
|
-
const bodyASigVertices = bodyA.getSignificantVertices(PointCal.multiplyVectorByScalar(normalAxis, -1));
|
|
179
|
-
const bodyBSigVertices = bodyB.getSignificantVertices(normalAxis);
|
|
180
|
-
const bodyAParallelIndicator = Math.abs(PointCal.dotProduct(bodyASigNormal, PointCal.multiplyVectorByScalar(normalAxis, -1)));
|
|
181
|
-
const bodyBParallelIndicator = Math.abs(PointCal.dotProduct(bodyBSigNormal, normalAxis));
|
|
182
|
-
|
|
183
|
-
if (bodyBSigVertices.length == 1 || bodyASigVertices.length == 1){
|
|
184
|
-
// one of the body is a circle
|
|
185
|
-
// console.log("involving a circle");
|
|
186
|
-
if (bodyBSigVertices.length == 1){
|
|
187
|
-
// bodyB is a circle
|
|
188
|
-
// contact point is on the perimeter of the circle and the direction is the collision normal
|
|
189
|
-
contactPoints.push(bodyBSigVertices[0]);
|
|
190
|
-
} else {
|
|
191
|
-
// bodyA is a circle
|
|
192
|
-
// contact point is on the perimeter of the circle and the direction is the collision normal
|
|
193
|
-
contactPoints.push(bodyASigVertices[0]);
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
else if (bodyAParallelIndicator > bodyBParallelIndicator) {
|
|
197
|
-
// bodyA has the normal that is the most parallel to the collision normal
|
|
198
|
-
const adjacentFaces = bodyA.getAdjacentFaces(PointCal.multiplyVectorByScalar(normalAxis, -1));
|
|
199
|
-
let faceToClip = [...bodyBSigVertices];
|
|
200
|
-
for(let index = 0; index < adjacentFaces.length - 1; index++){
|
|
201
|
-
let startPoint = adjacentFaces[index].startPoint.coord;
|
|
202
|
-
let endPoint = adjacentFaces[index].endPoint.coord;
|
|
203
|
-
let direction = PointCal.subVector(endPoint, startPoint);
|
|
204
|
-
let sigStart = PointCal.subVector(faceToClip[0], startPoint);
|
|
205
|
-
let sigEnd = PointCal.subVector(faceToClip[1], startPoint);
|
|
206
|
-
let startInside = PointCal.angleFromA2B(direction, sigStart) >= 0;
|
|
207
|
-
let endInside = PointCal.angleFromA2B(direction, sigEnd) >= 0;
|
|
208
|
-
if ((startInside ? 1 : 0) ^ (endInside ? 1 : 0)){
|
|
209
|
-
// one of the point is outside the face
|
|
210
|
-
let intersectionPoint = PointCal.getLineIntersection(startPoint, endPoint, faceToClip[0], faceToClip[1]);
|
|
211
|
-
if (intersectionPoint.intersects && intersectionPoint.intersection !== undefined){
|
|
212
|
-
if(startInside){
|
|
213
|
-
faceToClip[1] = intersectionPoint.intersection;
|
|
214
|
-
} else {
|
|
215
|
-
faceToClip[0] = intersectionPoint.intersection;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
const referenceFace = adjacentFaces[adjacentFaces.length - 1];
|
|
221
|
-
let startPoint = referenceFace.startPoint.coord;
|
|
222
|
-
let endPoint = referenceFace.endPoint.coord;
|
|
223
|
-
let direction = PointCal.subVector(endPoint, startPoint);
|
|
224
|
-
let sigStart = PointCal.subVector(faceToClip[0], startPoint);
|
|
225
|
-
let sigEnd = PointCal.subVector(faceToClip[1], startPoint);
|
|
226
|
-
let startInside = PointCal.angleFromA2B(direction, sigStart) >= 0;
|
|
227
|
-
let endInside = PointCal.angleFromA2B(direction, sigEnd) >= 0;
|
|
228
|
-
if (startInside){
|
|
229
|
-
contactPoints.push(faceToClip[0]);
|
|
230
|
-
}
|
|
231
|
-
if (endInside){
|
|
232
|
-
contactPoints.push(faceToClip[1]);
|
|
233
|
-
}
|
|
234
|
-
} else {
|
|
235
|
-
// bodyB has the normal that is the most parallel to the collision normal
|
|
236
|
-
const adjacentFaces = bodyB.getAdjacentFaces(normalAxis);
|
|
237
|
-
let faceToClip = [...bodyASigVertices];
|
|
238
|
-
if(faceToClip.length == 0){
|
|
239
|
-
console.log("warning");
|
|
240
|
-
}
|
|
241
|
-
let count = 0;
|
|
242
|
-
for(let index = 0; index < adjacentFaces.length - 1; index++){
|
|
243
|
-
let startPoint = adjacentFaces[index].startPoint.coord;
|
|
244
|
-
let endPoint = adjacentFaces[index].endPoint.coord;
|
|
245
|
-
let direction = PointCal.subVector(endPoint, startPoint);
|
|
246
|
-
let sigStart = PointCal.subVector(faceToClip[0], startPoint);
|
|
247
|
-
let sigEnd = PointCal.subVector(faceToClip[1], startPoint);
|
|
248
|
-
let startInside = PointCal.angleFromA2B(direction, sigStart) >= 0;
|
|
249
|
-
let endInside = PointCal.angleFromA2B(direction, sigEnd) >= 0;
|
|
250
|
-
if ((startInside ? 1 : 0) ^ (endInside ? 1 : 0)){
|
|
251
|
-
count += 1;
|
|
252
|
-
// one of the point is outside the face
|
|
253
|
-
let intersectionPoint = PointCal.getLineIntersection(startPoint, endPoint, faceToClip[0], faceToClip[1]);
|
|
254
|
-
if (intersectionPoint.intersects && intersectionPoint.intersection !== undefined){
|
|
255
|
-
if(startInside){
|
|
256
|
-
faceToClip[1] = intersectionPoint.intersection;
|
|
257
|
-
} else {
|
|
258
|
-
faceToClip[0] = intersectionPoint.intersection;
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
const referenceFace = adjacentFaces[adjacentFaces.length - 1];
|
|
264
|
-
let startPoint = referenceFace.startPoint.coord;
|
|
265
|
-
let endPoint = referenceFace.endPoint.coord;
|
|
266
|
-
let direction = PointCal.subVector(endPoint, startPoint);
|
|
267
|
-
let sigStart = PointCal.subVector(faceToClip[0], startPoint);
|
|
268
|
-
let sigEnd = PointCal.subVector(faceToClip[1], startPoint);
|
|
269
|
-
let startInside = PointCal.angleFromA2B(direction, sigStart) >= 0;
|
|
270
|
-
let endInside = PointCal.angleFromA2B(direction, sigEnd) >= 0;
|
|
271
|
-
if (startInside){
|
|
272
|
-
contactPoints.push(faceToClip[0]);
|
|
273
|
-
}
|
|
274
|
-
if (endInside){
|
|
275
|
-
contactPoints.push(faceToClip[1]);
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
if (resolveCollisionFlag) {
|
|
279
|
-
resolveCollisionWithRotation(bodyA, bodyB, {normal: normalAxis, contactPoints: contactPoints});
|
|
280
|
-
// resolveCollision(bodyA, bodyB, normalAxis);
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
});
|
|
284
|
-
return contactPoints;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
export function narrowPhase(bodies: BaseRigidBody[], combinationsToCheck: {bodyAIndex: number, bodyBIndex: number}[], resolveCollisionFlag: boolean): void {
|
|
288
|
-
if (!resolveCollisionFlag) {
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
|
-
combinationsToCheck.forEach(combination => {
|
|
292
|
-
let bodyA = bodies[combination.bodyAIndex];
|
|
293
|
-
let bodyB = bodies[combination.bodyBIndex];
|
|
294
|
-
let {collision, depth, normal: normalAxis} = intersects(bodyA, bodyB);
|
|
295
|
-
if (collision && normalAxis !== undefined && depth !== undefined) {
|
|
296
|
-
// console.log("collision");
|
|
297
|
-
let moveDisplacement = PointCal.multiplyVectorByScalar(normalAxis, depth / 2);
|
|
298
|
-
let revMoveDisplacement = PointCal.multiplyVectorByScalar(normalAxis, -depth / 2);
|
|
299
|
-
|
|
300
|
-
if (!bodyA.isStatic()) {
|
|
301
|
-
bodyA.move(moveDisplacement);
|
|
302
|
-
}
|
|
303
|
-
if (!bodyB.isStatic()) {
|
|
304
|
-
bodyB.move(revMoveDisplacement);
|
|
305
|
-
}
|
|
306
|
-
if (bodyA.isStatic()) {
|
|
307
|
-
// bodyA.move(revMoveDisplacement);
|
|
308
|
-
bodyB.move(revMoveDisplacement);
|
|
309
|
-
}
|
|
310
|
-
if (bodyB.isStatic()) {
|
|
311
|
-
bodyA.move(moveDisplacement);
|
|
312
|
-
// bodyB.move(moveDisplacement);
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
if (resolveCollisionFlag) {
|
|
316
|
-
resolveCollision(bodyA, bodyB, normalAxis);
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
}
|
|
320
|
-
})
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
export function broadPhaseWithRigidBodyReturned(quadTree: QuadTree, bodies: RigidBody[]): {bodyA: RigidBody, bodyB: RigidBody}[]{
|
|
324
|
-
let possibleCombi: {bodyA: RigidBody, bodyB: RigidBody}[] = [];
|
|
325
|
-
for(let index = 0; index <= bodies.length - 1; index++){
|
|
326
|
-
let objsToCheck = quadTree.retrieve(bodies[index]);
|
|
327
|
-
for(let jindex = 0; jindex <= objsToCheck.length - 1; jindex++){
|
|
328
|
-
let bodyA = bodies[index];
|
|
329
|
-
let bodyB = objsToCheck[jindex];
|
|
330
|
-
if (bodyA.isStatic() && bodyB.isStatic()){
|
|
331
|
-
continue;
|
|
332
|
-
}
|
|
333
|
-
if(!aabbIntersects(bodyA.AABB, bodyB.AABB)){
|
|
334
|
-
continue;
|
|
335
|
-
}
|
|
336
|
-
possibleCombi.push({bodyA: bodyA, bodyB: bodyB});
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
return possibleCombi
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
export function broadPhase(quadTree: QuadTree, bodies: BaseRigidBody[]): {bodyAIndex: number, bodyBIndex: number}[]{
|
|
343
|
-
let possibleCombi: {bodyAIndex: number, bodyBIndex: number}[] = [];
|
|
344
|
-
for(let index = 0; index <= bodies.length - 1; index++){
|
|
345
|
-
let objsToCheck = quadTree.retrieve(bodies[index]);
|
|
346
|
-
for(let jindex = 0; jindex <= objsToCheck.length - 1; jindex++){
|
|
347
|
-
let bodyA = bodies[index];
|
|
348
|
-
let bodyB = objsToCheck[jindex];
|
|
349
|
-
if (bodyA.isStatic() && bodyB.isStatic()){
|
|
350
|
-
continue;
|
|
351
|
-
}
|
|
352
|
-
if(!aabbIntersects(bodyA.AABB, bodyB.AABB)){
|
|
353
|
-
continue;
|
|
354
|
-
}
|
|
355
|
-
possibleCombi.push({bodyAIndex: index, bodyBIndex: jindex});
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
return possibleCombi
|
|
359
|
-
}
|
package/src/constraint.ts
DELETED
|
@@ -1,245 +0,0 @@
|
|
|
1
|
-
import { Point, PointCal } from "@ue-too/math";
|
|
2
|
-
import { RigidBody } from "./rigidbody";
|
|
3
|
-
|
|
4
|
-
export interface Constraint {
|
|
5
|
-
enforce(dt: number): void;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export class FixedPinJoint implements Constraint {
|
|
9
|
-
|
|
10
|
-
private anchorA: Point;
|
|
11
|
-
private worldAnchorA: Point;
|
|
12
|
-
private bodyA: RigidBody;
|
|
13
|
-
|
|
14
|
-
constructor(bodyA: RigidBody, anchorA: Point, worldAnchorA: Point) {
|
|
15
|
-
this.bodyA = bodyA;
|
|
16
|
-
this.anchorA = anchorA;
|
|
17
|
-
this.worldAnchorA = worldAnchorA;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
enforce(dt: number): void {
|
|
21
|
-
this.solveWorldPinJointConstraint(dt);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
solveWorldPinJointConstraint(dt: number) {
|
|
25
|
-
const body = this.bodyA;
|
|
26
|
-
const localAnchor = this.anchorA;
|
|
27
|
-
const worldAnchor = this.worldAnchorA;
|
|
28
|
-
|
|
29
|
-
// Transform local anchor point to world space
|
|
30
|
-
const worldAnchorOnBody = PointCal.addVector(body.center, PointCal.rotatePoint(localAnchor, body.orientationAngle));
|
|
31
|
-
|
|
32
|
-
// Calculate the difference between the anchor points
|
|
33
|
-
const diff = PointCal.subVector(worldAnchorOnBody, worldAnchor);
|
|
34
|
-
|
|
35
|
-
// Calculate the relative velocity of the anchor point
|
|
36
|
-
const r = PointCal.subVector(worldAnchorOnBody, body.center);
|
|
37
|
-
const velocity = PointCal.addVector(
|
|
38
|
-
body.linearVelocity,
|
|
39
|
-
PointCal.crossProduct({x: 0, y: 0, z: body.angularVelocity}, r)
|
|
40
|
-
);
|
|
41
|
-
|
|
42
|
-
// Calculate the mass matrix
|
|
43
|
-
const invMass = body.isStatic() ? 0 : 1 / body.mass;
|
|
44
|
-
const invI = body.isStatic() ? 0 : 1 / body.momentOfInertia;
|
|
45
|
-
|
|
46
|
-
const K = {
|
|
47
|
-
x: invMass + invI * r.y * r.y,
|
|
48
|
-
y: invMass + invI * r.x * r.x,
|
|
49
|
-
xy: -invI * r.x * r.y
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
// Calculate the impulse
|
|
53
|
-
const baumgarte = 1; // Baumgarte stabilization factor
|
|
54
|
-
const impulse = {
|
|
55
|
-
x: -K.x * diff.x - K.xy * diff.y - baumgarte * diff.x / dt - velocity.x,
|
|
56
|
-
y: -K.xy * diff.x - K.y * diff.y - baumgarte * diff.y / dt - velocity.y
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
// Apply the impulse
|
|
60
|
-
if (!body.isStatic()) {
|
|
61
|
-
body.linearVelocity.x += invMass * impulse.x;
|
|
62
|
-
body.linearVelocity.y += invMass * impulse.y;
|
|
63
|
-
body.angularVelocity += invI * (r.x * impulse.y - r.y * impulse.x);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export class PinJoint implements Constraint {
|
|
69
|
-
|
|
70
|
-
private anchorA: Point;
|
|
71
|
-
private anchorB: Point;
|
|
72
|
-
private bodyA: RigidBody;
|
|
73
|
-
private bodyB: RigidBody;
|
|
74
|
-
|
|
75
|
-
constructor(bodyA: RigidBody, bodyB: RigidBody, anchorA: Point, anchorB: Point) {
|
|
76
|
-
this.bodyA = bodyA;
|
|
77
|
-
this.bodyB = bodyB;
|
|
78
|
-
this.anchorA = anchorA;
|
|
79
|
-
this.anchorB = anchorB;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
enforce(dt: number): void {
|
|
83
|
-
this.solvePinJointConstraint(dt);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
solvePinJointConstraint(dt: number) {
|
|
87
|
-
const bodyA = this.bodyA;
|
|
88
|
-
const bodyB = this.bodyB;
|
|
89
|
-
const anchorA = this.anchorA;
|
|
90
|
-
const anchorB = this.anchorB;
|
|
91
|
-
|
|
92
|
-
// Transform local anchor points to world space
|
|
93
|
-
const worldAnchorA = PointCal.addVector(bodyA.center, PointCal.rotatePoint(anchorA, bodyA.orientationAngle));
|
|
94
|
-
const worldAnchorB = PointCal.addVector(bodyB.center, PointCal.rotatePoint(anchorB, bodyB.orientationAngle));
|
|
95
|
-
|
|
96
|
-
// Calculate the difference between the two anchor points in world space
|
|
97
|
-
const diff = PointCal.subVector(worldAnchorB, worldAnchorA);
|
|
98
|
-
|
|
99
|
-
// Calculate the relative velocity of the anchor points
|
|
100
|
-
const rA = PointCal.subVector(worldAnchorA, bodyA.center);
|
|
101
|
-
const rB = PointCal.subVector(worldAnchorB, bodyB.center);
|
|
102
|
-
const relativeVelocity = PointCal.subVector(
|
|
103
|
-
PointCal.addVector(bodyB.linearVelocity, PointCal.crossProduct({x: 0, y: 0, z: bodyB.angularVelocity}, rB)),
|
|
104
|
-
PointCal.addVector(bodyA.linearVelocity, PointCal.crossProduct({x: 0, y: 0, z: bodyA.angularVelocity}, rA))
|
|
105
|
-
);
|
|
106
|
-
|
|
107
|
-
// Calculate the mass matrix
|
|
108
|
-
const invMassA = bodyA.isStatic() ? 0 : 1 / bodyA.mass;
|
|
109
|
-
const invMassB = bodyB.isStatic() ? 0 : 1 / bodyB.mass;
|
|
110
|
-
const invIA = bodyA.isStatic() ? 0 : 1 / bodyA.momentOfInertia;
|
|
111
|
-
const invIB = bodyB.isStatic() ? 0 : 1 / bodyB.momentOfInertia;
|
|
112
|
-
|
|
113
|
-
const K = {
|
|
114
|
-
x: invMassA + invMassB + invIA * rA.y * rA.y + invIB * rB.y * rB.y,
|
|
115
|
-
y: invMassA + invMassB + invIA * rA.x * rA.x + invIB * rB.x * rB.x,
|
|
116
|
-
xy: -invIA * rA.x * rA.y - invIB * rB.x * rB.y
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
// Calculate the impulse
|
|
120
|
-
const baumgarte = 1; // Baumgarte stabilization factor
|
|
121
|
-
const impulse = {
|
|
122
|
-
x: -K.x * diff.x - K.xy * diff.y - baumgarte * diff.x / dt - relativeVelocity.x,
|
|
123
|
-
y: -K.xy * diff.x - K.y * diff.y - baumgarte * diff.y / dt - relativeVelocity.y
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
// Apply the impulse
|
|
127
|
-
if (!bodyA.isStatic()) {
|
|
128
|
-
bodyA.linearVelocity.x -= invMassA * impulse.x;
|
|
129
|
-
bodyA.linearVelocity.y -= invMassA * impulse.y;
|
|
130
|
-
bodyA.angularVelocity -= invIA * (rA.x * impulse.y - rA.y * impulse.x);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
if (!bodyB.isStatic()) {
|
|
134
|
-
bodyB.linearVelocity.x += invMassB * impulse.x;
|
|
135
|
-
bodyB.linearVelocity.y += invMassB * impulse.y;
|
|
136
|
-
bodyB.angularVelocity += invIB * (rB.x * impulse.y - rB.y * impulse.x);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
export interface PinJointConstraint {
|
|
143
|
-
bodyA: RigidBody;
|
|
144
|
-
bodyB: RigidBody;
|
|
145
|
-
anchorA: Point; // Local anchor point for bodyA
|
|
146
|
-
anchorB: Point; // Local anchor point for bodyB
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
export function solvePinJointConstraint(constraint: PinJointConstraint, dt: number) {
|
|
150
|
-
const { bodyA, bodyB, anchorA, anchorB } = constraint;
|
|
151
|
-
|
|
152
|
-
// Transform local anchor points to world space
|
|
153
|
-
const worldAnchorA = PointCal.addVector(bodyA.center, PointCal.rotatePoint(anchorA, bodyA.orientationAngle));
|
|
154
|
-
const worldAnchorB = PointCal.addVector(bodyB.center, PointCal.rotatePoint(anchorB, bodyB.orientationAngle));
|
|
155
|
-
|
|
156
|
-
// Calculate the difference between the two anchor points in world space
|
|
157
|
-
const diff = PointCal.subVector(worldAnchorB, worldAnchorA);
|
|
158
|
-
|
|
159
|
-
// Calculate the relative velocity of the anchor points
|
|
160
|
-
const rA = PointCal.subVector(worldAnchorA, bodyA.center);
|
|
161
|
-
const rB = PointCal.subVector(worldAnchorB, bodyB.center);
|
|
162
|
-
const relativeVelocity = PointCal.subVector(
|
|
163
|
-
PointCal.addVector(bodyB.linearVelocity, PointCal.crossProduct({x: 0, y: 0, z: bodyB.angularVelocity}, rB)),
|
|
164
|
-
PointCal.addVector(bodyA.linearVelocity, PointCal.crossProduct({x: 0, y: 0, z: bodyA.angularVelocity}, rA))
|
|
165
|
-
);
|
|
166
|
-
|
|
167
|
-
// Calculate the mass matrix
|
|
168
|
-
const invMassA = bodyA.isStatic() ? 0 : 1 / bodyA.mass;
|
|
169
|
-
const invMassB = bodyB.isStatic() ? 0 : 1 / bodyB.mass;
|
|
170
|
-
const invIA = bodyA.isStatic() ? 0 : 1 / bodyA.momentOfInertia;
|
|
171
|
-
const invIB = bodyB.isStatic() ? 0 : 1 / bodyB.momentOfInertia;
|
|
172
|
-
|
|
173
|
-
const K = {
|
|
174
|
-
x: invMassA + invMassB + invIA * rA.y * rA.y + invIB * rB.y * rB.y,
|
|
175
|
-
y: invMassA + invMassB + invIA * rA.x * rA.x + invIB * rB.x * rB.x,
|
|
176
|
-
xy: -invIA * rA.x * rA.y - invIB * rB.x * rB.y
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
// Calculate the impulse
|
|
180
|
-
const baumgarte = 0.5; // Baumgarte stabilization factor
|
|
181
|
-
const impulse = {
|
|
182
|
-
x: -K.x * diff.x - K.xy * diff.y - baumgarte * diff.x / dt - relativeVelocity.x,
|
|
183
|
-
y: -K.xy * diff.x - K.y * diff.y - baumgarte * diff.y / dt - relativeVelocity.y
|
|
184
|
-
};
|
|
185
|
-
|
|
186
|
-
// Apply the impulse
|
|
187
|
-
if (!bodyA.isStatic()) {
|
|
188
|
-
bodyA.linearVelocity.x -= invMassA * impulse.x;
|
|
189
|
-
bodyA.linearVelocity.y -= invMassA * impulse.y;
|
|
190
|
-
bodyA.angularVelocity -= invIA * (rA.x * impulse.y - rA.y * impulse.x);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
if (!bodyB.isStatic()) {
|
|
194
|
-
bodyB.linearVelocity.x += invMassB * impulse.x;
|
|
195
|
-
bodyB.linearVelocity.y += invMassB * impulse.y;
|
|
196
|
-
bodyB.angularVelocity += invIB * (rB.x * impulse.y - rB.y * impulse.x);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
export interface WorldPinJointConstraint {
|
|
201
|
-
body: RigidBody;
|
|
202
|
-
localAnchor: Point; // Anchor point in body's local space
|
|
203
|
-
worldAnchor: Point; // Fixed point in world space
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
export function solveWorldPinJointConstraint(constraint: WorldPinJointConstraint, dt: number) {
|
|
207
|
-
const { body, localAnchor, worldAnchor } = constraint;
|
|
208
|
-
|
|
209
|
-
// Transform local anchor point to world space
|
|
210
|
-
const worldAnchorOnBody = PointCal.addVector(body.center, PointCal.rotatePoint(localAnchor, body.orientationAngle));
|
|
211
|
-
|
|
212
|
-
// Calculate the difference between the anchor points
|
|
213
|
-
const diff = PointCal.subVector(worldAnchorOnBody, worldAnchor);
|
|
214
|
-
|
|
215
|
-
// Calculate the relative velocity of the anchor point
|
|
216
|
-
const r = PointCal.subVector(worldAnchorOnBody, body.center);
|
|
217
|
-
const velocity = PointCal.addVector(
|
|
218
|
-
body.linearVelocity,
|
|
219
|
-
PointCal.crossProduct({x: 0, y: 0, z: body.angularVelocity}, r)
|
|
220
|
-
);
|
|
221
|
-
|
|
222
|
-
// Calculate the mass matrix
|
|
223
|
-
const invMass = body.isStatic() ? 0 : 1 / body.mass;
|
|
224
|
-
const invI = body.isStatic() ? 0 : 1 / body.momentOfInertia;
|
|
225
|
-
|
|
226
|
-
const K = {
|
|
227
|
-
x: invMass + invI * r.y * r.y,
|
|
228
|
-
y: invMass + invI * r.x * r.x,
|
|
229
|
-
xy: -invI * r.x * r.y
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
// Calculate the impulse
|
|
233
|
-
const baumgarte = 0.2; // Baumgarte stabilization factor
|
|
234
|
-
const impulse = {
|
|
235
|
-
x: -K.x * diff.x - K.xy * diff.y - baumgarte * diff.x / dt - velocity.x,
|
|
236
|
-
y: -K.xy * diff.x - K.y * diff.y - baumgarte * diff.y / dt - velocity.y
|
|
237
|
-
};
|
|
238
|
-
|
|
239
|
-
// Apply the impulse
|
|
240
|
-
if (!body.isStatic()) {
|
|
241
|
-
body.linearVelocity.x += invMass * impulse.x;
|
|
242
|
-
body.linearVelocity.y += invMass * impulse.y;
|
|
243
|
-
body.angularVelocity += invI * (r.x * impulse.y - r.y * impulse.x);
|
|
244
|
-
}
|
|
245
|
-
}
|
package/src/index.ts
DELETED