Farmix 项目技术文档(Tech Doc)


0. 快速开始

  1. 场景与组件清单

    • 打开 GameScene,确认这些对象存在且启用:Qix(挂载 QixLite)、Level(挂载 LevelManager)、CanvasEventSystemMain Camera
    • QixLite 会在运行时构建玩法网格和 UI;你不需要在层级里预先摆放网格格子。
  2. 资源绑定(必需)

    • QixLite 的 Inspector 中,拖拽绑定资源:地面 sprites、14 向边缘 mask、14 向轨迹(Trail)mask、Player/Sheep/Wolf/Bear/Locust/Pesticide 的静态 sprite 与动画帧数组;BGM 与 SFX;如果使用 TextMeshPro,也请绑定 hudTMP
  3. 关卡设置

    • LevelLevelManager)中编辑 Levels 列表以定义多个关卡。如果列表为空,会自动生成5 个默认关卡,难度逐级递增。
  4. Build Settings

    • GameSceneMainMenu(或你使用的菜单场景名)加入 Build Settings。通关后,LevelManager 会返回 mainMenuSceneName

1. 架构与职责

1.1 运行时对象与脚本边界

  • LevelManager(流程/难度)

    • 对外暴露 LevelConfig(生命数、单位数量、速度、计时器、计分、胜利占领比、蝗虫并发上限等)。
    • 游戏开始:查找 QixLite 并调用 BeginLevel(cfg) 注入关卡参数并启动关卡。
    • 关卡结束:接收 QixLite 的胜利回调,推进到下一关或返回主菜单。
  • QixLite(玩法/渲染/输入/视听)

    • 网格:用 GridLayoutGroup 运行时构建 width×heightImage 网格,并维护状态机(Empty/Occupied/Trail)。
    • 玩家移动:键盘 + 陀螺仪;进入/退出画线模式;闭合后进行填充、计分与胜负判定。
    • 敌人与行为:Sheep(计分目标)、Wolf(多格占位移动)、Bear(边缘巡逻/计时提速/边缘规则)、Locust(并发刷新、啃食已占领区域、全局冷却)。
    • UI/HUD:分数、生命、占领率、计时器(Text 或 TMP),以及动画/SFX 钩子。
    • 特效/音频:序列帧动画、一次性尘土 FX、杀虫剂闪烁 FX、BGM/SFX 播放。

1.2 “没有 LevelManager” 的兜底模式

  • 如果场景里没有 LevelManagerQixLite.Start() 会使用 Inspector 中的自身参数创建“Free Play”配置并自动开始。这个模式适合做单元测试/美术集成。

2. 网格、精灵与边缘规则(视觉 + 规则统一)

2.1 网格构建

  • 运行时创建 CanvasGridHUDActors 等 Transform。Grid 使用 GridLayoutGroup;每个格子创建一个 Image 并初始化为空地 sprite。

2.2 格子状态

  • Cell:三态——Empty / Occupied / Trail。状态写入通过 SetCell/SetCellDirect,并在写入后刷新邻居。

2.3 14 向边缘 Mask(Occupied / Trail 各一套)

  • 位掩码:Up=1, Right=2, Down=4, Left=8
  • OccupiedTrail 各有 14 张组合边缘 sprite。ApplyCellSprite() 会根据邻接关系选择正确 sprite。
  • 注意:无论是内部还是边界情况,为了让边缘高亮更直观,计算高亮时会把 Trail 在视觉上当作空地来处理。

2.4 边界特例规则

  • 边界上的 Occupied 是否显示为“贴近空地的边界高亮”,通过采样仅内侧的 8 邻居来决定,避免高亮“扩散到场外”。
  • 边界角落如果只有纯对角接触(cardinal mask = 0),规则上仍然可行走,但会渲染为纯实心占领(不高亮)以避免误导。

3. 玩家输入与移动状态机

3.1 输入优先级

  • 键盘(WASD/方向键)优先;当两个轴都按下时,优先采用最后一次移动的轴。若无键盘输入,则读取陀螺仪(带 dead-zone/threshold)。

3.2 在 Occupied 上的可行走性

  • Occupied 上行走需要格子是合法边缘

    • 边界(Border):必须与 Empty(“空地”)存在 8 邻接接触
    • 内部(Interior):只有当存在 8 邻接接触 Empty 时才合法;否则玩家被视为被困(trapped)。
  • 踩到自己的 Trail(自撞)会立刻触发死亡处理。

