Physics

Physics Manager

The PhysicsScene (PhysicsScene) manages all physics components in the scene and communicates with the physics backend, implementing global operations related to the PhysicsScene, such as updates and ray casting. In multi-scene projects, each Scene has its own PhysicsScene, and physics systems between Scenes are isolated and do not affect each other.

Physics Update

The PhysicsScene and rendering scene are independent but continuously synchronize their data during program execution. Therefore, like scripts, the timing of synchronization is also very important. The update frequency of the PhysicsScene differs from the rendering scene and is controlled by the following parameter:

/** The fixed update time step (seconds) of the PhysicsScene */
fixedTimeStep: number = 1 / 60;

Update Mechanism

  • In each rendering frame, the physics engine updates according to the fixed time step fixedTimeStep
  • If the actual frame interval is greater than fixedTimeStep:
    • Multiple physics updates will be performed until catching up with the actual time
    • The maximum update time per frame is limited by engine.time.maximumDeltaTime
  • If the actual frame interval is less than fixedTimeStep, it accumulates to the next frame

Physics Update Callback

For physics component updates, you need to use a dedicated callback function in scripts:

export class Script extends Component {
  /**
   * Called before physics calculations, the number of calls depends on the physics update frequency
   */
  onPhysicsUpdate(): void {}
}

The position of the physics update in the entire update process can be referred to in the figure below

Internal Update Process of the Physics System

The execution order when the PhysicsScene is updated:

  1. Execute user logic in onPhysicsUpdate
  2. callColliderOnUpdate synchronizes the modified Entity Transform data to the physics collider
  3. Update the PhysicsScene
  4. callColliderOnLateUpdate synchronizes the updated positions of all colliders to the corresponding Entity

Setting Scene Gravity

The PhysicsScene allows customization of gravity direction and magnitude. Gravity affects all dynamic colliders with gravity enabled in the scene.

// Get the gravity value of the PhysicsScene
const gravity = scene.physics.gravity;
 
// Modify gravity - set gravity to 0
scene.physics.gravity.set(0, 0, 0);
 
// Modify gravity - set to Earth's gravitational acceleration (default value)
scene.physics.gravity.set(0, -9.81, 0);

Using Raycasting

A ray can be understood as an infinite line emitted from a point in a certain direction in the 3D world. Raycasting is widely used in 3D applications:

  • Used to pick objects in the 3D scene when the user clicks the screen
  • Used in shooting games to determine if a bullet can hit the target
  • Detect visibility and occlusion relationships between objects

Raycasting Example

To use raycasting, follow these steps:

  1. Import necessary modules such as Ray
  2. Create a ray (can be customized or generated through camera.screenPointToRay)
  3. Call the raycast method to detect collisions
// Load the Raycast module
import { WebGLEngine, HitResult, Ray } from "@galacean/engine";
import { LitePhysics } from "@galacean/engine-physics-lite";
 
const engine = await WebGLEngine.create({
  canvas: "canvas",
  physics: new LitePhysics()
});
engine.canvas.resizeByClientSize();
const scene = engine.scenes[0];
// Convert screen input to Ray
document.getElementById("canvas").addEventListener("click", (e) => {
  const ratio = window.devicePixelRatio;
  let ray = new Ray();
  camera.screenPointToRay(new Vector2(e.offsetX, e.offsetY).scale(ratio), ray);
  const hit = new HitResult();
  result = scene.physics.raycast(ray, Number.MAX_VALUE, Layer.Everything, hit);
  if (result) {
    console.log(hit.entity.name);
  }
});

Notes

  • Entity must add collider components to be detected by raycasting
  • When a ray hits multiple collider shapes at the same distance, it will return the Entity of the collider shape that was added first
  • It is recommended to use InputManager to handle input, as it provides a more convenient way to handle input

Was this page helpful?