Files
esengine/thirdparty/rapier.js/src.ts/geometry/broad_phase.ts
YHH 63f006ab62 feat: 添加跨平台运行时、资产系统和UI适配功能 (#256)
* feat(platform-common): 添加WASM加载器和环境检测API

* feat(rapier2d): 新增Rapier2D WASM绑定包

* feat(physics-rapier2d): 添加跨平台WASM加载器

* feat(asset-system): 添加运行时资产目录和bundle格式

* feat(asset-system-editor): 新增编辑器资产管理包

* feat(editor-core): 添加构建系统和模块管理

* feat(editor-app): 重构浏览器预览使用import maps

* feat(platform-web): 添加BrowserRuntime和资产读取

* feat(engine): 添加材质系统和着色器管理

* feat(material): 新增材质系统和着色器编辑器

* feat(tilemap): 增强tilemap编辑器和动画系统

* feat(modules): 添加module.json配置

* feat(core): 添加module.json和类型定义更新

* chore: 更新依赖和构建配置

* refactor(plugins): 更新插件模板使用ModuleManifest

* chore: 添加第三方依赖库

* chore: 移除BehaviourTree-ai和ecs-astar子模块

* docs: 更新README和文档主题样式

* fix: 修复Rust文档测试和添加rapier2d WASM绑定

* fix(tilemap-editor): 修复画布高DPI屏幕分辨率适配问题

* feat(ui): 添加UI屏幕适配系统(CanvasScaler/SafeArea)

* fix(ecs-engine-bindgen): 添加缺失的ecs-framework-math依赖

* fix: 添加缺失的包依赖修复CI构建

* fix: 修复CodeQL检测到的代码问题

* fix: 修复构建错误和缺失依赖

* fix: 修复类型检查错误

* fix(material-system): 修复tsconfig配置支持TypeScript项目引用

* fix(editor-core): 修复Rollup构建配置添加tauri external

* fix: 修复CodeQL检测到的代码问题

* fix: 修复CodeQL检测到的代码问题
2025-12-03 22:15:22 +08:00

521 lines
19 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import {RawBroadPhase, RawRayColliderIntersection} from "../raw";
import {RigidBodyHandle, RigidBodySet} from "../dynamics";
import {ColliderSet} from "./collider_set";
import {Ray, RayColliderHit, RayColliderIntersection} from "./ray";
import {InteractionGroups} from "./interaction_groups";
import {ColliderHandle} from "./collider";
import {Rotation, RotationOps, Vector, VectorOps} from "../math";
import {Shape} from "./shape";
import {PointColliderProjection} from "./point";
import {ColliderShapeCastHit} from "./toi";
import {QueryFilterFlags} from "../pipeline";
import {NarrowPhase} from "./narrow_phase";
/**
* The broad-phase used for coarse collision-detection.
*
* To avoid leaking WASM resources, this MUST be freed manually with `broadPhase.free()`
* once you are done using it.
*/
export class BroadPhase {
raw: RawBroadPhase;
/**
* Release the WASM memory occupied by this broad-phase.
*/
public free() {
if (!!this.raw) {
this.raw.free();
}
this.raw = undefined;
}
constructor(raw?: RawBroadPhase) {
this.raw = raw || new RawBroadPhase();
}
/**
* Find the closest intersection between a ray and a set of collider.
*
* @param colliders - The set of colliders taking part in this pipeline.
* @param ray - The ray to cast.
* @param maxToi - The maximum time-of-impact that can be reported by this cast. This effectively
* limits the length of the ray to `ray.dir.norm() * maxToi`.
* @param solid - If `false` then the ray will attempt to hit the boundary of a shape, even if its
* origin already lies inside of a shape. In other terms, `true` implies that all shapes are plain,
* whereas `false` implies that all shapes are hollow for this ray-cast.
* @param groups - Used to filter the colliders that can or cannot be hit by the ray.
* @param filter - The callback to filter out which collider will be hit.
*/
public castRay(
narrowPhase: NarrowPhase,
bodies: RigidBodySet,
colliders: ColliderSet,
ray: Ray,
maxToi: number,
solid: boolean,
filterFlags?: QueryFilterFlags,
filterGroups?: InteractionGroups,
filterExcludeCollider?: ColliderHandle,
filterExcludeRigidBody?: RigidBodyHandle,
filterPredicate?: (collider: ColliderHandle) => boolean,
): RayColliderHit | null {
let rawOrig = VectorOps.intoRaw(ray.origin);
let rawDir = VectorOps.intoRaw(ray.dir);
let result = RayColliderHit.fromRaw(
colliders,
this.raw.castRay(
narrowPhase.raw,
bodies.raw,
colliders.raw,
rawOrig,
rawDir,
maxToi,
solid,
filterFlags,
filterGroups,
filterExcludeCollider,
filterExcludeRigidBody,
filterPredicate,
),
);
rawOrig.free();
rawDir.free();
return result;
}
/**
* Find the closest intersection between a ray and a set of collider.
*
* This also computes the normal at the hit point.
* @param colliders - The set of colliders taking part in this pipeline.
* @param ray - The ray to cast.
* @param maxToi - The maximum time-of-impact that can be reported by this cast. This effectively
* limits the length of the ray to `ray.dir.norm() * maxToi`.
* @param solid - If `false` then the ray will attempt to hit the boundary of a shape, even if its
* origin already lies inside of a shape. In other terms, `true` implies that all shapes are plain,
* whereas `false` implies that all shapes are hollow for this ray-cast.
* @param groups - Used to filter the colliders that can or cannot be hit by the ray.
*/
public castRayAndGetNormal(
narrowPhase: NarrowPhase,
bodies: RigidBodySet,
colliders: ColliderSet,
ray: Ray,
maxToi: number,
solid: boolean,
filterFlags?: QueryFilterFlags,
filterGroups?: InteractionGroups,
filterExcludeCollider?: ColliderHandle,
filterExcludeRigidBody?: RigidBodyHandle,
filterPredicate?: (collider: ColliderHandle) => boolean,
): RayColliderIntersection | null {
let rawOrig = VectorOps.intoRaw(ray.origin);
let rawDir = VectorOps.intoRaw(ray.dir);
let result = RayColliderIntersection.fromRaw(
colliders,
this.raw.castRayAndGetNormal(
narrowPhase.raw,
bodies.raw,
colliders.raw,
rawOrig,
rawDir,
maxToi,
solid,
filterFlags,
filterGroups,
filterExcludeCollider,
filterExcludeRigidBody,
filterPredicate,
),
);
rawOrig.free();
rawDir.free();
return result;
}
/**
* Cast a ray and collects all the intersections between a ray and the scene.
*
* @param colliders - The set of colliders taking part in this pipeline.
* @param ray - The ray to cast.
* @param maxToi - The maximum time-of-impact that can be reported by this cast. This effectively
* limits the length of the ray to `ray.dir.norm() * maxToi`.
* @param solid - If `false` then the ray will attempt to hit the boundary of a shape, even if its
* origin already lies inside of a shape. In other terms, `true` implies that all shapes are plain,
* whereas `false` implies that all shapes are hollow for this ray-cast.
* @param groups - Used to filter the colliders that can or cannot be hit by the ray.
* @param callback - The callback called once per hit (in no particular order) between a ray and a collider.
* If this callback returns `false`, then the cast will stop and no further hits will be detected/reported.
*/
public intersectionsWithRay(
narrowPhase: NarrowPhase,
bodies: RigidBodySet,
colliders: ColliderSet,
ray: Ray,
maxToi: number,
solid: boolean,
callback: (intersect: RayColliderIntersection) => boolean,
filterFlags?: QueryFilterFlags,
filterGroups?: InteractionGroups,
filterExcludeCollider?: ColliderHandle,
filterExcludeRigidBody?: RigidBodyHandle,
filterPredicate?: (collider: ColliderHandle) => boolean,
) {
let rawOrig = VectorOps.intoRaw(ray.origin);
let rawDir = VectorOps.intoRaw(ray.dir);
let rawCallback = (rawInter: RawRayColliderIntersection) => {
return callback(
RayColliderIntersection.fromRaw(colliders, rawInter),
);
};
this.raw.intersectionsWithRay(
narrowPhase.raw,
bodies.raw,
colliders.raw,
rawOrig,
rawDir,
maxToi,
solid,
rawCallback,
filterFlags,
filterGroups,
filterExcludeCollider,
filterExcludeRigidBody,
filterPredicate,
);
rawOrig.free();
rawDir.free();
}
/**
* Gets the handle of up to one collider intersecting the given shape.
*
* @param colliders - The set of colliders taking part in this pipeline.
* @param shapePos - The position of the shape used for the intersection test.
* @param shapeRot - The orientation of the shape used for the intersection test.
* @param shape - The shape used for the intersection test.
* @param groups - The bit groups and filter associated to the ray, in order to only
* hit the colliders with collision groups compatible with the ray's group.
*/
public intersectionWithShape(
narrowPhase: NarrowPhase,
bodies: RigidBodySet,
colliders: ColliderSet,
shapePos: Vector,
shapeRot: Rotation,
shape: Shape,
filterFlags?: QueryFilterFlags,
filterGroups?: InteractionGroups,
filterExcludeCollider?: ColliderHandle,
filterExcludeRigidBody?: RigidBodyHandle,
filterPredicate?: (collider: ColliderHandle) => boolean,
): ColliderHandle | null {
let rawPos = VectorOps.intoRaw(shapePos);
let rawRot = RotationOps.intoRaw(shapeRot);
let rawShape = shape.intoRaw();
let result = this.raw.intersectionWithShape(
narrowPhase.raw,
bodies.raw,
colliders.raw,
rawPos,
rawRot,
rawShape,
filterFlags,
filterGroups,
filterExcludeCollider,
filterExcludeRigidBody,
filterPredicate,
);
rawPos.free();
rawRot.free();
rawShape.free();
return result;
}
/**
* Find the projection of a point on the closest collider.
*
* @param colliders - The set of colliders taking part in this pipeline.
* @param point - The point to project.
* @param solid - If this is set to `true` then the collider shapes are considered to
* be plain (if the point is located inside of a plain shape, its projection is the point
* itself). If it is set to `false` the collider shapes are considered to be hollow
* (if the point is located inside of an hollow shape, it is projected on the shape's
* boundary).
* @param groups - The bit groups and filter associated to the point to project, in order to only
* project on colliders with collision groups compatible with the ray's group.
*/
public projectPoint(
narrowPhase: NarrowPhase,
bodies: RigidBodySet,
colliders: ColliderSet,
point: Vector,
solid: boolean,
filterFlags?: QueryFilterFlags,
filterGroups?: InteractionGroups,
filterExcludeCollider?: ColliderHandle,
filterExcludeRigidBody?: RigidBodyHandle,
filterPredicate?: (collider: ColliderHandle) => boolean,
): PointColliderProjection | null {
let rawPoint = VectorOps.intoRaw(point);
let result = PointColliderProjection.fromRaw(
colliders,
this.raw.projectPoint(
narrowPhase.raw,
bodies.raw,
colliders.raw,
rawPoint,
solid,
filterFlags,
filterGroups,
filterExcludeCollider,
filterExcludeRigidBody,
filterPredicate,
),
);
rawPoint.free();
return result;
}
/**
* Find the projection of a point on the closest collider.
*
* @param colliders - The set of colliders taking part in this pipeline.
* @param point - The point to project.
* @param groups - The bit groups and filter associated to the point to project, in order to only
* project on colliders with collision groups compatible with the ray's group.
*/
public projectPointAndGetFeature(
narrowPhase: NarrowPhase,
bodies: RigidBodySet,
colliders: ColliderSet,
point: Vector,
filterFlags?: QueryFilterFlags,
filterGroups?: InteractionGroups,
filterExcludeCollider?: ColliderHandle,
filterExcludeRigidBody?: RigidBodyHandle,
filterPredicate?: (collider: ColliderHandle) => boolean,
): PointColliderProjection | null {
let rawPoint = VectorOps.intoRaw(point);
let result = PointColliderProjection.fromRaw(
colliders,
this.raw.projectPointAndGetFeature(
narrowPhase.raw,
bodies.raw,
colliders.raw,
rawPoint,
filterFlags,
filterGroups,
filterExcludeCollider,
filterExcludeRigidBody,
filterPredicate,
),
);
rawPoint.free();
return result;
}
/**
* Find all the colliders containing the given point.
*
* @param colliders - The set of colliders taking part in this pipeline.
* @param point - The point used for the containment test.
* @param groups - The bit groups and filter associated to the point to test, in order to only
* test on colliders with collision groups compatible with the ray's group.
* @param callback - A function called with the handles of each collider with a shape
* containing the `point`.
*/
public intersectionsWithPoint(
narrowPhase: NarrowPhase,
bodies: RigidBodySet,
colliders: ColliderSet,
point: Vector,
callback: (handle: ColliderHandle) => boolean,
filterFlags?: QueryFilterFlags,
filterGroups?: InteractionGroups,
filterExcludeCollider?: ColliderHandle,
filterExcludeRigidBody?: RigidBodyHandle,
filterPredicate?: (collider: ColliderHandle) => boolean,
) {
let rawPoint = VectorOps.intoRaw(point);
this.raw.intersectionsWithPoint(
narrowPhase.raw,
bodies.raw,
colliders.raw,
rawPoint,
callback,
filterFlags,
filterGroups,
filterExcludeCollider,
filterExcludeRigidBody,
filterPredicate,
);
rawPoint.free();
}
/**
* Casts a shape at a constant linear velocity and retrieve the first collider it hits.
* This is similar to ray-casting except that we are casting a whole shape instead of
* just a point (the ray origin).
*
* @param colliders - The set of colliders taking part in this pipeline.
* @param shapePos - The initial position of the shape to cast.
* @param shapeRot - The initial rotation of the shape to cast.
* @param shapeVel - The constant velocity of the shape to cast (i.e. the cast direction).
* @param shape - The shape to cast.
* @param targetDistance If the shape moves closer to this distance from a collider, a hit
* will be returned.
* @param maxToi - The maximum time-of-impact that can be reported by this cast. This effectively
* limits the distance traveled by the shape to `shapeVel.norm() * maxToi`.
* @param stopAtPenetration - If set to `false`, the linear shape-cast wont immediately stop if
* the shape is penetrating another shape at its starting point **and** its trajectory is such
* that its on a path to exit that penetration state.
* @param groups - The bit groups and filter associated to the shape to cast, in order to only
* test on colliders with collision groups compatible with this group.
*/
public castShape(
narrowPhase: NarrowPhase,
bodies: RigidBodySet,
colliders: ColliderSet,
shapePos: Vector,
shapeRot: Rotation,
shapeVel: Vector,
shape: Shape,
targetDistance: number,
maxToi: number,
stopAtPenetration: boolean,
filterFlags?: QueryFilterFlags,
filterGroups?: InteractionGroups,
filterExcludeCollider?: ColliderHandle,
filterExcludeRigidBody?: RigidBodyHandle,
filterPredicate?: (collider: ColliderHandle) => boolean,
): ColliderShapeCastHit | null {
let rawPos = VectorOps.intoRaw(shapePos);
let rawRot = RotationOps.intoRaw(shapeRot);
let rawVel = VectorOps.intoRaw(shapeVel);
let rawShape = shape.intoRaw();
let result = ColliderShapeCastHit.fromRaw(
colliders,
this.raw.castShape(
narrowPhase.raw,
bodies.raw,
colliders.raw,
rawPos,
rawRot,
rawVel,
rawShape,
targetDistance,
maxToi,
stopAtPenetration,
filterFlags,
filterGroups,
filterExcludeCollider,
filterExcludeRigidBody,
filterPredicate,
),
);
rawPos.free();
rawRot.free();
rawVel.free();
rawShape.free();
return result;
}
/**
* Retrieve all the colliders intersecting the given shape.
*
* @param colliders - The set of colliders taking part in this pipeline.
* @param shapePos - The position of the shape to test.
* @param shapeRot - The orientation of the shape to test.
* @param shape - The shape to test.
* @param groups - The bit groups and filter associated to the shape to test, in order to only
* test on colliders with collision groups compatible with this group.
* @param callback - A function called with the handles of each collider intersecting the `shape`.
*/
public intersectionsWithShape(
narrowPhase: NarrowPhase,
bodies: RigidBodySet,
colliders: ColliderSet,
shapePos: Vector,
shapeRot: Rotation,
shape: Shape,
callback: (handle: ColliderHandle) => boolean,
filterFlags?: QueryFilterFlags,
filterGroups?: InteractionGroups,
filterExcludeCollider?: ColliderHandle,
filterExcludeRigidBody?: RigidBodyHandle,
filterPredicate?: (collider: ColliderHandle) => boolean,
) {
let rawPos = VectorOps.intoRaw(shapePos);
let rawRot = RotationOps.intoRaw(shapeRot);
let rawShape = shape.intoRaw();
this.raw.intersectionsWithShape(
narrowPhase.raw,
bodies.raw,
colliders.raw,
rawPos,
rawRot,
rawShape,
callback,
filterFlags,
filterGroups,
filterExcludeCollider,
filterExcludeRigidBody,
filterPredicate,
);
rawPos.free();
rawRot.free();
rawShape.free();
}
/**
* Finds the handles of all the colliders with an AABB intersecting the given AABB.
*
* @param aabbCenter - The center of the AABB to test.
* @param aabbHalfExtents - The half-extents of the AABB to test.
* @param callback - The callback that will be called with the handles of all the colliders
* currently intersecting the given AABB.
*/
public collidersWithAabbIntersectingAabb(
narrowPhase: NarrowPhase,
bodies: RigidBodySet,
colliders: ColliderSet,
aabbCenter: Vector,
aabbHalfExtents: Vector,
callback: (handle: ColliderHandle) => boolean,
) {
let rawCenter = VectorOps.intoRaw(aabbCenter);
let rawHalfExtents = VectorOps.intoRaw(aabbHalfExtents);
this.raw.collidersWithAabbIntersectingAabb(
narrowPhase.raw,
bodies.raw,
colliders.raw,
rawCenter,
rawHalfExtents,
callback,
);
rawCenter.free();
rawHalfExtents.free();
}
}