3.3 画线与闭合

  • 从占领区离开即进入画线模式;经过的格子变为 Trail 并应用正确的 14 向轨迹 sprite。重新进入占领区会触发 CloseAndFillArea() 执行 flood fill 与结算。

3.4 自动救援(被困时)

  • 如果玩家站在 Occupied 上但不在合法边缘,会启动 PlayerRescueAutopilot()

    • 先闪烁 1 秒(真实时间)→ 在 Occupied 上 BFS 到最近的玩家可站立的占领边缘格 → 按当前玩家步速移动过去。

4. 区域闭合、填充与计分

4.1 核心填充算法

  1. 从所有狼(它们的矩形占位)和熊出发 BFS,标记“可达的 Empty”。
  2. 未标记的 Empty 判定为被封闭 → 设为 Occupied;同时将整条 Trail 转为 Occupied
  3. 统计 filled 格子数并加分:filled × scorePerCell;统计被封闭的羊并为每只加 scorePerSheep
  4. 被封闭在内部的熊会获得一条“回到最近合法边缘”的路径(仅在 Occupied 上的直线路径)。
  5. filled > 0sealsCount 自增(用于蝗虫刷新前置条件;见 §6)。
  6. 刷新边缘 sprite 与 UI。若占领率 ≥ winOccupyRatio,触发胜利。

BFS 与直线路径构造位于 FindPathToNearestEdge() / BuildStraightPath(),并保证每一步都在 Occupied 上。


5. 敌人系统

5.1 Sheep(羊)

  • 随机生成在空地单格上;当被完整封闭时加分并播放计分 SFX。

5.2 Wolves(狼:矩形占位)

  • wolfSize 为边长(默认 2 → 2×2 区域)。在空地矩形上生成;支持四方向动画(未配置时回退到通用动画)。
  • 轨迹切割可能触发“狼分离”检测(CheckWolfSeparationByTrail();即便这里未展示片段也已预留接线)。

5.3 Bears(熊:边缘巡逻 / 计时提速 / 边缘规则)

  • 初始在右上附近生成到最近 Occupied;若无效,则在 Occupied 上 BFS 找最近合法边缘作为出生点。
  • 熊的可行走性与玩家一致:必须为合法边缘(边界/内部都要求与 Empty 存在 8 邻接接触)。
  • 在计时器事件中速度可提升(bearTilesPerSecondFast/Faster);HandleTimerTimeout() 也可按关卡配置追加生成熊。

6. 蝗虫系统(并发、啃食、冷却)

6.1 刷新条件与并发上限

  • 全局 tick 达到 locustSpawnInterval 才尝试刷新;需要满足:

    • 至少 两次闭合sealsCount ≥ 2);
    • 当前时间 ≥ locustGlobalNoSpawnUntil(即不在全局冷却期);
    • 当前蝗虫数量 < maxLocusts
    • 每次尝试有 50% 概率;
    • 优先选择与空地接触的占领格(内部边缘)或内部占领边缘;若不存在则回退到任意占领格;
    • 出生格不能与除羊以外的实体碰撞(玩家与羊不阻挡)。
  • maxLocusts 来自关卡配置 LevelConfig.locustMaxConcurrent,进入关卡时应用。

6.2 移动与旋转

  • 每一步,蝗虫都会 BFS 到最近的**可吃的 Occupied**(非边界)。移动始终保持在 Occupied 上。步进方向会驱动 sprite 的旋转。
  • 边界不可吃。如果只剩 一条合法占领边缘,蝗虫会自毁并启动全局冷却,避免把最后的边缘断开导致无解。

6.3 移除/死亡与特效

  • 当新填充的区域与蝗虫所在的占领连通块连到一起时,蝗虫被击杀并播放杀虫剂闪烁 FX(默认 2 秒;pesticideAnimpesticideBaseSprite);随后启动全局冷却locustRespawnCooldown)。
  • 若只剩一条合法边缘或找不到可吃目标,蝗虫会消失(despawn)并进入冷却。
  • 提供 spawn/death 的独立 SFX 钩子(sfxLocustSpawn / sfxLocustEaten)。

7. 计时器与阶段事件

  • 关卡计时 levelTimerSeconds 每帧递减;当 ≤ 0 时触发 HandleTimerTimeout(),随后计时器会重置为初始值。

  • 典型阶段动作(由关卡配置决定):

    • 第一次超时:可选地通过 extraBearsOnFirstTimeout 增加熊;
    • 提速:将熊速度切换到 bearTilesPerSecondFast/Faster
  • 计时器由 HUD/TMP 显示(TimerText;使用 hudTMP 可构建更丰富的 HUD)。


