Skip to content

Commit 953412a

Browse files
fix(physx): fix velocity not accounted in collisions
With this fix the objects don't clip anymore. A following fix will address the issue with the clunky position on a collision
1 parent 37e6a5f commit 953412a

3 files changed

Lines changed: 83 additions & 88 deletions

File tree

examples/simplePongGame/index.html

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@
7575
const pingPongBall = new SparkEngine.GameObject();
7676
pingPongBall.transform.size = { width: 10, height: 10 };
7777
pingPongBall.transform.position = new SparkEngine.Vec2(140, 70);
78-
pingPongBall.transform.velocity = new SparkEngine.Vec2(5);
79-
pingPongBall.material.diffuseColor = baseColor;
78+
pingPongBall.transform.velocity = new SparkEngine.Vec2(5.75);
79+
pingPongBall.material.diffuseColor = new SparkEngine.Rgb(255, 0, 0);
8080

8181
const pingPongBB = new SparkEngine.BoundingBoxComponent()
8282
pingPongBB.matchContainerTransform = true;
@@ -105,10 +105,12 @@
105105

106106
const drawFrame = () => {
107107
inputSystem.update();
108-
hierarchySystem.update();
109-
physicsSystem.update();
110108

109+
physicsSystem.update();
111110
physx.simulate();
111+
112+
hierarchySystem.update();
113+
112114
renderSystem.update();
113115
renderer.endFrame(context);
114116
}

src/physx/Physx.ts

Lines changed: 48 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export interface onCollisionCallbackParams {
2323
otherObject: PhysicsObject;
2424
simulationResult: {
2525
velocity: Vec2
26+
position: Vec2
2627
}
2728
// collisionPlane: Vec2;
2829
}
@@ -42,7 +43,7 @@ export interface PhysicalObjectCallbackAggregate {
4243
}
4344

