物理管理器(PhysicsManager)用于管理场景中所有的物理组件,并且负责与物理后端通信,实现有关物理场景的全局操作,例如更新和射线检测等等。在多场景项目中,每个Scene都有自己的PhysicsManager,Scene之间的物理系统是相互隔离互不影响的。
物理场景和渲染场景相互独立,但在程序运行过程中不断同步各自的数据。因此,和脚本一样,同步的时序也非常重要。一般来说,物理场景的更新频率和渲染场景不同,在物理管理器中可以对其进行设置:
/** The fixed time step in seconds at which physics are performed. */
fixedTimeStep: number = 1 / 60;
/** The max sum of time step in seconds one frame. */
maxSumTimeStep: number = 1 / 3;
每一个渲染帧中,物理引擎都会按照固定时间步长进行更新 fixedTimeStep
。
如果时时间间隔大于 fixedTimeStep
,则单步模拟的最大时间步长由 maxSumTimeStep
确定。此时,如果按照上面列出的默认参数,有可能会发生追帧现象。
这时候可以通过调节 maxSumTimeStep
降低每帧物理模拟的更新次数。
如果不满一个 fixedTimeStep
,则顺延到下一帧再处理。因此,每一个渲染帧,物理场景可能会更新多次,也可能只更新一次,因此对于有关物理组件更新,都需要放在特定的更新函数,Script
提供了这一接口:
export class Script extends Component {
/**
* Called before physics calculations, the number of times is related to the physical update frequency.
*/
onPhysicsUpdate(): void {
}
}
物理场景在更新时,除了调用该函数,还会同步 Collider 和其所挂载的 Entity 的姿态。物理更新的时序如下:
onPhysicsUpdate
中的用户逻辑callColliderOnUpdate
将被修改的 Entity 新姿态同步给物理碰撞器callColliderOnLateUpdate
将所有 DynamicCollider 更新后的位置同步给对应的 Entity射线可以理解成 3D 世界中一个点向一个方向发射的一条无终点的线。射线投射在 3D 应用中非常广泛。通过射线投射,可以在用户点击屏幕时,拾取 3D 场景中的物体;也可以在射击游戏中,判断子弹能否射中目标。
(图片来源于网络)
在使用射线投射,首先要在代码中引入 Ray 模块;然后生成射线,射线可以自定义生成,也可以通过相机(camera )将屏幕输入转化成射线;最后调用 PhysicsManager.raycast 方法即可检测射线投射命中的碰撞体。代码如下:
// 加载 Raycast 模块
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();
// 将屏幕输入转换成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 = engine.physicsManager.raycast(ray, Number.MAX_VALUE, Layer.Everything, hit);
if (result) {
console.log(hit.entity.name);
}
});
需要特别指出,如果想要对 Entity 启用射线投射,该 Entity 就必须拥有 Collider ,否则无法触发。若射线命中的Collider的Shape距离相同,则返回先被添加的Shape(举个例子:有两个Collider相同的Entity完全重合,则会返回先添加Collider,更准确的说是先添加Shape的Entity)。
同时,在 Galacean 当中,还提供了 InputManager,该管理器将输入源做了封装,提供了更加易用的逻辑,使用方式可以参考 .