diff --git a/docs/prd/AI_NATIVE_AGENT_FIRST_BIG_FISH_GAME_CREATION_AND_GAMEPLAY_PRD_2026-04-22.md b/docs/prd/AI_NATIVE_AGENT_FIRST_BIG_FISH_GAME_CREATION_AND_GAMEPLAY_PRD_2026-04-22.md index 1c850c3b..dc717eb6 100644 --- a/docs/prd/AI_NATIVE_AGENT_FIRST_BIG_FISH_GAME_CREATION_AND_GAMEPLAY_PRD_2026-04-22.md +++ b/docs/prd/AI_NATIVE_AGENT_FIRST_BIG_FISH_GAME_CREATION_AND_GAMEPLAY_PRD_2026-04-22.md @@ -17,6 +17,9 @@ 7. 发布为可运行玩法 8. 进入竖屏全屏实时玩法运行态 +补充说明: +当前工程实现中,运行态页面需要直接消费结果页已经生成的等级主图、动作图与场地背景图,不能只在结果页预览资产、进入玩法后退回圆点占位表现。 + 本稿必须满足两个硬要求: 1. 不能沿用 RPG 创作链里的旧命名和旧数据口径,把实时吞噬玩法硬塞进 `rpg` 或旧 `customWorld` 语义里。 diff --git a/src/components/big-fish-runtime/BigFishRuntimeShell.tsx b/src/components/big-fish-runtime/BigFishRuntimeShell.tsx index 0032211e..c729e33c 100644 --- a/src/components/big-fish-runtime/BigFishRuntimeShell.tsx +++ b/src/components/big-fish-runtime/BigFishRuntimeShell.tsx @@ -2,13 +2,16 @@ import { ArrowLeft, Loader2 } from 'lucide-react'; import { useEffect, useRef, useState } from 'react'; import type { + BigFishAssetSlotResponse, BigFishRuntimeEntityResponse, BigFishRuntimeSnapshotResponse, SubmitBigFishInputRequest, } from '../../../packages/shared/src/contracts/bigFish'; +import { ResolvedAssetImage } from '../ResolvedAssetImage'; type BigFishRuntimeShellProps = { run: BigFishRuntimeSnapshotResponse | null; + assetSlots?: BigFishAssetSlotResponse[]; isBusy?: boolean; error?: string | null; onBack: () => void; @@ -54,32 +57,87 @@ function projectEntity( }; } +function findBigFishAssetSlot( + slots: BigFishAssetSlotResponse[], + assetKind: string, + level?: number, + motionKey?: string, +) { + return slots.find((slot) => { + if (slot.assetKind !== assetKind || slot.status !== 'ready') { + return false; + } + if (level !== undefined && slot.level !== level) { + return false; + } + if (motionKey !== undefined && slot.motionKey !== motionKey) { + return false; + } + return true; + }); +} + +function resolveRuntimeEntityAsset( + entity: BigFishRuntimeEntityResponse, + assetSlots: BigFishAssetSlotResponse[], +) { + return ( + findBigFishAssetSlot(assetSlots, 'level_motion', entity.level, 'move_swim') ?? + findBigFishAssetSlot(assetSlots, 'level_motion', entity.level, 'idle_float') ?? + findBigFishAssetSlot(assetSlots, 'level_main_image', entity.level) + ); +} + function BigFishEntityDot({ entity, run, owned, + assetSlots, }: { entity: BigFishRuntimeEntityResponse; run: BigFishRuntimeSnapshotResponse; owned: boolean; + assetSlots: BigFishAssetSlotResponse[]; }) { const projected = projectEntity(entity, run); const isLeader = run.leaderEntityId === entity.entityId; + const assetSlot = resolveRuntimeEntityAsset(entity, assetSlots); + const entityImageSrc = assetSlot?.assetUrl?.trim() || null; return (
run.playerLevel - ? 'border-rose-100/70 bg-rose-500/88 shadow-rose-950/24' - : 'border-emerald-100/70 bg-emerald-400/88 shadow-emerald-950/20' + className={`absolute -translate-x-1/2 -translate-y-1/2 overflow-hidden rounded-full border shadow-lg transition-all ${ + entityImageSrc + ? owned + ? isLeader + ? 'border-cyan-50 shadow-cyan-950/40' + : 'border-cyan-100/80 shadow-cyan-950/28' + : entity.level > run.playerLevel + ? 'border-rose-100/80 shadow-rose-950/28' + : 'border-emerald-100/80 shadow-emerald-950/24' + : owned + ? isLeader + ? 'border-cyan-100 bg-cyan-300 shadow-cyan-950/30' + : 'border-cyan-100/70 bg-cyan-500/88 shadow-cyan-950/24' + : entity.level > run.playerLevel + ? 'border-rose-100/70 bg-rose-500/88 shadow-rose-950/24' + : 'border-emerald-100/70 bg-emerald-400/88 shadow-emerald-950/20' }`} style={projected} > - + {entityImageSrc ? ( + <> + +
+ + ) : null} + {entity.level}
@@ -88,6 +146,7 @@ function BigFishEntityDot({ export function BigFishRuntimeShell({ run, + assetSlots = [], isBusy = false, error = null, onBack, @@ -142,10 +201,20 @@ export function BigFishRuntimeShell({ const statusLabel = run.status === 'won' ? '通关' : run.status === 'failed' ? '失败' : '进行中'; + const backgroundAsset = + findBigFishAssetSlot(assetSlots, 'stage_background')?.assetUrl?.trim() || null; return (
+ {backgroundAsset ? ( + + ) : null} +
@@ -168,6 +237,7 @@ export function BigFishRuntimeShell({ entity={entity} run={run} owned={false} + assetSlots={assetSlots} /> ))} {run.ownedEntities.map((entity) => ( @@ -176,6 +246,7 @@ export function BigFishRuntimeShell({ entity={entity} run={run} owned + assetSlots={assetSlots} /> ))}
diff --git a/src/components/platform-entry/PlatformEntryFlowShellImpl.tsx b/src/components/platform-entry/PlatformEntryFlowShellImpl.tsx index 00c2a6f2..17cf0584 100644 --- a/src/components/platform-entry/PlatformEntryFlowShellImpl.tsx +++ b/src/components/platform-entry/PlatformEntryFlowShellImpl.tsx @@ -1791,6 +1791,7 @@ export function PlatformEntryFlowShellImpl({ > {