物理场景(PhysicsScene)用于管理场景中所有的物理组件,并且负责与物理后端通信,实现有关物理场景的全局操作,例如更新和射线检测等等。在多场景项目中,每个Scene都有自己的物理场景,Scene之间的物理系统是相互隔离互不影响的。
物理场景和渲染场景相互独立,但在程序运行过程中不断同步各自的数据。因此,和脚本一样,同步的时序也非常重要。物理场景的更新频率和渲染场景不同,通过以下参数进行控制:
/** 物理场景的固定更新时间步长(秒) */
fixedTimeStep: number = 1 / 60;
fixedTimeStep
:
engine.time.maximumDeltaTime
限制fixedTimeStep
,则累积到下一帧处理针对物理组件的更新,需要使用脚本中专门的回调函数:
export class Script extends Component {
/**
* 在物理计算前调用,调用次数取决于物理更新频率
*/
onPhysicsUpdate(): void {}
}
物理更新在整个更新流程中的位置可以参考下图
物理场景在更新时的执行顺序:
onPhysicsUpdate
中的用户逻辑callColliderOnUpdate
将被修改的 实体 Transform
数据同步给物理碰撞器callColliderOnLateUpdate
将所有 碰撞器 更新后的位置同步给对应的 实体
物理场景允许自定义重力方向和大小。重力会影响场景中所有启用重力的动态碰撞器。
// 获取物理场景的重力值
const gravity = scene.physics.gravity;
// 修改重力 - 将重力改为 0
scene.physics.gravity.set(0, 0, 0);
// 修改重力 - 设置为地球重力加速度 (默认值)
scene.physics.gravity.set(0, -9.81, 0);
射线可以理解成 3D 世界中一个点向一个方向发射的一条无终点的线。射线投射在 3D 应用中应用非常广泛:
(图片来源于网络)
使用射线检测需要以下步骤:
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();
const scene = engine.scenes[0];
// 将屏幕输入转换成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);
}
});