4445
enum CollisionQuadrant {
45-
TopLeft,
46+
TopLeft = 1,
4647
TopRight,
4748
BottomLeft,
4849
BottomRight
@@ -72,21 +73,35 @@ export class Physx {
7273
}
7374

7475
private checkCollision(objectA: PhysicsObject, objectB: PhysicsObject): Vec2 | null {
75-
const [x1, y1, w1, h1] = objectA.aabb;
76-
const [x2, y2, w2, h2] = objectB.aabb;
77-
7876
if (objectA.isContainer) {
7977
return this.checkCollisionContainer(objectA, objectB);
8078
} else if (objectB.isContainer) {
8179
return this.checkCollisionContainer(objectB, objectA);
8280
}
8381

82+
return this.checkCollisionClassic(objectA, objectB);
83+
}
84+
85+
private checkCollisionClassic(objectA: PhysicsObject, objectB: PhysicsObject): Vec2 | null {
86+
const [x1, y1, w1, h1] = objectA.aabb;
87+
const [x2, y2, w2, h2] = objectB.aabb;
88+
89+
const x1v = x1 + objectA.velocity.x;
90+
const y1v = y1 + objectA.velocity.y;
91+
const x2v = x2 + objectB.velocity.x;
92+
const y2v = y2 + objectB.velocity.y;
93+
94+
const xw1v = x1v + w1;
95+
const yh1v = y1v + h1;
96+
const xw2v = x2v + w2;
97+
const yh2v = y2v + h2;
98+
8499
// normal collision detection
85100
if (
86-
x1 < x2 + w2 &&
87-
x1 + w1 > x2 &&
88-
y1 < y2 + h2 &&
89-
y1 + h1 > y2
101+
x1v < xw2v &&
102+
xw1v > x2v &&
103+
y1v < yh2v &&
104+
yh1v > y2v
90105
) {
91106
return new Vec2();
92107
}
@@ -98,83 +113,32 @@ export class Physx {
98113
const [x1, y1, w1, h1] = container.aabb;
99114
const [x2, y2, w2, h2] = objectB.aabb;
100115

101-
const xw1 = x1 + w1;
102-
const yh1 = y1 + h1;
103-
const xw2 = x2 + w2;
104-
const yh2 = y2 + h2;
105-
106-
let result: Vec2 | null = null;
107-
let collisionQuadrant: CollisionQuadrant | null = null;
108-
109-
// another way might be to find the center of mass of each object and get the normal based on the
110-
// position of the objectB related to the center of mass of the container
111-
const containerCenterOfMass = new Vec2(x1 + w1 / 2, y1 + h1 / 2);
112-
const objectBCenterOfMass = new Vec2(x2 + w2 / 2, y2 + h2 / 2);
113-
114-
if (containerCenterOfMass.x <= objectBCenterOfMass.x && containerCenterOfMass.y <= objectBCenterOfMass.y) {
115-
collisionQuadrant = CollisionQuadrant.TopRight;
116-
} else if (objectBCenterOfMass.x < containerCenterOfMass.x && containerCenterOfMass.y <= objectBCenterOfMass.y) {
117-
collisionQuadrant = CollisionQuadrant.TopLeft;
118-
} else if(containerCenterOfMass.x <= objectBCenterOfMass.x && objectBCenterOfMass.y < containerCenterOfMass.y) {
119-
collisionQuadrant = CollisionQuadrant.BottomRight;
120-
} else {
121-
collisionQuadrant = CollisionQuadrant.BottomLeft;
122-
}
116+
const x1v = x1 + container.velocity.x;
117+
const y1v = y1 + container.velocity.y;
118+
const x2v = x2 + objectB.velocity.x;
119+
const y2v = y2 + objectB.velocity.y;
120+
121+
const xw1v = x1v + w1;
122+
const yh1v = y1v + h1;
123+
const xw2v = x2v + w2;
124+
const yh2v = y2v + h2;
123125

124-
if (collisionQuadrant === CollisionQuadrant.TopRight && (xw2 > xw1 || yh2 > yh1)) {
125-
// if xw2 - xw1 < yh2 - yh1 - the smaller negative number wins as it's the one with the greatest collision area
126-
// normal is a vector facing left
127-
// else is a vector facing down
128-
// new velocity is the reflection of the object original velocity related to the normal
129-
130-
result = Vec2.from(objectB.velocity);
131-
132-
if (xw2 - xw1 < yh2 - yh1) {
133-
result.reflect(Vec2.LEFT);
134-
} else {
135-
result.reflect(Vec2.DOWN);
136-
}
137-
} else if (collisionQuadrant === CollisionQuadrant.BottomRight && (xw2 > xw1 || y2 < y1)) {
138-
// if xw2 - xw1 < y2 - y1
139-
// normal is a vector facing left
140-
// else a vector facing up
141-
// new velocity is the reflection of the object original velocity related to the normal
142-
143-
result = Vec2.from(objectB.velocity);
144-
145-
if (xw2 - xw1 < y2 - y1) {
146-
result.reflect(Vec2.LEFT);
147-
} else {
148-
result.reflect(Vec2.UP);
149-
}
150-
} else if (collisionQuadrant === CollisionQuadrant.BottomLeft && (x2 < x1 || y2 < y1)) {
151-
// if x2 - x1 > y2 - y1 - on the left the bigger positive number wins
152-
// normal is a vector facing right
153-
// else a vector facing up
154-
// new velocity is the reflection of the object original velocity related to the normal
155-
156-
result = Vec2.from(objectB.velocity);
157-
158-
if (x2 - x1 > y2 - y1) {
159-
result.reflect(Vec2.RIGHT);
160-
} else {
161-
result.reflect(Vec2.UP);
162-
}
163-
} else if (collisionQuadrant === CollisionQuadrant.TopLeft && (x2 < x1 || yh2 > yh1)) {
164-
// if x2 - x1 > yh2 - yh1 - on the left the bigger positive number wins
165-
// normal is a vector facing right
166-
// else a vector facing down
167-
// new velocity is the reflection of the object original velocity related to the normal
168-
169-
result = Vec2.from(objectB.velocity);
170-
171-
if (x2 - x1 > yh2 - yh1) {
172-
result.reflect(Vec2.RIGHT);
173-
} else {
174-
result.reflect(Vec2.DOWN);
175-
}
126+
if (xw2v > xw1v) {
127+
return new Vec2();
176128
}
177-
178-
return result;
129+
130+
if (yh2v > yh1v) {
131+
return new Vec2();
132+
}
133+
134+
if(x2v < x1v) {
135+
return new Vec2();
136+
}
137+
138+
if (y2v < y1v) {
139+
return new Vec2();
140+
}
141+
142+
return null;
179143
}
180144
}

test/unit/physx/Physx.test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,34 @@ describe('physx/Physx', () => {
7575
expect(physicsObject2.onCollisionCallback).toHaveBeenCalledWith(physicsObject.object);
7676
});
7777

78+
// it('Should take the object velocity into collision account', () => {
79+
// const physicsObject: PhysicalObjectCallbackAggregate = {
80+
// object: {
81+
// aabb: [0, 100, 16, 150],
82+
// velocity: new Vec2(5)
83+
// },
84+
// onCollisionCallback: jest.fn(() => { }),
85+
// };
86+
87+
// const physicsObject2: PhysicalObjectCallbackAggregate = {
88+
// object: {
89+
// aabb: [0, 100, 20, 150],
90+
// velocity: new Vec2()
91+
// },
92+
// onCollisionCallback: jest.fn(() => { }),
93+
// };
94+
95+
// physx.pushPhysicalObject(physicsObject);
96+
// physx.pushPhysicalObject(physicsObject2);
97+
98+
// physx.simulate();
99+
100+
// expect(physicsObject.onCollisionCallback).toHaveBeenCalledWith(physicsObject2.object);
101+
// expect(physicsObject2.onCollisionCallback).toHaveBeenCalledWith(physicsObject.object);
102+
// })
103+
104+
it.todo('Should calculate and include in the Physics object callback the new velocity resulting from the collision')
105+
78106
it('Should not trigger a collision for object that are not colliding', () => {
79107
const physicsObject: PhysicalObjectCallbackAggregate = {
80108
object: {
@@ -100,6 +128,7 @@ describe('physx/Physx', () => {
100128
expect(physicsObject.onCollisionCallback).not.toHaveBeenCalled();
101129
expect(physicsObject2.onCollisionCallback).not.toHaveBeenCalled();
102130
});
131+
103132

104133
describe('.isContainer', () => {
105134
it.each([{

0 commit comments

Comments
 (0)