Check collisions between objects on specific layers

Hi everyone,

I make sure to have the latest version, and use the “physics_3d_collision_layers” demonstrate to see how objects of different layers interact, but unfortunately when I open the code for the main play screen (not init but play, the one that happens every frame), there doesn’t seem to be anything obvious/noticeable about testing whether two objects of specific layers collide, like there is no script on a sphere saying for example “if I collide with all objects of a particular layer do something”;

I tried looking in the scripting API for an answer but can’t seem to find anything;

my goal is to make a double jump, but only if you aren’t touching the ground, so “if player rigid body is not touching any object on layer ground set can double jump to 1”, for a Super Mario 64 style fan game.

Does anybody have any ideas as to how I would go about this?

There is indeed no explicit code that checks for collisions in example “physics_3d_collision_layers (or other physics examples). The point of physics engine is that such collisions are checked internally by CGE code (actually our physics engine, Kraft). Also internally we “react” to them (when 2 objects collide, they bounce off each other, by default). So there’s just no code needed to do this. It happens just because you set up TCastleRigidBody and TCastleXxxCollider instances.

See Physics | Manual | Castle Game Engine for more docs about physics.

As for your question: you want to detect whether player is standing on the ground. To do this, use “ray cast” with a ray direction set to “downward” (this is Vector3(0, -1, 0) in CGE). If you have an instance of TCastleRigidBody called MyRigidBody, do something like

var
  GroundRayCast: TPhysicsRayCastResult;
  RayOrigin: TVector3;
  MaxDistanceToGround: Single;
  StandOnGround: Boolean;
begin
  RayOrigin := ...;
  MaxDistanceToGround := ...;
  GroundRayCast := MyRigidBody.PhysicsRayCast(
    RayOrigin,
    Vector3(0, -1, 0),
    MaxDistanceToGround
  );
  StandOnGround := GroundRayCast.Hit and (GroundRayCastHit.Distance <= 1.23 + 0.01);
  if StandOnGround then
    ... // do some decision based on StandOnGround, or pass it somewhere
end;

Set RayOrigin to some point in the middle of the avatar. Like just Vector3(0, 1.23, 0), where 1.23 is just an example. If the raycast will return that something collides with a distance similar to 1.23 (you can add there some epsilon like 0.01), then you know you stand on ground. Otherwise (if the raycast returns no collision, or the collision is further than that distance) you know you’re flying the air.

Set MaxDistanceToGround to some value further than any ground you hope to detect. You can pass just some huge value, like 100000, but actually passing something “significantly larger than the distance you hope to detect” is better. In the example above, I would use 2 * 1.23, since we don’t care to detect objects further than that.

See Castle Game Engine: CastleTransform: Class TCastleRigidBody for detailed docs of TCastleRigidBody.PhysicsRayCast.

There’s also Viewport.Items.PhysicsRayCast, but it’s less comfortable in this case. (because TCastleRigidBody.PhysicsRayCast automatically ignores collision with parent body, so the ray cast will not detect the avatar). Though if you use layers to already avoid that, then it may also be useful. See Castle Game Engine: CastleTransform: Class TCastleAbstractRootTransform .

See examples/platformer/ for a big example using this technique. It is using PhysicsRayCast for various purposes, proper jumping being just one of them.