# 抓大鹅运行态 3D 几何体实验 2026-05-02 ## 1. 实验目标 本轮只验证抓大鹅运行态把可消除物从 2D 纯色几何图案切换为 3D 几何体后的可读性、点击手感和堆叠碰撞观感。 3D 表现层必须满足: 1. 圆形图案映射为球体。 2. 方形图案映射为方块。 3. 三角形、菱形、五角星、六边形、胶囊、心形、梯形、平行四边形等现有视觉键映射为近似 3D 几何体。 4. 物体在圆形空间内保持边界约束,并使用物理模拟产生轻微碰撞、堆叠、晃动效果。 5. 点击、备选栏、消除、胜负判定仍使用当前后端权威快照与前端即时反馈协议,不把规则真相迁到前端。 ## 2. 回退要求 这是一次可取消实验,不替换现有 2D 方案。 1. 现有 `Match3DVisualIcon`、`Match3DToken` 和托盘 2D 图案渲染代码必须保留。 2. 新增 3D 表现层只作为运行态棋盘的可选渲染分支。 3. 当浏览器不支持 WebGL、3D 依赖加载失败或实验开关关闭时,运行态必须自动回到现有 2D 图案表现。 4. 3D 模式下,托盘直接复用场内同一套程序化 3D 模型,以固定斜 `45` 度识别视角展示已选物品;托盘内物品不进入物理世界,不参与碰撞。WebGL 不可用或实验回退时,托盘继续使用当前 2D 图标。 ## 3. 工程落点 本轮只改前端表现层: ```text src/components/match3d-runtime/Match3DPhysicsBoard.tsx src/components/match3d-runtime/Match3DRuntimeShell.tsx src/components/match3d-runtime/Match3DRuntimeShell.test.tsx src/components/match3d-runtime/match3dRuntimePresentation.ts src/components/match3d-runtime/match3dVisualAssets.tsx ``` 新增依赖: ```text three cannon-es @types/three ``` 3D 棋盘默认启用;需要快速回到当前 2D demo 表现时,在运行态 URL 上追加任一参数: ```text ?match3dRender=2d ?match3d3d=off ``` 3D 分支只读取后端快照中的物品坐标、层级、可点击状态和视觉键。物理碰撞、轻微堆叠和几何体姿态只作为前端表现层,不改变消除规则、备选栏规则、胜负判定或最终权威快照。 `match3dVisualAssets.tsx` 保留 2D 纯色几何图案映射,运行态托盘在 3D 模式下通过 `Match3DTrayPreviewBoard` 使用单个共享 WebGL 预览层复用 `createMatch3DItemMesh` 生成同款 3D 模型,不能为每个托盘格单独创建 `WebGLRenderer`。托盘预览层必须按实际容器宽高更新正交相机,并把每个模型放入独立 pivot 后再沿相机屏幕横轴定位到对应格子中心;托盘预览不能把所有模型统一缩放到同一外观尺寸,必须保留场内相对尺寸差异,否则会让点击后入槽的模型和场内物件对应关系失真。WebGL 不可用或 2D 回退时继续使用该 2D 图标;`match3dRuntimePresentation.ts` 收口显示层坐标和状态兼容,避免异常旧坐标把 2D 或 3D 物体推到圆形边界外。 ## 4. 验收口径 1. `/match3d` 能打开并默认看到 3D 几何体棋盘。 2. 3D 几何体保持在圆形区域内,不被圆形边界裁切到不可点。 3. 物体进入场景后有轻微物理碰撞和堆叠稳定过程。 4. 点击 3D 物体后仍执行原有乐观入槽、后端确认、三消反馈和结算。 5. 被取出的 3D 物体必须立即从棋盘物理世界移除;备选栏展示的是无碰撞、固定角度的独立预览模型,不允许继续受场内碰撞、重力或堆叠影响。 6. 托盘 3D 预览必须共享一个 renderer,避免多个 WebGL 上下文导致中心棋盘上下文被浏览器回收;中心棋盘监听 `webglcontextlost`,丢失时自动回退 2D 表现,禁止出现模型不可见但仍可点击的状态。 7. 单元测试仍覆盖 2D 回退图案,确保回退路径没有被删除。 8. 390px 移动端与桌面端均不能出现横向溢出,顶部状态、圆形棋盘和 7 格备选栏都要完整可见。 ## 5. 锅型容器优化 2026-05-02 追加一轮 3D 表现优化,把运行态圆形空间明确解释为一口有固定深度和确定边界的锅。 编码口径: 1. 相机改为俯视角,玩家优先看到锅内物体的平面分布、遮挡关系和向上堆叠。 2. 3D 场景里的圆形区域拆成锅底、锅壁和锅沿三层视觉结构,锅壁有固定高度,锅沿明确标出边界。 3. 物理世界使用同一个锅内半径作为水平活动边界,所有可消除物体的初始位置和运行中位置都必须被约束在圆形锅内。 4. 物体受到重力后只允许在锅内碰撞、滑动、翻滚和向上堆叠,不能因为碰撞或初始坐标散落到圆形区域外。 5. 该优化仍只属于前端 3D 表现层,不改变后端运行态坐标、点击权威判定、备选栏、消除和胜负规则。 ## 6. 中心引力优化 2026-05-02 追加中心引力,用来解决高消除次数下 3D 物体过于松散、贴边后被圆形场地裁切的问题。体验后发现默认向心力会让模型过度挤压成团,因此当前先关闭默认引力,只保留代码开关,后续如需再尝试可重新调参。 编码口径: 1. 中心引力默认系数为 `0`,默认不对物理 body 施加水平向心力。 2. 引力只作用在 X/Z 平面,不改变垂直重力,物体仍会自然落到锅底或堆叠在其他物体上。 3. 引力在越靠近锅边时越明显,避免大量物体碰撞后形成稀疏外环;靠近中心时力度收敛,避免所有物体被吸成单点。 4. 锅内活动边界继续作为硬约束;高数量物体应被锅边挡住并向上堆叠,不允许散落到圆形场地外。 5. `/match3d?clearCount=100` 可作为本地直达压力测试入口,用于验证 300 个物体时仍在锅内聚拢。 ## 7. 正交俯视与真实场地边界 2026-05-02 针对高堆叠时 3D 物体被 DOM 圆形裁切的问题,明确中心圆形区域不是裁切蒙版,而是游戏实际游玩场地。 编码口径: 1. 3D 棋盘使用正交俯视相机,避免高处物体因为透视放大而投影到圆形场地外。 2. 圆形场地的内圈圆环对应 3D 世界里的锅内空气墙,物体范围由物理约束控制,不再依赖 DOM `overflow-hidden` 裁切。 3. 外层圆形 UI 只负责显示锅沿和场地外观,不能把物体裁成半截;如果物体看起来越界,优先修正相机、物理半径和空气墙。 4. 高数量压力测试以 `/match3d?clearCount=100` 为基准,物体可以在场地内向上堆叠,但不能被圆形边缘压住或切掉。 ## 8. 类型数量与样式池历史口径 2026-05-03 曾调整消除物类型生成规则,解决 3D 关卡中可消除物类型和样式过少的问题。该节为历史口径,后续实际实现以第 11 节 25 个积木件资源池为准。 编码口径: 1. 历史版本曾使用 20 类形状颜色组合。 2. 当前版本已替换为 25 个积木件,旧 20 类上限不再作为编码依据。 3. 3D 与 2D 回退仍共用视觉键映射,新增样式不能破坏 `?match3dRender=2d` 回退路径。 ## 9. 特殊形状 3D 可读性修正 2026-05-03 针对 20 组关卡中看不到十字、圆环、盾形、闪电、月牙、箭头等新形状的问题,补充 3D 几何体渲染口径。 编码口径: 1. 数据层仍使用 `visualKey` 决定类型,不新增贴图素材或文本标识。 2. 十字、心形、星形、圆环、盾形、闪电、月牙、箭头、V 形等特殊形状不能继续使用普通盒子、球体或锥体代理,必须生成俯视角可辨认的 3D 轮廓。 3. 特殊形状使用 Three.js 程序化轮廓挤出生成,保持当前 3D 实验可快速回退,不影响现有 2D 图案分支。 4. 特殊形状的物理碰撞可以继续使用近似碰撞体,但显示网格需要固定为俯视可读姿态,避免落地翻滚后又变成长方块或普通三角体。 5. 当前特殊形状已被 25 个积木件资源池替换;不能为了让玩家开局肉眼看到全部类型而改动初始层级、物理堆叠、遮挡、边界或可点击规则。 ## 10. 15 组中档局面的类型唯一性修正 2026-05-03 针对 `clearCount=15` 时可消除物类型不足 15 种的问题,补充中档局面的规则验收口径。 编码口径: 1. `clearCount=15` 时,运行态数据中必须生成 `15` 种不同 `itemTypeId`,且首个 `15` 个 `visualKey` 必须分别对应不同几何形状。 2. 每种 `itemTypeId` 在 `clearCount=15` 时只对应 1 次消除目标,即恰好生成 `3` 件物体;同一种视觉模型在同局中不应出现超过 3 件。 3. 不为了展示 15 种而修改初始层级、物理堆叠、遮挡、边界或可点击规则;被盖住、堆叠和局部不可见是正常玩法效果。 4. 当前版本已改为第 11 节的 `itemTypeCount = clearCount <= 25 ? clearCount : 25` 规则。 ## 11. 25 个积木件资源池替换 2026-05-03 根据新的参考图,把可消除物体替换为 25 个积木件类型,并调整本局类型抽取规则。 编码口径: 1. 默认 `visualKey` 资源池改为 25 个积木件,覆盖长条、短条、2x2、2x3、2x4、1x1、光板、斜坡、圆柱、透明圆环、拱门和锥形件等差异化模型。 2. 前端 3D 表现继续使用 Three.js 程序化几何体生成,不引入外部贴图或 GLB;托盘和 2D 回退继续使用同一批 `visualKey` 的简化图标。 3. `clearCount <= 25` 时,本局从 25 个类型中按确定性随机顺序抽取 `clearCount` 种类型,不允许同局刷新重复类型。 4. `clearCount > 25` 时,本局最多使用 25 种类型,额外消除组在这 25 种中轮转复用;每种类型最终数量仍必须是 3 的倍数。 5. 该随机抽取只决定本局使用哪些类型和使用顺序,不改变物理堆叠、遮挡、边界、可点击判定、备选栏和胜负规则。 6. 前端本地试玩、创作后试玩和后端权威运行态必须使用同一套 `itemTypeCount = clearCount <= 25 ? clearCount : 25` 口径。 ## 12. 五档体积规则 2026-05-03 追加可消除物模型大小规则,把每局可消除物按五档相对体积分配。 编码口径: 1. M 型作为标准体积 `1.00`。 2. XL 型相对体积范围为 `1.60~2.30`,占本局可消除类型数的 `20%`。 3. L 型相对体积范围为 `1.25~1.60`,占本局可消除类型数的 `30%`。 4. M 型相对体积固定为 `1.00`,占本局可消除类型数的 `30%`。 5. XS 型相对体积范围为 `0.65~0.85`,占本局可消除类型数的 `15%`。 6. S 型相对体积范围为 `0.35~0.50`,占本局可消除类型数的 `5%`。 7. 本局使用类型数仍按第 11 节计算,即 `clearCount <= 25 ? clearCount : 25`。比例遇到非整数时按最大余数补齐,确保五档数量之和等于本局使用类型数。 8. 体积档位分配绑定到本局选中的 `visualKey`,同一局内同一个颜色和造型只能有一个尺寸档位和一个半径;当 `clearCount > 25` 轮转复用类型时,复用的同一 `visualKey` 继续沿用同一尺寸。 9. 前端本地试玩、创作后试玩和后端权威运行态必须使用同一套五档体积分配口径。 ## 13. 可点击物整体显示倍率 2026-05-04 追加一轮点击手感优化,解决当前玩家点击可消除物偏困难的问题。 编码口径: 1. 运行态表现层使用 `MATCH3D_RENDER_ITEM_SCALE = 2`,把后端快照中的 `item.radius` 统一乘 `2` 后再进入显示层坐标收束。 2. 该倍率只影响前端 2D 回退图标、3D 场内模型、碰撞体、射线点击命中区域和托盘 3D 预览测量。 3. 五档体积规则、每局类型数量、每种物品的唯一尺寸关系、后端权威快照和消除判定不做变化;所有物体之间的相对大小比例保持不变。 4. 放大后的物体仍必须通过圆形场地显示层收束和 3D 锅内空气墙约束,不允许重新依赖 DOM 圆形裁切。 5. 2026-05-04 追加修正:碰撞体必须和当前视觉模型使用同一套尺寸公式。长条、光板、斜坡、圆柱、圆环、拱门和锥形件不能再只按 `shape + radius` 粗略生成统一碰撞体;不得借此调整整体显示倍率、点击倍率、锅体尺寸或物理步进。 ## 14. 两位数消除局的点击命中与旧模型复用修正 2026-05-05 针对 `clearCount >= 10` 时出现“点击到的 3D 模型和下方备选栏模型不一致”的问题,补充运行态复用口径。 编码口径: 1. 运行态 3D 棋盘的物理条目不能只按 `itemInstanceId` 复用,还必须结合 `runId`、`itemTypeId`、`visualKey`、`radius` 和 `layer` 生成当前渲染签名。 2. 当同一个 `itemInstanceId` 出现在新的 run 快照里,但渲染签名已经变化时,旧 mesh 和 body 必须先销毁,再按当前快照重建。 3. 这条修正只针对前端 3D 表现层,不改变后端权威快照、点击判定、备选栏规则和三消规则。 4. 底部备选栏预览继续沿用按当前 run 快照重建的视觉键,不允许把上一局的旧 3D 资源误复用到新一局。 ## 15. 备选栏 3D 模型可读性优化 2026-05-05 针对备选栏中的 3D 模型偏小、部分积木件难以辨认的问题,补充 UI 预览层展示口径。 编码口径: 1. 备选栏 3D 预览可以使用比场内更紧凑的显示尺度,让模型在单格 UI 中占用更大可读面积。 2. 托盘相机和模型姿态只服务 UI 识别;当前采用偏强的俯视 `3/4` 立体角,并通过更明显的光照对比突出顶面与侧面差异,避免退化成纯平面旋转。 3. 该调整不能改变中心场地 3D 模型的物理姿态、碰撞体、点击判定和后端权威快照。 4. 托盘仍使用共享 `WebGLRenderer`,继续按当前 `visualKey` 和尺寸关系生成同款模型;不得新增每格独立 renderer。 5. 托盘缩放不能继续只按本局最大模型统一压缩所有物体;小尺寸模型需要保留最低可读显示尺寸,但仍不能改动场内真实尺寸、碰撞尺寸和后端权威尺寸。 6. 备选栏单格高度可大于宽度,优先保证局内 3D 预览的识别面积;不得为了适配旧正方形格子把模型再次压小。 ## 16. 中心场地隐藏纵深与动态上顶 2026-05-05 针对中心场地高数量局面穿模严重、消除后中下层物体长期陷在深处的问题,追加隐藏纵深与动态上顶表现修正。 编码口径: 1. 该纵深只存在于 3D 物理表现层,不修改锅体图案、锅壁模型、托盘表现、后端快照、点击权威判定、消除和胜负规则。 2. 物体生成高度不再使用固定极小层级步长,而是按本局总物体数计算一个隐藏初始纵深;物体总量越大,初始逻辑纵深越深,用来减少大量放大后模型被挤进同一高度区间导致的穿模。 3. 当前剩余场内物体数会动态缩短可用纵深;随着玩家持续消除,下层物体的目标高度逐步上移,表现为中下层物体陆续向上顶到表面层。 4. 动态上顶只通过向上托举力和目标高度调整完成,不增加中心引力,不修改水平约束半径,不改变碰撞体尺寸倍率。 5. 表面层高度保持稳定,避免越消除越显得物体掉进深处或视觉尺寸异常变小。 ## 17. 高数量局面物理稳定与动态锅容量 2026-05-06 继续按方案 C 和方案 D 优化 `clearCount=100` 等高数量局面的稳定性。 方案 C 编码口径: 1. 只调整 3D 表现层的物理稳定参数,包括求解迭代次数、接触摩擦、接触弹性、线性阻尼、角阻尼、睡眠阈值和速度上限。 2. 物体数量越大,物理世界越偏向高摩擦、低弹性和更强阻尼,减少大量物体同时生成后的持续弹跳、穿插和边界挤压。 3. 速度保护只限制极端水平速度和垂直速度,不改物体位置生成规则、点击判定、备选栏、消除和胜负规则。 方案 D 编码口径: 1. 隐藏锅容量的纵深按本局总物体数,也就是用户配置的消除次数乘 `3` 后动态计算;消除次数越大,锅内容量纵深越深。 2. 动态纵深只影响 3D 物理层的生成高度、目标层高度和消除后的上顶回补;锅底、锅壁、锅沿和 DOM 场地外观不随纵深变化。 3. 高数量局面需要降低单层容量,让更多物体分散到纵向层级中,避免 `300` 个物体被压进少量高度层。 4. 随着消除进度推进,当前可用纵深继续按剩余物体数收缩,确保下层物体逐步向表面回补,保持中心场地表层稳定可见。 5. 本节不改变中心引力默认值,不改水平活动半径,不改碰撞体与视觉模型的尺寸一致性规则。 ## 18. 原型入场节奏与创建限流 2026-05-07 根据原型视频补充创建过程优化。原型不是在同一帧把全部物体摆进容器,而是先短暂空场,再用连续小批量把物体投放到容器中,批与批之间留出自然沉降时间,最后再进入可操作局面。 编码口径: 1. 该优化只作用于前端 3D 表现层的物理 body 创建节奏,不改变后端快照、消除目标数量、点击权威判定、备选栏、三消和胜负规则。 2. `totalItemCount < 30` 时保留较快创建节奏;`30 <= totalItemCount <= 50` 进入中速波次投放,降低每波数量并增加波次沉降窗口,避免最后一层物体压进尚未稳定的表层堆叠。 3. `totalItemCount > 50` 后进入更强限流投放,单帧创建数量下降,避免同一帧把过多碰撞体塞入物理世界。 4. 随着总物体数增加,投放初始等待、层级间隔和同层错峰间隔都要逐步变长,模拟原型中“持续落入、短暂沉降、继续补入”的节奏。 5. `clearCount=100` 对应 `300` 个物体时,投放节奏应接近连续数秒完成,而不是在一秒左右完成全量创建。 6. 该节不允许通过缩小碰撞体、扩大锅半径、开启中心引力或修改模型尺寸来掩盖穿模;如果后续仍需调整,只继续围绕创建节拍和物理沉降窗口处理。 ## 19. 生成高度避让已有堆叠 2026-05-07 继续按方案 2 优化 `30` 件左右局面最后一层或最后一波物体仍会穿进已有堆叠的问题。 编码口径: 1. 该优化只作用于前端 3D 表现层的新物体创建高度,不改变后端快照、物品数量、模型尺寸、碰撞体尺寸、锅半径、点击判定、备选栏、三消和胜负规则。 2. 新物体进入物理世界前,先根据当前同一水平区域附近已有物体的碰撞体顶部高度,计算一个不低于原计划高度的生成高度。 3. 只有水平外接半径发生重叠的已有物体会影响本次生成高度;远处物体不能把新物体整体抬高,避免破坏原有随机洒落和分层节奏。 4. 该避让只解决“直接创建在已有模型内部”的初始穿插,后续沉降、翻滚、堆叠仍交给 cannon-es 物理模拟。 5. 本节不允许额外引入中心引力、扩大锅容量或修改模型生成规则;若后续仍需优化,只继续围绕生成高度、入场节拍和沉降窗口做局部迭代。 ## 20. 从小到大的生成动画 2026-05-08 追加生成动画优化,参考原型中物体逐个出现、从小到大补入容器的观感。 编码口径: 1. 该优化只作用于前端 3D 表现层的可见 mesh 缩放,不改变后端快照、碰撞体尺寸、物品数量、锅半径、点击判定、备选栏、三消和胜负规则。 2. 物理 body 在创建时仍使用最终尺寸碰撞体,并立即加入 cannon-es 物理世界,确保生成动画过程中碰撞已经按完整体积稳定占位。 3. 可见 mesh 初始以较小比例显示,再用缓动动画放大到完整尺寸;视觉缩放不得反向修改 body shape、质量、边界半径或生成高度避让计算。 4. 入场动画继续服从第 18 节的创建限流和第 19 节的生成高度避让;不能为了动画效果把物体直接放进已有堆叠内部。 5. 动画结束后 mesh 缩放必须回到 `1`,避免影响后续点击可读性和托盘对应关系。 ## 21. 高 DPR 移动端 WebGL 画布尺寸锁定 2026-05-10 针对移动端试玩入口中 3D 锅体和物体从中心区域向右下溢出的问题,补充 WebGL canvas 布局口径。 编码口径: 1. 中心 3D 棋盘和托盘 3D 预览都允许通过 `renderer.setPixelRatio(...)` 提升绘制清晰度,但 `WebGLRenderer.domElement` 的 CSS 显示尺寸必须单独锁定为 `position: absolute; inset: 0; width: 100%; height: 100%; display: block`。 2. `renderer.setSize(width, height, false)` 只负责绘图缓冲区与当前容器尺寸同步,不能依赖 canvas 默认属性尺寸承载 CSS 布局;否则高 DPR 设备会把绘图缓冲区尺寸当成页面尺寸显示,导致棋盘内容放大并从容器右下溢出。 3. 移动端验收仍以 `390px` 竖屏为基准:顶部状态、圆形棋盘和 `7` 格备选栏都必须完整可见,锅体内容应落在屏幕中间的圆形区域内。 4. 该修复只影响 WebGL 画布 CSS 布局,不改变相机、物理世界、碰撞体、点击命中、后端权威快照或托盘规则。