Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api/animate.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ const updateCapsuleShapeForAnimation = (physicsMesh, animationName) => {
flock.scene,
);
} else {
newShape = flock.createCapsuleFromBoundingBox(physicsMesh, flock.scene);
newShape = flock.createShapeFromBoundingBox(physicsMesh, flock.scene);
}

physicsMesh.physics.shape = newShape;
Expand Down
25 changes: 15 additions & 10 deletions api/mesh.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,37 @@ export function setFlockReference(ref) {
}

export const flockMesh = {
createCapsuleFromBoundingBox(mesh, scene) {
createShapeFromBoundingBox(mesh, scene) {
mesh.computeWorldMatrix(true);
const boundingInfo = mesh.getBoundingInfo();
// Use LOCAL bounding box coordinates
const localMin = boundingInfo.boundingBox.minimum;
const localMax = boundingInfo.boundingBox.maximum;

// Apply the mesh's scaling to get actual dimensions
const height = (localMax.y - localMin.y) * Math.abs(mesh.scaling.y);
const width = (localMax.x - localMin.x) * Math.abs(mesh.scaling.x);
const depth = (localMax.z - localMin.z) * Math.abs(mesh.scaling.z);

const radius = Math.min(width, depth) / 2;

// Shrink the capsule vertically to allow intersections
const shrinkAmount = 0.01; // Adjust this value as needed
const adjustedHeight = Math.max(0, height - shrinkAmount);
const cylinderHeight = Math.max(0, adjustedHeight - 2 * radius);

// Center the capsule at the bounding box center in LOCAL space
const localCenter = new flock.BABYLON.Vector3(
(localMin.x + localMax.x) / 2,
(localMin.y + localMax.y) / 2,
(localMin.z + localMax.z) / 2,
);

if (height < 2 * radius) {
return new flock.BABYLON.PhysicsShapeBox(
localCenter,
flock.BABYLON.Quaternion.Identity(),
new flock.BABYLON.Vector3(width, height, depth),
scene,
);
}

const shrinkAmount = 0.01;
const adjustedHeight = Math.max(0, height - shrinkAmount);
const cylinderHeight = adjustedHeight - 2 * radius;
Comment on lines +28 to +39
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use the same threshold for the fallback and the shrink step.

height < 2 * radius is checked before subtracting shrinkAmount, so meshes at height === 2 * radius — or within 0.01 above it — still go down the capsule path and end up with a negative cylinderHeight. That reintroduces the degenerate geometry this change is trying to avoid.

Suggested fix
-    if (height < 2 * radius) {
+    const shrinkAmount = 0.01;
+    const adjustedHeight = Math.max(0, height - shrinkAmount);
+    if (adjustedHeight <= 2 * radius) {
       return new flock.BABYLON.PhysicsShapeBox(
         localCenter,
         flock.BABYLON.Quaternion.Identity(),
         new flock.BABYLON.Vector3(width, height, depth),
         scene,
       );
     }
 
-    const shrinkAmount = 0.01;
-    const adjustedHeight = Math.max(0, height - shrinkAmount);
-    const cylinderHeight = adjustedHeight - 2 * radius;
+    const cylinderHeight = Math.max(0, adjustedHeight - 2 * radius);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (height < 2 * radius) {
return new flock.BABYLON.PhysicsShapeBox(
localCenter,
flock.BABYLON.Quaternion.Identity(),
new flock.BABYLON.Vector3(width, height, depth),
scene,
);
}
const shrinkAmount = 0.01;
const adjustedHeight = Math.max(0, height - shrinkAmount);
const cylinderHeight = adjustedHeight - 2 * radius;
const shrinkAmount = 0.01;
const adjustedHeight = Math.max(0, height - shrinkAmount);
if (adjustedHeight <= 2 * radius) {
return new flock.BABYLON.PhysicsShapeBox(
localCenter,
flock.BABYLON.Quaternion.Identity(),
new flock.BABYLON.Vector3(width, height, depth),
scene,
);
}
const cylinderHeight = Math.max(0, adjustedHeight - 2 * radius);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/mesh.js` around lines 28 - 39, Compute the adjustedHeight (using
shrinkAmount) before deciding the fallback and use that adjustedHeight when
checking against 2 * radius so you don't produce a negative cylinderHeight;
specifically, move or add adjustedHeight = Math.max(0, height - shrinkAmount)
above the conditional and change the test from if (height < 2 * radius) to if
(adjustedHeight < 2 * radius) so the fallback box path and the cylinderHeight
calculation (cylinderHeight = adjustedHeight - 2 * radius) use the same
threshold.


const segmentStart = new flock.BABYLON.Vector3(
localCenter.x,
localCenter.y - cylinderHeight / 2,
Expand Down Expand Up @@ -797,7 +802,7 @@ export const flockMesh = {
flock.scene,
);

const boxShape = flock.createCapsuleFromBoundingBox(bb, flock.scene);
const boxShape = flock.createShapeFromBoundingBox(bb, flock.scene);

boxBody.shape = boxShape;
boxBody.setMassProperties({ mass: 1, restitution: 0.5 });
Expand Down
4 changes: 2 additions & 2 deletions api/physics.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const disposePhysics = (targetMesh) => {
const createPhysicsShape = (mesh, shapeType) => {
if (shapeType === "CAPSULE") {
mesh.computeWorldMatrix(true);
return flock.createCapsuleFromBoundingBox(mesh, flock.scene);
return flock.createShapeFromBoundingBox(mesh, flock.scene);
}
Comment on lines 58 to 62
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n -C3 'getShapeTypeFromPhysics|PhysicsShapeBox|createShapeFromBoundingBox|physicsShapeType|physicsCache|resolvedShapeType|setupMesh' api/physics.js api/mesh.js

Repository: flipcomputing/flock

Length of output: 6511


🏁 Script executed:

sed -n '3,17p' api/physics.js

Repository: flipcomputing/flock

Length of output: 448


Persist the actual collider type returned by createShapeFromBoundingBox().

getShapeTypeFromPhysics() only recognizes PhysicsShapeCapsule and PhysicsShapeMesh (returns null for any other type). However, createShapeFromBoundingBox() can return PhysicsShapeBox based on dimensions (api/mesh.js:29). When called at lines 61 and 328–331, the actual returned shape type is never captured—only the requested "CAPSULE" intent is stored in physicsShapeType. This causes boxes created here to be misidentified as "MESH" on restore (line 276 defaults to "MESH" when type is missing), losing the intended collider. Similarly, bodies seeded in api/mesh.js:805 via setupMesh don't persist their shape type at all.

Derive the real shape type from the returned object immediately after creation and cache it instead of the requested type.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/physics.js` around lines 58 - 62, The created collider's actual type
isn't being saved: in createPhysicsShape when you call
flock.createShapeFromBoundingBox(mesh, flock.scene) (and similarly where
setupMesh seeds bodies), capture the returned shape object, call
getShapeTypeFromPhysics(returnedShape) to derive the real type, and assign that
result to physicsShapeType (instead of the requested "CAPSULE" literal). Update
any mesh/body seeding code that previously set physicsShapeType implicitly to
instead inspect the created shape and persist the derived type so boxes created
by createShapeFromBoundingBox are stored correctly.

return new flock.BABYLON.PhysicsShapeMesh(mesh, flock.scene);
};
Expand Down Expand Up @@ -325,7 +325,7 @@ export const flockPhysics = {
disposePhysics(targetMesh);

// IMPORTANT: use targetMesh (not outer mesh)
const physicsShape = flock.createCapsuleFromBoundingBox(
const physicsShape = flock.createShapeFromBoundingBox(
targetMesh,
flock.scene,
);
Expand Down
2 changes: 1 addition & 1 deletion ui/blockmesh.js
Original file line number Diff line number Diff line change
Expand Up @@ -1536,7 +1536,7 @@ function setAbsoluteSize(mesh, width, height, depth) {
);
break;
case "Capsule":
newShape = flock.createCapsuleFromBoundingBox(mesh, mesh.getScene());
newShape = flock.createShapeFromBoundingBox(mesh, mesh.getScene());
break;
default:
console.log("Unknown or unsupported physics shape type: " + shapeType);
Expand Down
Loading