8. UI / HUD / 字体

8.1 运行时构建 UI

  • ConstructIfNeeded() 创建 CanvasGridHUDActors。HUD 默认包含 TimerTexthudText 作为扩展钩子(推荐 TMP)。

8.2 字体兼容性(Unity 6)

  • CreateText() 使用 builtinFont ? builtinFont : Resources.GetBuiltinResource<Font>("Arial.ttf")

  • Unity 6 内置 Arial 资源的名称/路径发生变化(常见报错:“Arial.ttf is no longer a valid built in font. Please use LegacyRuntime.ttf”)。

    • 建议

      1. builtinFont 指定工程内字体(最好与 TMP 同字体族),或
      2. 将 fallback 资源改为 "LegacyRuntime.ttf",或
      3. 将 HUD 全面迁移到 TextMeshPro。项目已经提供 hudTMP 字段。

9. 音频系统

  • 使用两个 AudioSourcemusicSource 播放 BGM(支持“升级版 BGM”),sfxSource 播放短音效(脚步、计分、蝗虫刷新/消失、胜负等)。
  • 工具方法:PlayBGM(clip, loop)PlaySfx(clip, vol)
  • 建议:使用 AudioMixer 将 BGM/SFX 分组并加 limiter;叠加时尽量把 SFX 峰值控制在 -6 dBFS 以下,避免削波失真。

10. LevelConfig → 运行时映射

LevelConfig 字段 用途 / 应用位置
lives 进入关卡时若 resetLives 为 true,则覆盖 QixLite.lives
numSheep / numWolves / wolfSize 进入关卡时应用;用于 SpawnSheep/SpawnWolves
initialBears / extraBearsOnFirstTimeout 初始熊数量 + 第一次超时追加熊
playerStepPerSecond 玩家步速(tiles/sec)
wolfSpeed 狼速度 → wolfTilesPerSecond
bearSpeed / bearFastSpeed / bearFasterSpeed 熊的三段速度
locustSpeed / SpawnInterval / RespawnCooldown 蝗虫速度 / 刷新间隔 / 全局冷却
locustMaxConcurrent 并发上限maxLocusts = Max(1, cfg.locustMaxConcurrent)
winOccupyRatio 胜利阈值(0.5–0.95)
levelTimerSeconds 初始计时值
scorePerCell / scorePerSheep 填充每格得分 / 捕获羊得分

LevelManager.levels 为空,Awake() 会生成 5 个默认关卡,敌人逐渐加速、计时略微缩短。


11. 资源规范与美术说明

  • Sprites

    • 地面:groundEmpty / groundOccupied / groundTrail / groundCrops
    • 边缘 mask:Occupied 14 张Trail 14 张(U/D/L/R、UR/UL/DR/DL、URD/ULD/DRL/URL、RL/UD)。命名清晰、像素尺寸一致。
  • 动画序列帧:数组顺序即播放顺序;每个资源可配置 FPS。支持玩家/敌人/尘土/杀虫剂。

  • 视觉缩放:每个 actor 有一个 xxxVisualScale,只影响视觉大小(不改变碰撞/规则)。


12. 性能与内存

  • 网格大小:默认 48×27 ≈ 1296 个 Image。中高端设备可接受。避免重复重建网格;当前实现只构建一次,后续只替换 sprite。
  • Actor:Sheep/Wolf/Bear/Locust/FX 按需 Instantiate/Destroy。若并发较高,建议引入对象池
  • 寻路/BFS:网格上是 O(w·h)。蝗虫频繁 BFS 时可限制搜索半径或加入局部缓存。
  • 音频:对每步脚步音效做节流,或复用 AudioSource,避免同一帧多次播放。

13. QA 测试清单

功能

  • 闭合后:空地填充正确;14 向边缘组合正确;整条 Trail 变为 Occupied
  • 捕获羊加分并播放 SFX。
  • 熊出生点合法;巡逻始终走边缘;计时提速按配置触发。
  • 狼 2×2 碰撞与分离逻辑正确。
  • 蝗虫刷新满足 sealsCount/冷却/并发;不吃边界;只剩一条合法边缘时自毁。
  • 自动救援:1 秒闪烁 + BFS 路径正确;地图在救援途中变化时不死锁。
  • 计时器超时事件(第一次加熊/提速)与计时器重置正确。
  • 胜利后 LevelManager.OnLevelWinFinished() 能正确推进/回菜单。

