Files
西风逍遥游andCursor Agent d603219164 feat: complete 2D/3D pick, overlap, and collision query APIs (#11)
Add Math geometry tests for 2D/3D picking and overlaps, Physics
rayCast/queryAABB/testPoint, and Camera2D/3D screen pick helpers,
with script bindings, docs, and unit tests.

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-08-10 07:42:09 +08:00

106 lines
5.6 KiB
Markdown
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.
# 数学模块
**脚本入口:** `eve.Math()`
提供向量、矩阵、几何、噪声、随机数、插值和缓动工具。2D/3D 对象的**点选、重叠与射线检测**也放在本模块(轻量几何测试);带刚体/接触响应的模拟见 [Physics](physics.md),屏幕坐标换算见 [Graphics](graphics.md) 的 Camera2D/Camera3D。
## 基本用法
```squirrel
local math = eve.Math();
math.setRandomSeed(42);
local p = math.newVec2(10, 20);
local n = math.noise2(p.getX(), p.getY());
```
## 对象关系与调用时机
`Math` 是算法与随机状态入口;Vec2/Vec3/Mat4 是值对象;noise、random、ease、Bezier 和几何测试由模块提供。需要确定性的系统应拥有独立且明确 seed 的 Math 状态。
## 目标导向指南
### 可复现随机地图
生成前 `setRandomSeed(seed)`,所有随机选择使用同一 Math 实例;存档只需记录 seed 和玩家改动。不要用时间 seed 做需要联网同步的逻辑。
### 平滑移动和程序噪声
用 lerp/smoothstep/ease 做相机与 UI 插值;`noise2()` / fractal noise 适合高度图,输入坐标乘 frequency 控制尺度。Vec/Mat 对象用于变换组合,热点循环避免反复分配临时对象。
### 2D 点击拾取与重叠
鼠标/触摸先经 `Camera2D.screenToWorld*` 得到世界坐标,再用:
- `pointInCircle` / `pointInRect` — 点选精灵或按钮
- `circlesOverlap` / `rectsOverlap` / `circleRectOverlap` — 无物理的碰撞/触发
- `raycastCircle2` / `raycastRect2` — 子弹、视线;命中点 = `o + t * d`,未命中返回 `-1`
- `segmentsIntersect` — 线段相交(弹道、边缘)
```squirrel
local mx = mouse.getX();
local my = mouse.getY();
local wx = cam2d.screenToWorldX(mx, my, gfx.getWidth(), gfx.getHeight());
local wy = cam2d.screenToWorldY(mx, my, gfx.getWidth(), gfx.getHeight());
if (math.pointInRect(wx, wy, spriteX, spriteY, spriteW, spriteH)) {
// picked
}
```
### 3D 射线拾取
`Camera3D.screenToRay` 生成世界射线后,用 `raycastSphere` / `raycastBox` / `raycastPlane` 测距;`t >= 0` 表示命中。多个候选取最小 `t`。
```squirrel
cam3d.screenToRay(mouse.getX(), mouse.getY(), gfx.getWidth(), gfx.getHeight());
local ox = cam3d.getScreenRayOriginX();
local oy = cam3d.getScreenRayOriginY();
local oz = cam3d.getScreenRayOriginZ();
local dx = cam3d.getScreenRayDirX();
local dy = cam3d.getScreenRayDirY();
local dz = cam3d.getScreenRayDirZ();
local t = math.raycastSphere(ox, oy, oz, dx, dy, dz, cx, cy, cz, radius);
if (t >= 0) {
local hx = ox + dx * t;
local hy = oy + dy * t;
local hz = oz + dz * t;
}
```
## 常见问题
- 客户端各自用时间 seed,造成联机状态分叉。
- 度和弧度混用。
- 未归一化方向向量就用于速度或点积判断。
- 射线 API 的 `t` 是参数:`hit = origin + t * dir`;`dir` 不必单位化,线段检测时用 `dir = B - A` 并要求 `t ∈ [0,1]`。
- 把 Math 几何测试当成刚体物理:需要接触事件、摩擦或传感器时用 Physics。
## API 快查
下列方法名来自当前 Squirrel 绑定;同一模块创建的辅助对象(例如 `World`、`Body`、`Source`)的方法也列在这里。
- `add()`、`angle()`、`angle2()`、`angleBetween2()`、`approach()`、`bezierCubic()`、`bezierCubic2X()`、`bezierCubic2Y()`
- `bezierQuadratic()`、`bezierQuadratic2X()`、`bezierQuadratic2Y()`、`bias()`、`bilinear()`、`boxesOverlap()`、`cartesianAngle()`
- `cartesianRadius()`、`circleRectOverlap()`、`circlesOverlap()`、`clamp()`、`clone()`、`closestPointOnSegment2X()`、`closestPointOnSegment2Y()`、`closestPointOnSegment3X()`
- `closestPointOnSegment3Y()`、`closestPointOnSegment3Z()`、`cross()`、`cross2()`、`degToRad()`、`distance2()`、`distance3()`、`distanceTo()`
- `dot()`、`dot2()`、`dot3()`、`ease()`、`fbm2()`、`fbm3()`、`fract()`、`gain()`
- `get()`、`getName()`、`getRandomSeed()`、`getX()`、`getY()`、`getZ()`、`hash1()`、`hash2()`
- `hash3()`、`identity()`、`inverseLerp()`、`length()`、`length2()`、`length3()`、`lengthSquared()`、`lerp()`
- `lerpAngle()`、`lerpTo()`、`multiplied()`、`multiply()`、`newMat4()`、`newMat4RotationZ()`、`newMat4Scale()`、`newMat4Translation()`
- `newVec2()`、`newVec3()`、`noise1()`、`noise2()`、`noise3()`、`normalize()`、`normalize2X()`、`normalize2Y()`
- `normalize3X()`、`normalize3Y()`、`normalize3Z()`、`normalized()`、`perlin2()`、`perlin3()`、`pingPong()`、`pointInBox()`
- `pointInCircle()`、`pointInRect()`、`pointInSphere()`、`polarX()`、`polarY()`、`quantize()`、`radToDeg()`、`random()`
- `randomGaussian()`、`randomInt()`、`randomRange()`、`raycastBox()`、`raycastCircle2()`、`raycastPlane()`、`raycastRect2()`、`raycastSphere()`
- `rectsOverlap()`、`remap()`、`ridged2()`、`ridged3()`、`rotate2X()`、`rotate2Y()`、`rotateX()`、`rotateY()`
- `rotateZ()`、`scale()`、`segmentsIntersect()`、`set()`、`setRandomSeed()`、`setRandomSeedFromTime()`、`setX()`、`setY()`
- `setZ()`、`sign()`、`smootherstep()`、`smoothstep()`、`snap()`、`spheresOverlap()`、`step()`、`sub()`
- `transformPoint2()`、`transformVec3()`、`translate()`、`turbulence2()`、`voronoi2()`、`voronoiEdge2()`、`warpNoise2()`、`wrap()`
## 使用要点
- 模块对象和它创建的资源对象应保存在全局或实体状态中,不要在每帧重复创建。
- 带 `update(dt)` 的系统应在 `eve_update` 调用;绘制方法应在 `eve_render` 调用。
- 参数约束、默认值和返回类型以对应模块头文件及 `addFunc` 绑定为准;本文 API 快查与当前源码同步生成。
**源码:** [`src/modules/math/`](../../../src/modules/math/)
**相关测试:** 在 [`test/`](../../../test/) 中搜索 `math`。