Skip to content

Commit 93312ad

Browse files
willeastcottclaude
andcommitted
refactor(physics): split rigid-body data classes into separate modules
Move RaycastResult, SingleContactResult, ContactPoint and ContactResult out of system.js into their own one-class modules, matching the engine's one-class-per-file convention. Behavior-neutral; the public API is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent d19586e commit 93312ad

6 files changed

Lines changed: 350 additions & 319 deletions

File tree

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import { Vec3 } from '../../../core/math/vec3.js';
2+
3+
/**
4+
* Represents a single point of contact between two colliding rigid bodies in the physics
5+
* simulation. Each contact point stores detailed spatial information about the collision,
6+
* including both local and world space coordinates of the exact contact points on both entities,
7+
* the contact normal direction, and the collision impulse force.
8+
*
9+
* Contact points are generated by the physics engine during collision detection and are typically
10+
* accessed through a {@link ContactResult} object, which can contain multiple contact points for a
11+
* single collision between two entities. Multiple contact points commonly occur when objects
12+
* collide along edges or faces rather than at a single point.
13+
*
14+
* The impulse property can be particularly useful for gameplay mechanics that need to respond
15+
* differently based on the force of impact, such as damage calculations or sound effect volume.
16+
*
17+
* @example
18+
* // Access contact points from a collision event
19+
* entity.collision.on('contact', (result) => {
20+
* // Get the first contact point
21+
* const contact = result.contacts[0];
22+
*
23+
* // Get the contact position in world space
24+
* const worldPos = contact.point;
25+
*
26+
* // Check how hard the collision was
27+
* if (contact.impulse > 10) {
28+
* console.log("That was a hard impact!");
29+
* }
30+
* });
31+
*
32+
* @category Physics
33+
*/
34+
class ContactPoint {
35+
/**
36+
* The point on the entity where the contact occurred, relative to the entity.
37+
*
38+
* @type {Vec3}
39+
*/
40+
localPoint;
41+
42+
/**
43+
* The point on the other entity where the contact occurred, relative to the other entity.
44+
*
45+
* @type {Vec3}
46+
*/
47+
localPointOther;
48+
49+
/**
50+
* The point on the entity where the contact occurred, in world space.
51+
*
52+
* @type {Vec3}
53+
*/
54+
point;
55+
56+
/**
57+
* The point on the other entity where the contact occurred, in world space.
58+
*
59+
* @type {Vec3}
60+
*/
61+
pointOther;
62+
63+
/**
64+
* The normal vector of the contact on the other entity, in world space. This vector points
65+
* away from the surface of the other entity at the point of contact.
66+
*
67+
* @type {Vec3}
68+
*/
69+
normal;
70+
71+
/**
72+
* The total accumulated impulse applied by the constraint solver during the last sub-step.
73+
* This value represents how hard two objects collided. Higher values indicate stronger impacts.
74+
*
75+
* @type {number}
76+
*/
77+
impulse;
78+
79+
/**
80+
* Create a new ContactPoint instance.
81+
*
82+
* @param {Vec3} [localPoint] - The point on the entity where the contact occurred, relative to
83+
* the entity.
84+
* @param {Vec3} [localPointOther] - The point on the other entity where the contact occurred,
85+
* relative to the other entity.
86+
* @param {Vec3} [point] - The point on the entity where the contact occurred, in world space.
87+
* @param {Vec3} [pointOther] - The point on the other entity where the contact occurred, in
88+
* world space.
89+
* @param {Vec3} [normal] - The normal vector of the contact on the other entity, in world
90+
* space.
91+
* @param {number} [impulse] - The total accumulated impulse applied by the constraint solver
92+
* during the last sub-step. Describes how hard two objects collide. Defaults to 0.
93+
* @ignore
94+
*/
95+
constructor(localPoint = new Vec3(), localPointOther = new Vec3(), point = new Vec3(), pointOther = new Vec3(), normal = new Vec3(), impulse = 0) {
96+
this.localPoint = localPoint;
97+
this.localPointOther = localPointOther;
98+
this.point = point;
99+
this.pointOther = pointOther;
100+
this.normal = normal;
101+
this.impulse = impulse;
102+
}
103+
}
104+
105+
export { ContactPoint };
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/**
2+
* @import { Entity } from '../../entity.js'
3+
* @import { ContactPoint } from './contact-point.js'
4+
*/
5+
6+
/**
7+
* Represents a collection of contact points between two entities in a physics collision.
8+
* When rigid bodies collide, this object stores the entity involved in the collision and
9+
* an array of specific contact points where the collision occurred. This information is
10+
* used by the physics system to resolve collisions and notify components through events.
11+
*
12+
* Instances of this class are passed to event handlers for the `contact` and `collisionstart`
13+
* events on individual {@link RigidBodyComponent} and {@link CollisionComponent} instances.
14+
*
15+
* Unlike {@link SingleContactResult} which is used for global contact events, ContactResult
16+
* objects provide information about collision from the perspective of one entity, with
17+
* information about which other entity was involved and all points of contact.
18+
*
19+
* Please refer to the following event documentation for more information:
20+
*
21+
* - {@link CollisionComponent.EVENT_CONTACT}
22+
* - {@link CollisionComponent.EVENT_COLLISIONSTART}
23+
* - {@link RigidBodyComponent.EVENT_CONTACT}
24+
* - {@link RigidBodyComponent.EVENT_COLLISIONSTART}
25+
*
26+
* @category Physics
27+
*/
28+
class ContactResult {
29+
/**
30+
* The entity that was involved in the contact with this entity.
31+
*
32+
* @type {Entity}
33+
*/
34+
other;
35+
36+
/**
37+
* An array of ContactPoints with the other entity.
38+
*
39+
* @type {ContactPoint[]}
40+
*/
41+
contacts;
42+
43+
/**
44+
* Create a new ContactResult instance.
45+
*
46+
* @param {Entity} other - The entity that was involved in the contact with this entity.
47+
* @param {ContactPoint[]} contacts - An array of ContactPoints with the other entity.
48+
* @ignore
49+
*/
50+
constructor(other, contacts) {
51+
this.other = other;
52+
this.contacts = contacts;
53+
}
54+
}
55+
56+
export { ContactResult };
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* @import { Entity } from '../../entity.js'
3+
* @import { Vec3 } from '../../../core/math/vec3.js'
4+
*/
5+
6+
/**
7+
* Contains the result of a successful raycast intersection with a rigid body. When a ray
8+
* intersects with a rigid body in the physics simulation, this class stores the complete
9+
* information about that intersection including the entity, the exact point of impact, the normal
10+
* at the impact point, and the fractional distance along the ray where the intersection occurred.
11+
*
12+
* Instances of this class are created and returned by {@link RigidBodyComponentSystem#raycastFirst}
13+
* and {@link RigidBodyComponentSystem#raycastAll} methods when performing physics raycasts.
14+
*
15+
* @category Physics
16+
*/
17+
class RaycastResult {
18+
/**
19+
* The entity that was hit.
20+
*
21+
* @type {Entity}
22+
*/
23+
entity;
24+
25+
/**
26+
* The point at which the ray hit the entity in world space.
27+
*
28+
* @type {Vec3}
29+
*/
30+
point;
31+
32+
/**
33+
* The normal vector of the surface where the ray hit in world space.
34+
*
35+
* @type {Vec3}
36+
*/
37+
normal;
38+
39+
/**
40+
* The normalized distance (between 0 and 1) at which the ray hit occurred from the
41+
* starting point.
42+
*
43+
* @type {number}
44+
*/
45+
hitFraction;
46+
47+
/**
48+
* Create a new RaycastResult instance.
49+
*
50+
* @param {Entity} entity - The entity that was hit.
51+
* @param {Vec3} point - The point at which the ray hit the entity in world space.
52+
* @param {Vec3} normal - The normal vector of the surface where the ray hit in world space.
53+
* @param {number} hitFraction - The normalized distance (between 0 and 1) at which the ray hit
54+
* occurred from the starting point.
55+
* @ignore
56+
*/
57+
constructor(entity, point, normal, hitFraction) {
58+
this.entity = entity;
59+
this.point = point;
60+
this.normal = normal;
61+
this.hitFraction = hitFraction;
62+
}
63+
}
64+
65+
export { RaycastResult };
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import { Vec3 } from '../../../core/math/vec3.js';
2+
3+
/**
4+
* @import { Entity } from '../../entity.js'
5+
* @import { ContactPoint } from './contact-point.js'
6+
*/
7+
8+
/**
9+
* Represents the detailed data of a single contact point between two rigid bodies in the physics
10+
* simulation. This class provides comprehensive information about the contact, including the
11+
* entities involved, the exact contact points in both local and world space coordinates, the
12+
* contact normal, and the collision impulse force.
13+
*
14+
* Instances of this class are created by the physics engine when collision events occur and are
15+
* passed to event handlers only through the global `contact` event on the
16+
* {@link RigidBodyComponentSystem}. Individual rigid body components receive instances of
17+
* {@link ContactResult} instead.
18+
*
19+
* @example
20+
* app.systems.rigidbody.on('contact', (result) => {
21+
* console.log(`Contact between ${result.a.name} and ${result.b.name}`);
22+
* });
23+
* @category Physics
24+
*/
25+
class SingleContactResult {
26+
/**
27+
* The first entity involved in the contact.
28+
*
29+
* @type {Entity}
30+
*/
31+
a;
32+
33+
/**
34+
* The second entity involved in the contact.
35+
*
36+
* @type {Entity}
37+
*/
38+
b;
39+
40+
/**
41+
* The total accumulated impulse applied by the constraint solver during the last
42+
* sub-step. Describes how hard two bodies collided.
43+
*
44+
* @type {number}
45+
*/
46+
impulse;
47+
48+
/**
49+
* The point on Entity A where the contact occurred, relative to A.
50+
*
51+
* @type {Vec3}
52+
*/
53+
localPointA;
54+
55+
/**
56+
* The point on Entity B where the contact occurred, relative to B.
57+
*
58+
* @type {Vec3}
59+
*/
60+
localPointB;
61+
62+
/**
63+
* The point on Entity A where the contact occurred, in world space.
64+
*
65+
* @type {Vec3}
66+
*/
67+
pointA;
68+
69+
/**
70+
* The point on Entity B where the contact occurred, in world space.
71+
*
72+
* @type {Vec3}
73+
*/
74+
pointB;
75+
76+
/**
77+
* The normal vector of the contact on Entity B, in world space.
78+
*
79+
* @type {Vec3}
80+
*/
81+
normal;
82+
83+
/**
84+
* Create a new SingleContactResult instance.
85+
*
86+
* @param {Entity} a - The first entity involved in the contact.
87+
* @param {Entity} b - The second entity involved in the contact.
88+
* @param {ContactPoint} contactPoint - The contact point between the two entities.
89+
* @ignore
90+
*/
91+
constructor(a, b, contactPoint) {
92+
if (arguments.length !== 0) {
93+
this.a = a;
94+
this.b = b;
95+
this.impulse = contactPoint.impulse;
96+
this.localPointA = contactPoint.localPoint;
97+
this.localPointB = contactPoint.localPointOther;
98+
this.pointA = contactPoint.point;
99+
this.pointB = contactPoint.pointOther;
100+
this.normal = contactPoint.normal;
101+
} else {
102+
this.a = null;
103+
this.b = null;
104+
this.impulse = 0;
105+
this.localPointA = new Vec3();
106+
this.localPointB = new Vec3();
107+
this.pointA = new Vec3();
108+
this.pointB = new Vec3();
109+
this.normal = new Vec3();
110+
}
111+
}
112+
}
113+
114+
export { SingleContactResult };

0 commit comments

Comments
 (0)