兼容性

  • HUD 使用 TMP 且指定字体;若仍用 Text,需设置 builtinFont 或 fallback 到 LegacyRuntime.ttf
  • 移动端:陀螺仪阈值/dead-zone 手感合理;横竖屏 UI 安全区正确。

健壮性

  • LevelConfig 极端值(0/负数)被 clamp(例如 maxLocusts = Max(1, …))。
  • 关卡切换时清理旧的 Actors 与 FX。
  • 在暂停状态(死亡/救援/杀虫剂/狼清理)中,Update 要 early-out,避免竞态。

14. FAQ

  1. HUD 字体报错(Unity 6)

    • 现象:Arial.ttf is no longer a valid built in font
    • 解决:给 builtinFont 指定工程字体或把 fallback 改为 LegacyRuntime.ttf;最好切换到 TMP。
  2. HUD/计时器不显示

    • ConstructIfNeeded() 会在 HUD 下创建 TimerText。若 UI 被挡住,检查 sibling 顺序:gridRoot(0)< actorsRoot(1)< uiRoot(2)。
  3. 蝗虫“啃掉最后一条边缘”导致死局

    • 已有防护:边界不可吃;当只剩一条合法内部边缘时蝗虫会自毁并进入冷却。
  4. 玩家在边界/角落“卡住”

    • 合法边缘要求与 Empty 8 邻接接触;纯对角接触会渲染为实心占领(仍可走)。被困时会触发自动救援。

15. 扩展与可改造点

  • 新增单位:沿用 Actor.KindSpawnXxx/MoveXxx 模式,为新类型添加 sprite、动画与移动规则。
  • 更高级 AI:给狼增加 flocking/避 Trail;给熊增加“追最近合法玩家边缘”(复用 FindPathToNearestEdge)。
  • 脚本化关卡:将 LevelConfig 序列化为 JSON/ScriptableObject 做关卡编辑器;在 LevelManager.Awake 中加载。
  • 对象池:统一 Actors 与 FX 生命周期,降低 GC 与卡顿。
  • 调试面板:在 QixLite 增加 Debug 区(路径覆盖、mask bit、合法/非法边缘上色等)。

16. 团队协作习惯

  • 命名:对 sprites/动画使用一致前缀(occ_ / tr_ / wolf_up_XX 等),方便批量绑定与搜索。
  • 提交前自检:从开始跑到通关一局;检查边缘高亮、计分与音频;用 Deep Profile 检查分配。
  • PR 说明:若改动关键路径(如 ApplyCellSprite / CloseAndFillArea / HandleLocust),请提供前后对比截图与性能数据

17. 关键 API/方法(按用途)

  • 关卡BeginLevel(cfg, levelIndex, resetLives)(进入),OnLevelWinFinished(caller)(推进)
  • 网格/边缘ApplyCellSprite / UpdateAllEdgeVisuals / BorderHasEmpty8 / HasEmptyNeighbor8
  • 玩家ReadPlayerDirectionCardinal / StepPlayer / IsPlayerTrapped / PlayerRescueAutopilot
  • 闭合CloseAndFillArea / FindPathToNearestEdge / BuildStraightPath
  • 蝗虫HandleLocust / TrySpawnLocustPreferOccupied / IsEdibleOccupied / LocustNextStepToNearestEdible / KillLocustWithSmoke
  • IsBearEdgeCell / FindFreeEdgeSpawnNear
  • UIConstructIfNeeded / CreateText / UpdateHUD(HUD 更新在 Update/结算逻辑中触发)

18. 版本与环境

  • Unity:Unity 6(按截图),DX11;注意内置 Text 字体资源变更。
  • 平台:支持键鼠 + 陀螺仪(移动端);iOS/Android 可补充触控输入映射与响应式 UI。
  • 依赖:TextMeshPro(推荐用于所有 HUD 文本)。

附录:上手/运营清单

  • 美术接线:把 14 向 masks 与动画序列帧拖到 QixLite 中对应数组(注意顺序)。
  • SFX 调参:在安静环境跑一局,确认脚步音效不疲劳;必要时加小的播放节流间隔。
  • 关卡调参:从 Level 1 起步:wolfSpeed 6, bearSpeed 4, win 0.75, timer 37s, maxLocusts 1;后续逐步提高速度/并发并缩短计时器。