Skip to content

Physical system design

yangfengzzz edited this page Apr 14, 2022 · 9 revisions

This is the design of physical system.

Author: @GuoLei1990 @yangfengzzz

The physics engine is a very important component of the game engine. The industry generally adopts PhysX to introduce related functions. However, for lightweight scenarios, PhysX makes the final application size very large, which exceeds the limitations of these projects. Oasis is based on a multi-backend design. On the one hand, it uses PhysX.js which compiled through WebAssembly. On the other hand, it also provides lightweight physics engine. The two are consistent at the API level. Users only need to select a specific physics backend when initializing the engine. It can meet the needs of various scenarios such as lightweight applications and heavyweight games.

Multi-backend subcontracting design of physical system

物理引擎分包设计 001

API Design

You can find the physics engine related interfaces here

UML: image

Script Call back:

In addition to physical components, users only need to care about the implementation of script logic. For the physics engine, the script class has the following interfaces

export class Script extends Component {
..............

  /**
   * Called before physics calculations, the number of times is related to the physical update frequency.
   */
  onPhysicsUpdate(): void {
  }

  /**
   * Called when the collision enter.
   * @param other - ColliderShape
   */
  onTriggerEnter(other: ColliderShape): void {
  }

  /**
   * Called when the collision stay.
   * @remarks onTriggerStay is called every frame while the collision stay.
   * @param other - ColliderShape
   */
  onTriggerExit(other: ColliderShape): void {
  }

  /**
   * Called when the collision exit.
   * @param other - ColliderShape
   */
  onTriggerStay(other: ColliderShape): void {
  }

  /**
   * Called when the collision enter.
   * @param other - ColliderShape
   */
  onCollisionEnter(other: ColliderShape): void {
  }

  /**
   * Called when the collision stay.
   * @remarks onTriggerStay is called every frame while the collision stay.
   * @param other - ColliderShape
   */
  onCollisionExit(other: ColliderShape): void {
  }

  /**
   * Called when the collision exit.
   * @param other - ColliderShape
   */
  onCollisionStay(other: ColliderShape): void {
  }

..............
}

There are three types of interfaces:

  1. onPhysicsUpdate: Called according to the update frequency of the physics engine.
  2. onTriggerXXX: Called by physics engine trigger.
  3. onCollisionXXX: Called by physics engine collider.

PhysicsManager:

PhysicsManager is to save the object of the physics backend, so that the update function of the physics engine can be called according to the update frequency. In addition, this class also packages all physics scripts into function objects, so that the physics engine calls them when triggering related triggers and collider events.

Generally speaking, users do not need to care about the above content. The most core usage in PhysicsManager is raycast, which judges whether objects in the physical scene intersect through ray detection, that is, the following API:

export class PhysicsManager {
  /** @internal */
  static _nativePhysics: IPhysics;

  /**
   * Casts a ray through the Scene and returns the first hit.
   * @param ray - The ray
   * @returns Returns true if the ray intersects with a Collider, otherwise false.
   */
  raycast(ray: Ray): Boolean;

  /**
   * Casts a ray through the Scene and returns the first hit.
   * @param ray - The ray
   * @param outHitResult - If true is returned, outHitResult will contain more detailed collision information
   * @returns Returns true if the ray intersects with a Collider, otherwise false.
   */
  raycast(ray: Ray, outHitResult: HitResult): Boolean;

  /**
   * Casts a ray through the Scene and returns the first hit.
   * @param ray - The ray
   * @param distance - The max distance the ray should check
   * @returns Returns true if the ray intersects with a Collider, otherwise false.
   */
  raycast(ray: Ray, distance: number): Boolean;

  /**
   * Casts a ray through the Scene and returns the first hit.
   * @param ray - The ray
   * @param distance - The max distance the ray should check
   * @param outHitResult - If true is returned, outHitResult will contain more detailed collision information
   * @returns Returns true if the ray intersects with a Collider, otherwise false.
   */
  raycast(ray: Ray, distance: number, outHitResult: HitResult): Boolean;

  /**
   * Casts a ray through the Scene and returns the first hit.
   * @param ray - The ray
   * @param distance - The max distance the ray should check
   * @param layerMask - Layer mask that is used to selectively ignore Colliders when casting
   * @returns Returns true if the ray intersects with a Collider, otherwise false.
   */
  raycast(ray: Ray, distance: number, layerMask: Layer): Boolean;

  /**
   * Casts a ray through the Scene and returns the first hit.
   * @param ray - The ray
   * @param distance - The max distance the ray should check
   * @param layerMask - Layer mask that is used to selectively ignore Colliders when casting
   * @param outHitResult - If true is returned, outHitResult will contain more detailed collision information
   * @returns Returns true if the ray intersects with a Collider, otherwise false.
   */
  raycast(ray: Ray, distance: number, layerMask: Layer, outHitResult: HitResult): Boolean;
}

Design Source Code

https://github.com/oasis-engine/engine/tree/main/packages/design/src/physics

User API Design: packages/core/src/physics
Physics engine interface Design: packages/design/src/physics
Physics engine implement sample: packages/physics-physX and packages/physics-lite