mirror of
https://github.com/galacean/engine.git
synced 2026-05-22 17:00:49 +08:00
287 lines
8.8 KiB
Plaintext
287 lines
8.8 KiB
Plaintext
---
|
||
order: 4
|
||
title: 形状投射
|
||
type: 物理
|
||
label: Physics
|
||
---
|
||
|
||
形状投射(Shape Casting)是物理引擎中的高级查询功能,可以沿指定方向"投射"一个三维形状来检测阻挡。与 [射线检测](/docs/physics/query/raycast) 使用无限细的线不同,形状投射使用具有体积的几何体进行检测,能够提供更精确和实用的阻挡信息。
|
||
|
||
## 概述
|
||
|
||
Galacean 物理引擎提供三种形状投射功能:
|
||
|
||
- **boxCast** - 盒子投射:投射一个立方体形状
|
||
- **sphereCast** - 球体投射:投射一个球形形状
|
||
- **capsuleCast** - 胶囊投射:投射一个胶囊形状
|
||
|
||
<Image src="https://mdn.alipayobjects.com/huamei_3zduhr/afts/img/A*AicVTLV-8dsAAAAAQHAAAAgAesJ_AQ/original" />
|
||
|
||
## 应用场景
|
||
|
||
形状投射在游戏开发中有广泛应用:
|
||
|
||
- **角色移动检测** - 在角色移动前检测是否会被障碍物阻挡
|
||
- **载具路径预测** - 检测车辆、飞机等载具的移动路径是否畅通
|
||
- **武器攻击判定** - 模拟剑击、爆炸等具有范围的攻击
|
||
- **物体放置验证** - 在放置物体前检测空间是否足够
|
||
- **AI路径规划** - 为AI角色规划安全的移动路径
|
||
|
||
## 盒子投射 (boxCast)
|
||
|
||
盒子投射沿指定方向投射一个立方体,检测与场景中碰撞器的交集。
|
||
|
||
### 函数重载
|
||
|
||
为了提升易用性,`boxCast` 提供了多个重载版本:
|
||
|
||
```typescript
|
||
// 基础检测 - 仅返回是否被阻挡
|
||
boxCast(center: Vector3, halfExtents: Vector3, direction: Vector3): boolean
|
||
|
||
// 获取命中信息
|
||
boxCast(center: Vector3, halfExtents: Vector3, direction: Vector3, outHitResult: HitResult): boolean
|
||
|
||
// 指定投射距离
|
||
boxCast(center: Vector3, halfExtents: Vector3, direction: Vector3, distance: number): boolean
|
||
|
||
// 指定距离并获取命中信息
|
||
boxCast(center: Vector3, halfExtents: Vector3, direction: Vector3, distance: number, outHitResult: HitResult): boolean
|
||
|
||
// 完整参数版本
|
||
boxCast(
|
||
center: Vector3,
|
||
halfExtents: Vector3,
|
||
direction: Vector3,
|
||
orientation: Quaternion,
|
||
distance: number,
|
||
layerMask: Layer,
|
||
outHitResult?: HitResult
|
||
): boolean
|
||
```
|
||
|
||
### 使用示例
|
||
|
||
```typescript
|
||
import { Vector3, HitResult, Layer, Quaternion } from "@galacean/engine";
|
||
|
||
// 获取物理场景
|
||
const physicsScene = scene.physics;
|
||
|
||
// 示例1: 基础阻挡检测
|
||
const center = new Vector3(0, 5, 0);
|
||
const halfExtents = new Vector3(1, 1, 1); // 盒子半尺寸
|
||
const direction = new Vector3(0, -1, 0); // 向下投射
|
||
|
||
if (physicsScene.boxCast(center, halfExtents, direction)) {
|
||
console.log("检测到阻挡!");
|
||
}
|
||
|
||
// 示例2: 获取详细命中信息
|
||
const hitResult = new HitResult();
|
||
if (physicsScene.boxCast(center, halfExtents, direction, hitResult)) {
|
||
console.log(`命中实体: ${hitResult.entity.name}`);
|
||
console.log(`命中距离: ${hitResult.distance}`);
|
||
console.log(`命中点: ${hitResult.point.toString()}`);
|
||
console.log(`命中法线: ${hitResult.normal.toString()}`);
|
||
}
|
||
|
||
// 示例3: 角色移动预检测
|
||
const playerSize = new Vector3(0.5, 1, 0.5);
|
||
const moveDirection = new Vector3(1, 0, 0);
|
||
const moveDistance = 2.0;
|
||
|
||
if (!physicsScene.boxCast(playerPosition, playerSize, moveDirection, moveDistance)) {
|
||
// 路径安全,可以移动
|
||
playerPosition.add(moveDirection.scale(moveDistance));
|
||
}
|
||
|
||
// 示例4: 使用完整参数进行精确检测
|
||
const orientation = new Quaternion(0, 0, 0, 1); // 无旋转
|
||
const layerMask = Layer.Everything; // 检测所有层
|
||
const maxDistance = 10.0;
|
||
|
||
const detailHit = new HitResult();
|
||
if (physicsScene.boxCast(
|
||
center,
|
||
halfExtents,
|
||
direction,
|
||
orientation,
|
||
maxDistance,
|
||
layerMask,
|
||
detailHit
|
||
)) {
|
||
console.log("精确检测成功");
|
||
}
|
||
```
|
||
|
||
## 球体投射 (sphereCast)
|
||
|
||
球体投射沿指定方向投射一个球形,适用于需要球形检测区域的场景。
|
||
|
||
### 函数重载
|
||
|
||
```typescript
|
||
// 基础检测
|
||
sphereCast(center: Vector3, radius: number, direction: Vector3): boolean
|
||
|
||
// 获取命中信息
|
||
sphereCast(center: Vector3, radius: number, direction: Vector3, outHitResult: HitResult): boolean
|
||
|
||
// 指定投射距离
|
||
sphereCast(center: Vector3, radius: number, direction: Vector3, distance: number): boolean
|
||
|
||
// 指定距离并获取命中信息
|
||
sphereCast(center: Vector3, radius: number, direction: Vector3, distance: number, outHitResult: HitResult): boolean
|
||
|
||
// 完整参数版本
|
||
sphereCast(
|
||
center: Vector3,
|
||
radius: number,
|
||
direction: Vector3,
|
||
distance: number,
|
||
layerMask: Layer,
|
||
outHitResult?: HitResult
|
||
): boolean
|
||
```
|
||
|
||
### 使用示例
|
||
|
||
```typescript
|
||
// 示例1: 球形物体移动预测
|
||
const ballRadius = 0.5;
|
||
const ballPosition = new Vector3(-5, 2, 0);
|
||
const rollDirection = new Vector3(1, 0, 0);
|
||
const rollDistance = 8.0;
|
||
|
||
const rollHit = new HitResult();
|
||
if (physicsScene.sphereCast(ballPosition, ballRadius, rollDirection, rollDistance, rollHit)) {
|
||
console.log(`球会在距离 ${rollHit.distance} 处撞到 ${rollHit.entity.name}`);
|
||
}
|
||
```
|
||
|
||
## 胶囊投射 (capsuleCast)
|
||
|
||
胶囊投射沿指定方向投射一个胶囊形状,特别适合人形角色的路径检测。
|
||
|
||
### 函数重载
|
||
|
||
```typescript
|
||
// 基础检测
|
||
capsuleCast(center: Vector3, radius: number, height: number, direction: Vector3): boolean
|
||
|
||
// 获取命中信息
|
||
capsuleCast(center: Vector3, radius: number, height: number, direction: Vector3, outHitResult: HitResult): boolean
|
||
|
||
// 指定投射距离
|
||
capsuleCast(center: Vector3, radius: number, height: number, direction: Vector3, distance: number): boolean
|
||
|
||
// 指定距离并获取命中信息
|
||
capsuleCast(center: Vector3, radius: number, height: number, direction: Vector3, distance: number, outHitResult: HitResult): boolean
|
||
|
||
// 完整参数版本
|
||
capsuleCast(
|
||
center: Vector3,
|
||
radius: number,
|
||
height: number,
|
||
direction: Vector3,
|
||
orientation: Quaternion,
|
||
distance: number,
|
||
layerMask: Layer,
|
||
outHitResult?: HitResult
|
||
): boolean
|
||
```
|
||
|
||
### 使用示例
|
||
|
||
```typescript
|
||
// 示例1: 角色跳跃检测
|
||
const characterCenter = new Vector3(0, 1, 0);
|
||
const characterRadius = 0.5;
|
||
const characterHeight = 1.8;
|
||
const jumpDirection = new Vector3(0, 1, 0);
|
||
const jumpHeight = 2.0;
|
||
|
||
if (!physicsScene.capsuleCast(characterCenter, characterRadius, characterHeight, jumpDirection, jumpHeight)) {
|
||
// 头顶空间足够,可以跳跃
|
||
performJump();
|
||
}
|
||
|
||
// 示例2: 人形角色移动检测
|
||
const moveDirection = new Vector3(1, 0, 0);
|
||
const stepDistance = 1.0;
|
||
|
||
const moveHit = new HitResult();
|
||
if (physicsScene.capsuleCast(
|
||
characterCenter,
|
||
characterRadius,
|
||
characterHeight,
|
||
moveDirection,
|
||
stepDistance,
|
||
moveHit
|
||
)) {
|
||
console.log(`角色移动会在 ${moveHit.distance} 处碰到障碍物`);
|
||
// 可以实现滑动或其他阻挡响应
|
||
}
|
||
```
|
||
|
||
## 参数说明
|
||
|
||
### 通用参数
|
||
|
||
- **center** - 形状的中心位置(世界坐标)
|
||
- **direction** - 投射方向(必须为单位向量)
|
||
- **distance** - 投射距离(默认为 `Number.MAX_VALUE`)
|
||
- **layerMask** - 层遮罩,用于过滤特定层的碰撞器(默认为 `Layer.Everything`)
|
||
- **outHitResult** - 输出的命中结果信息(可选)
|
||
|
||
### 形状特定参数
|
||
|
||
- **halfExtents** (boxCast) - 盒子的半尺寸
|
||
- **radius** (sphereCast/capsuleCast) - 球体/胶囊的半径
|
||
- **height** (capsuleCast) - 胶囊的高度
|
||
- **orientation** (boxCast/capsuleCast) - 形状的旋转(默认为无旋转)
|
||
|
||
## 性能优化建议
|
||
|
||
1. **合理使用距离限制** - 指定合适的投射距离,避免不必要的远距离检测
|
||
2. **层遮罩过滤** - 使用 `layerMask` 只检测相关的碰撞器层
|
||
3. **重用 HitResult 对象** - 避免频繁创建新的 HitResult 实例
|
||
4. **选择合适的形状** - 根据实际需求选择最简单的形状类型
|
||
|
||
```typescript
|
||
// 性能优化示例
|
||
class PhysicsQuery {
|
||
private static readonly _hitResult = new HitResult();
|
||
private static readonly _playerLayerMask = Layer.Layer0 | Layer.Layer1;
|
||
|
||
static checkPlayerMovement(center: Vector3, direction: Vector3): boolean {
|
||
return scene.physics.capsuleCast(
|
||
center,
|
||
0.5, // 固定半径
|
||
1.8, // 固定高度
|
||
direction,
|
||
2.0, // 限制检测距离
|
||
this._playerLayerMask, // 只检测相关层
|
||
this._hitResult // 重用结果对象
|
||
);
|
||
}
|
||
}
|
||
```
|
||
|
||
## 注意事项
|
||
|
||
1. **方向向量规范化** - 确保 `direction` 参数是单位向量
|
||
2. **世界坐标系统** - 所有位置和方向都基于世界坐标系
|
||
3. **碰撞器要求** - 只有添加了[碰撞器组件](/docs/physics/collider/overview)的实体才能被检测到
|
||
|
||
## 与射线检测的区别
|
||
|
||
| 特性 | 射线检测 | 形状投射 |
|
||
|------|----------|----------|
|
||
| 检测精度 | 点精度 | 体积精度 |
|
||
| 性能消耗 | 低 | 中等 |
|
||
| 适用场景 | 点选、瞄准 | 移动预测、路径验证 |
|
||
|
||
形状投射提供了比射线检测更精确的阻挡信息,特别适合需要考虑物体体积的应用场景。结合合适的性能优化策略,可以在保证精度的同时维持良好的运行效率。
|