From 7694ef57232a9185d1e1716a74c388d312787afe Mon Sep 17 00:00:00 2001 From: kdletters Date: Sun, 26 Apr 2026 21:41:20 +0800 Subject: [PATCH] feat: add big fish runtime rules entry --- .../BIG_FISH_RUNTIME_RULE_ENTRY_2026-04-26.md | 33 +++++++++++ .../BigFishRuntimeShell.test.tsx | 19 +++++++ .../big-fish-runtime/BigFishRuntimeShell.tsx | 55 ++++++++++++++++++- 3 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 docs/technical/BIG_FISH_RUNTIME_RULE_ENTRY_2026-04-26.md diff --git a/docs/technical/BIG_FISH_RUNTIME_RULE_ENTRY_2026-04-26.md b/docs/technical/BIG_FISH_RUNTIME_RULE_ENTRY_2026-04-26.md new file mode 100644 index 00000000..19b48c12 --- /dev/null +++ b/docs/technical/BIG_FISH_RUNTIME_RULE_ENTRY_2026-04-26.md @@ -0,0 +1,33 @@ +# 大鱼吃小鱼运行页规则入口说明 2026-04-26 + +## 背景 + +大鱼吃小鱼玩法规则已经在 PRD 与运行态技术方案中定义,但网站运行页没有给玩家查看规则的入口。玩家进入 `/big-fish` 或正式运行页后,只能看到当前等级、状态和事件日志,无法在游玩前快速理解吞噬、合成、胜负条件。 + +## 设计结论 + +1. 规则入口放在运行页顶部操作区,使用 `CircleHelp` 图标按钮。 +2. 默认界面不直接铺规则长文案,点击按钮后打开独立模态窗口。 +3. 模态窗口只保留玩家决策所需的核心规则: + - 拖动方向控制移动。 + - 吃掉低级或同级野生实体并收编。 + - 碰到更高级野生实体时,己方实体会被吃掉。 + - 3 个同级己方实体自动合成更高一级。 + - 拥有最高等级后通关,己方实体归零后失败。 +4. 入口必须在移动端单手可点,不遮挡舞台主体。 +5. 规则内容只做说明,不参与任何前端裁决;真实规则仍以后端运行快照为准。 + +## 落地范围 + +1. `src/components/big-fish-runtime/BigFishRuntimeShell.tsx` + - 增加规则按钮与规则模态窗口。 + - 复用 `UnifiedModal`,避免在当前玩法舞台内容流里展开说明。 +2. `src/components/big-fish-runtime/BigFishRuntimeShell.test.tsx` + - 覆盖规则入口打开与关闭。 + +## 验收口径 + +1. 进入大鱼吃小鱼运行页后,右上角可看到规则图标入口。 +2. 点击规则入口后出现独立弹窗。 +3. 弹窗能展示核心吞噬、合成、通关与失败规则。 +4. 关闭弹窗后回到玩法舞台,不改变当前运行快照。 diff --git a/src/components/big-fish-runtime/BigFishRuntimeShell.test.tsx b/src/components/big-fish-runtime/BigFishRuntimeShell.test.tsx index e6b8597c..51a771db 100644 --- a/src/components/big-fish-runtime/BigFishRuntimeShell.test.tsx +++ b/src/components/big-fish-runtime/BigFishRuntimeShell.test.tsx @@ -77,4 +77,23 @@ describe('BigFishRuntimeShell', () => { fireEvent.click(screen.getByRole('button', { name: '退出' })); expect(onBack).toHaveBeenCalledTimes(1); }); + + test('opens and closes the runtime rule modal', () => { + render( + {}} + onSubmitInput={() => {}} + />, + ); + + fireEvent.click(screen.getByRole('button', { name: '查看规则' })); + + expect(screen.getByRole('dialog', { name: '玩法规则' })).toBeTruthy(); + expect(screen.getByText('低级或同级野生实体会被收编。')).toBeTruthy(); + + fireEvent.click(screen.getByRole('button', { name: '关闭' })); + + expect(screen.queryByRole('dialog', { name: '玩法规则' })).toBeNull(); + }); }); diff --git a/src/components/big-fish-runtime/BigFishRuntimeShell.tsx b/src/components/big-fish-runtime/BigFishRuntimeShell.tsx index 344ba674..f4c6b353 100644 --- a/src/components/big-fish-runtime/BigFishRuntimeShell.tsx +++ b/src/components/big-fish-runtime/BigFishRuntimeShell.tsx @@ -1,4 +1,4 @@ -import { ArrowLeft, Loader2, RotateCcw } from 'lucide-react'; +import { ArrowLeft, CircleHelp, Loader2, RotateCcw } from 'lucide-react'; import { type PointerEvent, useEffect, useRef, useState } from 'react'; import type { @@ -7,6 +7,7 @@ import type { BigFishRuntimeSnapshotResponse, SubmitBigFishInputRequest, } from '../../../packages/shared/src/contracts/bigFish'; +import { UnifiedModal } from '../common/UnifiedModal'; import { ResolvedAssetImage } from '../ResolvedAssetImage'; type TouchOrigin = { @@ -127,6 +128,38 @@ function resolveSettlementCopy(run: BigFishRuntimeSnapshotResponse) { return null; } +function BigFishRuleModal({ + open, + onClose, +}: { + open: boolean; + onClose: () => void; +}) { + return ( + +
+
+ 拖动屏幕控制方向,角色会按固定速度移动。 +
+
+
低级或同级野生实体会被收编。
+
更高级野生实体会吃掉碰到的己方实体。
+
3 个同级己方实体会自动合成更高一级。
+
拥有最高等级实体后通关,己方实体归零后失败。
+
+
+
+ ); +} + function BigFishEntityDot({ entity, run, @@ -194,6 +227,7 @@ export function BigFishRuntimeShell({ }: BigFishRuntimeShellProps) { const stageRef = useRef(null); const [touchOrigin, setTouchOrigin] = useState(null); + const [isRuleModalOpen, setIsRuleModalOpen] = useState(false); const [stick, setStick] = useState({ x: 0, y: 0 }); const stickRef = useRef(stick); @@ -297,8 +331,19 @@ export function BigFishRuntimeShell({ > -
- Lv.{run.playerLevel}/{run.winLevel} · {statusLabel} +
+ +
+ Lv.{run.playerLevel}/{run.winLevel} · {statusLabel} +
@@ -370,6 +415,10 @@ export function BigFishRuntimeShell({ ))} + setIsRuleModalOpen(false)} + /> );