Raycast to check if player is standing on ground

Please refer to the Playground link below:
Playground

Please click inside the Playground scene to activate Pointer Lock. Pressing Esc will exit Pointer Lock. To move use WASD. To jump use Space.

  • Blue mesh is the player.
  • Green mesh is a pillar with checkCollisions = true . The grey ground also has collision checking on. An array named obstacles contains both this pillar and the ground.

In the Playground, please view the code under // Raycast Method 1 and // Raycast Method 2:

// Raycast Method 1
const pick = scene.pickWithRay(ray);
if (pick) onObject = pick.hit;

// Raycast Method 2
for (const obstacle of obstacles) {
    if (ray.intersectsBox(obstacle.getBoundingInfo().boundingBox)) {
        onObject = true;
    }
}

Raycast Method 1 works. Note that when the player lands on the ground, we can press Space to jump again.

Raycast Method 2 does not work (with Method 1 commented out). For some reason, the player remains in the air, and the raycast thinks it’s intersecting one of the obstacles… We can keep pressing Space to move the player higher.

Any guidance would be very much appreciated :smiley: Please find below an image showing the RayHelper (red).

A tiny repro to help focusing only on the intersect issue: https://www.babylonjs-playground.com/#3EDS3A#12

1 Like

At a first quick glance it looks like the ray length is not accounted for in the intersectBox method… if I am not mistaken :slight_smile:

1 Like

@gbz, this is all by design that the intersectBox does not account for the length and I will add doc in the comments of the method to precise it.

In your case fast picking would be the way to go :slight_smile:
https://www.babylonjs-playground.com/#3EDS3A#13

basically the pick predicate will help you only test the mesh you want and the 3rd param fast check will be pretty close to the fast Line vs AABB algo in use in the intersectBox function.

3 Likes

Thank you so much for all your time and help, @sebavan! :smiley:

@sebavan, thank you for providing a code snippet that works:

const pick = scene.pickWithRay(ray, (mesh) => {
    return mesh === ground;
}, true);

if (pick) onObject = pick.hit;

However, I wish there was a way not to iterate over all meshes in the scene (even if the raycast check is only ran on meshes fulfulling the predicate).

Suppose there were 1000 environment meshes and only 5 player meshes. To check if a bullet hits a player, I wouldn’t want to iterate over all 1000 environment meshes and check if they are players. I would love to be able to do something like:

class Player {
    mesh = BABYLON.MeshBuilder.CreateBox(...);
    health = 100;
}

for (const player of players) {
    // hypothetical ray intersection with single mesh method that doesn't currently exist
    const pick = ray.pickWithRay(player.mesh); // pick information is also valuable
    if (pick && pick.hit) { // bullet hits player
        // actions on hit player
        player.health -= 10;
    }
}

This is also convenient since player has a reference to its mesh (player.mesh), but the mesh doesn’t have a reference to its player. So with the currently existing scene.pickWithRay, which returns a picked mesh as pickedMesh, it’s not as straightforward to find which player that mesh corresponds to.

Do you know how we could request a raycast feature like this? This can already be done with AABB collisions with intersectsMesh. Thank you for all of your time and help!

1 Like

@gbz
thanks very much, this example really helps . thanks very much.

1 Like