From a1e5c2150c51cd29fac1f98f3828e7f0998af062 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=94=E9=A6=99=E4=B8=B8=E5=AD=90?= <15518898337@163.com> Date: Fri, 8 May 2026 22:52:13 +0800 Subject: [PATCH] feat: refine match3d spawn visuals --- ...NG_EXPO_ROLLUP_BANNER_DESIGN_2026-05-07.md | 12 +++++------ ...NTIME_3D_GEOMETRY_EXPERIMENT_2026-05-02.md | 12 +++++++++++ .../match3d-runtime/Match3DPhysicsBoard.tsx | 21 ++++++++++++++++--- .../Match3DRuntimeShell.test.tsx | 13 ++++++++++++ 4 files changed, 49 insertions(+), 9 deletions(-) diff --git a/docs/design/BAIMENG_EXPO_ROLLUP_BANNER_DESIGN_2026-05-07.md b/docs/design/BAIMENG_EXPO_ROLLUP_BANNER_DESIGN_2026-05-07.md index b260b218..ff60e59c 100644 --- a/docs/design/BAIMENG_EXPO_ROLLUP_BANNER_DESIGN_2026-05-07.md +++ b/docs/design/BAIMENG_EXPO_ROLLUP_BANNER_DESIGN_2026-05-07.md @@ -6,7 +6,7 @@ 1. 产品名称:百梦。 2. 产品愿景:百梦AI团队致力于打造AI互动内容UGC平台。 -3. 产品slogan:每个人都可以在10分钟内轻松创作出一款精品互动作品。 +3. 产品slogan:不用代码,不用美术,10分钟把脑洞变成有趣的体验。 4. 产品特点:低门槛创作、高完成度作品、玩过后可改造并发布。 5. 关键技术:Harness Engineering、多Agent调度、AI创作工具、AI原生游戏框架。 6. 产品心智:想玩但找不到、玩到不满意、平台外体验不满意时,都可以来百梦做成自己满意的。 @@ -28,16 +28,14 @@ ```text 百梦 -AI互动内容UGC平台 -把想玩的世界,亲手做出来 +10分钟做自己的互动内容 ``` 第二层:远读slogan ```text -每个人都可以在10分钟内 -轻松创作出一款 -精品互动作品 +不用代码,不用美术, +10分钟把脑洞变成有趣的体验 ``` 第三层:产品特点 @@ -88,6 +86,8 @@ reference image: 百梦气泡共创logo方向图 output: output/imagegen/baimeng-expo-rollup/baimeng-rollup-background-gpt-image-2.png ``` +2026-05-08 根据新文案重新调用 `gpt-image-2` 生成新版底图。新版底图在中上部保留更干净的两行 slogan 留白,并在下半部增加轻量内容卡、创作路径和 AI 辅助创作氛围,最终再叠加精确中文排版。 + 因为图片模型直接生成中文长文案存在错字风险,最终稿采用“gpt-image-2 底图 + 本地精确中文排版”的方式生成: ```text diff --git a/docs/technical/MATCH3D_RUNTIME_3D_GEOMETRY_EXPERIMENT_2026-05-02.md b/docs/technical/MATCH3D_RUNTIME_3D_GEOMETRY_EXPERIMENT_2026-05-02.md index 003129f1..c056f2ac 100644 --- a/docs/technical/MATCH3D_RUNTIME_3D_GEOMETRY_EXPERIMENT_2026-05-02.md +++ b/docs/technical/MATCH3D_RUNTIME_3D_GEOMETRY_EXPERIMENT_2026-05-02.md @@ -250,3 +250,15 @@ cannon-es 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`,避免影响后续点击可读性和托盘对应关系。 diff --git a/src/components/match3d-runtime/Match3DPhysicsBoard.tsx b/src/components/match3d-runtime/Match3DPhysicsBoard.tsx index 0f3c1e9d..254fb79e 100644 --- a/src/components/match3d-runtime/Match3DPhysicsBoard.tsx +++ b/src/components/match3d-runtime/Match3DPhysicsBoard.tsx @@ -140,6 +140,8 @@ const MATCH3D_ITEM_SPAWN_STAGGER_MS = 4; const MATCH3D_ITEM_SPAWN_STACK_CLEARANCE = 0.14; const MATCH3D_ITEM_SPAWN_STACK_RADIUS_PADDING = 0.08; const MATCH3D_ITEM_SPAWN_ANIMATION_MS = 260; +const MATCH3D_ITEM_SPAWN_VISUAL_SCALE_START = 0.18; +const MATCH3D_ITEM_SPAWN_VISUAL_DROP_OFFSET = 0.04; const MATCH3D_ITEM_EXTREME_VERTICAL_SPEED_LIMIT = 8.6; const MATCH3D_ITEM_EXTREME_HORIZONTAL_SPEED_LIMIT = 4.4; const MATCH3D_CENTER_GRAVITY_COEFFICIENT = 0; @@ -558,6 +560,18 @@ function resolveSpawnAnimationProgress(entry: PhysicsEntry, now: number) { ); } +export function resolveMatch3DSpawnVisualScale(progress: number) { + const clampedProgress = Math.min( + 1, + Math.max(0, Number.isFinite(progress) ? progress : 0), + ); + const easedProgress = 1 - Math.pow(1 - clampedProgress, 3); + return ( + MATCH3D_ITEM_SPAWN_VISUAL_SCALE_START + + (1 - MATCH3D_ITEM_SPAWN_VISUAL_SCALE_START) * easedProgress + ); +} + function applyCenterGravity(entry: PhysicsEntry) { if (MATCH3D_CENTER_GRAVITY_COEFFICIENT <= 0) { return; @@ -1028,7 +1042,7 @@ function createPhysicsEntryFromPendingSpawn( 0.08, 0.08 + (pendingSpawn.item.layer % 4) * 0.02, ); - visual.mesh.scale.setScalar(0.82); + visual.mesh.scale.setScalar(MATCH3D_ITEM_SPAWN_VISUAL_SCALE_START); runtime.world.addBody(body); runtime.scene.add(visual.mesh); @@ -1714,11 +1728,12 @@ export function Match3DPhysicsBoard({ applyStabilityPlanToBody(entry, activeRuntime.stabilityPlan); constrainBodyInsidePot(entry); const spawnProgress = resolveSpawnAnimationProgress(entry, now); - const spawnScale = 0.82 + spawnProgress * 0.18; + const spawnScale = resolveMatch3DSpawnVisualScale(spawnProgress); entry.mesh.scale.setScalar(spawnScale); entry.mesh.position.set( entry.body.position.x, - entry.body.position.y - (1 - spawnProgress) * 0.06, + entry.body.position.y - + (1 - spawnProgress) * MATCH3D_ITEM_SPAWN_VISUAL_DROP_OFFSET, entry.body.position.z, ); entry.mesh.quaternion.set( diff --git a/src/components/match3d-runtime/Match3DRuntimeShell.test.tsx b/src/components/match3d-runtime/Match3DRuntimeShell.test.tsx index 4db8d3a6..62b60a4e 100644 --- a/src/components/match3d-runtime/Match3DRuntimeShell.test.tsx +++ b/src/components/match3d-runtime/Match3DRuntimeShell.test.tsx @@ -31,6 +31,7 @@ import { resolveMatch3DSpawnTimingPlan, resolveMatch3DStackTargetY, resolveMatch3DSpawnDelay, + resolveMatch3DSpawnVisualScale, resolveMatch3DSpawnY, resolveMatch3DTrayPreviewRotation, resolveMatch3DTrayPreviewReferenceDimension, @@ -591,6 +592,18 @@ test('3D 新物体生成高度会避让同位置已有堆叠', () => { expect(unchangedSpawnY).toBe(plannedSpawnY); }); +test('3D 新物体生成动画只缩放可见模型并最终回到完整尺寸', () => { + const startScale = resolveMatch3DSpawnVisualScale(0); + const middleScale = resolveMatch3DSpawnVisualScale(0.5); + const endScale = resolveMatch3DSpawnVisualScale(1); + + expect(startScale).toBeGreaterThan(0); + expect(startScale).toBeLessThan(0.25); + expect(middleScale).toBeGreaterThan(startScale); + expect(middleScale).toBeLessThan(endScale); + expect(endScale).toBe(1); +}); + test('积木视觉键不会被统一兜底成红色苹字', () => { const run = startLocalMatch3DRun(2); run.items = run.items.slice(0, 2).map((item, index) => ({