器官塔防游戏架构

3 小时前综合
Phase 0 实施计划:口腔塔防核心原型总览:现有代码 → Phase 0 目标的差距维度现有代码Phase 0 目标差距节奏系统固定5波 Wave 表消化节拍循环(12-15s周期,4阶段)全部重写塔系统4种通用塔(enzyme/acid/antibody/whitecell)物理线(切牙堡垒)+ 化学线(淀粉酶塔)重写 TowerTypes敌人系统4种食物直接击杀2种食物(面包+鸡块)+ 碎裂机制新增碎裂逻辑经济金币 (💰)ATP能量 (⚡) + 加工链倍率重命名 + 新规则核心机制传统塔防击杀物理拆解→化学消化加工链全新玩家控制被动等波闸门主动控制进食节奏全新反馈无连击计数器 + 节拍指示器全新依赖关系图Config.lua (0.1)     ← 其他所有模块都依赖
    ↓
GameState.lua (0.8)  ← BeatSystem / GateController 依赖
    ↓
┌───────────────────────────┐
│ BeatSystem.lua (0.2)      │ ← 替代 Wave.lua 的节奏控制
│ GateController.lua (0.3)  │ ← 闸门控制(BeatSystem 调用)
│ Enemy.lua (0.4)           │ ← 碎裂机制
│ Tower.lua (0.5)           │ ← 牙齿堡垒 + 酶塔
│ ProcessingChain.lua (0.6) │ ← 加工链追踪
│ ComboTracker.lua (0.7)    │ ← 连击反馈
└───────────────────────────┘
    ↓
Render.lua (0.9)   ← 渲染新增元素
    ↓
main.lua (0.10)    ← HUD 集成
    ↓
DigestiveSystem.lua (0.11) ← 最后加的薄壳
实施顺序:0.1 → 0.8 → 0.2 → 0.3 → 0.4 → 0.5 → 0.6 → 0.7 → 0.9 → 0.10 → 0.11
0.1 Config.lua 重写改动范围:~150 行修改/新增lua
复制-- ========== 删除 ==========
Config.Waves = { ... }          -- 固定波次表完全删除
Config.START_GOLD = 100         -- 改名
-- ========== 新增/修改 ==========
-- 经济重命名
Config.START_ATP = 200          -- 初始 ATP(原 START_GOLD)
Config.START_LIVES = 5          -- 减为5(单节拍漏5个即死)
-- 节拍配置
Config.Beat = {
    phases = { "preview", "influx", "process", "settle" },
    -- 各阶段时长(秒),按难度期递减
    durations = {
        early  = { preview = 2, influx = 5, process = 6, settle = 2 },  -- 1-10拍
        mid    = { preview = 2, influx = 4, process = 5, settle = 2 },  -- 11-30拍
        late   = { preview = 1.5, influx = 3, process = 4, settle = 1.5 }, -- 31+拍
    },
    earlyEnd  = 10,   -- 前期结束的节拍数
    midEnd    = 30,   -- 中期结束的节拍数
}
-- 闸门配置
Config.Gate = {
    hungerMax       = 100,    -- 饥饿值上限
    hungerPerSec    = 5,      -- 延迟时每秒+5
    hungerDecaySec  = 2,      -- 正常时每秒-2
    fastSpeedMult   = 2.0,    -- 快速放行的敌人释放倍速
    fastATPBonus    = 0.5,    -- 快速放行 ATP 奖励 +50%
}
-- 加工链配置
Config.Processing = {
    physicalMultiplier = 5.0,   -- 经过物理塔后酶塔伤害 ×5
    unprocessedPenalty = 0.2,   -- 未拆解时酶塔伤害 ×0.2
    chainATPMultiplier = 2.0,   -- 完整加工链 ATP ×2.0
    directKillATPMult  = 0.5,   -- 直接击杀 ATP ×0.5
    splitHPRatio       = 0.4,   -- 碎裂子体 HP = 父体剩余 × 0.4
}
-- 塔重写(Phase 0 只有2种)
Config.TowerTypes = {
    incisor = {
        name = "切牙堡垒",
        cost = 0,             -- 牙齿堡垒不花钱,地图上固定位置
        damage = 25,
        range = 1.5,          -- 格子数(近战)
        cooldown = 0.8,
        color = {255, 255, 240, 255},
        attackType = "physical",  -- 新类型:物理拆解
        isFixed = true,           -- 固定位置标记
        splitForce = true,        -- 可触发碎裂
    },
    amylase = {
        name = "淀粉酶塔",
        cost = 50,
        damage = 10,           -- 对已拆解:×5=50;对未拆解:×0.2=2
        range = 3,
        cooldown = 1.5,
        color = {120, 220, 160, 255},
        attackType = "chemical",  -- 新类型:化学消化
        isFixed = false,
    },
}
Config.TowerOrder = { "amylase" }  -- 只有酶塔可手动放置
-- 敌人重写(Phase 0 只有2种)
Config.EnemyTypes = {
    bread = {
        name = "面包块",
        speed = 40,
        maxHp = 120,
        baseATP = 30,         -- 基础 ATP 价值(替代 reward)
        color = {210, 170, 100, 255},
        radius = 12,
        canSplit = true,       -- 可碎裂
        splitCount = 2,        -- 碎裂为 2 个中块
        splitType = "bread_mid", -- 碎裂后的类型
        processedLevel = 0,    -- 0=未处理, 1=中块, 2=小块
        chemTag = "carb",      -- 化学成分标签
    },
    bread_mid = {
        name = "面包片",
        speed = 45,
        maxHp = 50,            -- 碎裂时动态计算,这是上限参考
        baseATP = 15,
        color = {220, 185, 120, 255},
        radius = 9,
        canSplit = true,
        splitCount = 2,
        splitType = "bread_small",
        processedLevel = 1,
        chemTag = "carb",
    },
    bread_small = {
        name = "面包碎",
        speed = 50,
        maxHp = 20,
        baseATP = 8,
        color = {230, 200, 140, 255},
        radius = 6,
        canSplit = false,
        processedLevel = 2,    -- 已充分拆解,酶塔高效分解
        chemTag = "carb",
    },
    chicken = {
        name = "炸鸡块",
        speed = 30,
        maxHp = 200,
        baseATP = 50,
        color = {200, 140, 60, 255},
        radius = 14,
        canSplit = true,
        splitCount = 2,
        splitType = "chicken_mid",
        processedLevel = 0,
        chemTag = "fat",       -- 脂肪类(Phase 0 无脂酶,但标签预留)
    },
    chicken_mid = {
        name = "炸鸡碎",
        speed = 35,
        maxHp = 80,
        baseATP = 25,
        color = {210, 155, 80, 255},
        radius = 10,
        canSplit = true,
        splitCount = 2,
        splitType = "chicken_small",
        processedLevel = 1,
        chemTag = "fat",
    },
    chicken_small = {
        name = "炸鸡渣",
        speed = 40,
        maxHp = 30,
        baseATP = 12,
        color = {220, 170, 100, 255},
        radius = 7,
        canSplit = false,
        processedLevel = 2,
        chemTag = "fat",
    },
}
保留不变:地图配置、编辑器瓦片、颜色主题、寻路配置等全部保留。
0.2 BeatSystem.lua 新建(~120行)职责:取代 Wave.lua 的节奏控制角色,驱动 4 阶段节拍循环。核心接口:
BeatSystem.Init()
BeatSystem.Update(dt)          → 驱动阶段切换、敌人生成
BeatSystem.GetPhase()          → "preview"|"influx"|"process"|"settle"
BeatSystem.GetPhaseTimer()     → 当前阶段剩余秒数
BeatSystem.GetPhaseProgress()  → 0~1 进度
BeatSystem.GetBeatCount()      → 已完成的节拍数
BeatSystem.GetBeatTotal()      → 当前节拍周期总时长
BeatSystem.IsInPhase(name)     → 便捷判断
BeatSystem.Reset()
阶段切换逻辑:preview → influx → process → settle → preview(循环)
            ↑                    ↑
      GateController        ComboTracker
      控制敌人释放          结算连击奖励
程序化敌人生成(在 influx 阶段):
  • 基础强度 = baseStrength × (1 + 0.08 × beatCount)
  • Phase 0 只有 bread 和 chicken 两种,比例随机 7:3
  • GateController 控制实际释放速度
0.3 GateController.lua 新建(~80行)职责:闸门控制,玩家决定食物流入节奏。核心接口:
GateController.Init()
GateController.SetMode(mode)     → "normal"|"fast"|"delay"
GateController.GetMode()
GateController.GetHunger()       → 当前饥饿值 0~100
GateController.IsForceOpen()     → 饥饿值满,强制开启
GateController.Update(dt)        → 更新饥饿值
GateController.GetSpawnInterval() → 当前敌人释放间隔(受模式影响)
GateController.Reset()
UI 交互:main.lua 中 3 个闸门按钮 → 调用 SetMode()。
0.4 Enemy.lua 改造(~80行增量)新增字段:lua
复制enemy.processedLevel = 0      -- 0=大块, 1=中块, 2=小块
enemy.chemTag = "carb"         -- 化学成分标签
enemy.parentId = nil           -- 碎裂来源(追踪加工链)
enemy.isProcessed = false      -- 是否经过物理塔处理
新增函数:lua
复制--- 碎裂:大块 → 2个中块,中块 → 2个小块
--- 子体继承父体路径(从碎裂点继续),HP = 父体剩余 × splitHPRatio
Enemy.Split(enemy)             → 返回生成的子体列表
--- 标记已被物理处理
Enemy.MarkProcessed(enemy)     → 设置 isProcessed = true
碎裂流程
  1. 物理塔攻击 → 伤害扣血
  2. 如果 enemy.canSplit 且 HP ≤ 阈值(或每次物理攻击命中都触发碎裂)→ Enemy.Split()
  3. 碎裂后原体死亡,生成 splitCount 个子体
  4. 子体在原位生成,共享父体路径的剩余部分
  • 更可控,玩家可以观察"切→裂"的因果关系
  • 避免碎片数量指数爆炸
0.5 Tower.lua 改造(~60行增量)关键变化
  1. 牙齿堡垒(物理塔):从地图瓦片自动生成
  2. 酶塔(化学塔):保持手动放置
复制-- 新增函数
Tower.InitFromMap()   -- 扫描地图瓦片,为牙齿位置创建堡垒
Tower.IsFixed(tower)  -- 判断是否固定塔
-- 修改 UpdateOne:
function Tower.UpdateOne(tower, dt)
    if tower.config.attackType == "physical" then
        -- 物理塔:造成伤害,HP→0 时触发碎裂
        -- 调用 Enemy.Damage() + 检查是否触发 Enemy.Split()
    elseif tower.config.attackType == "chemical" then
        -- 化学塔:根据 processedLevel 计算实际伤害
        local mult = enemy.isProcessed and Config.Processing.physicalMultiplier
                                        or Config.Processing.unprocessedPenalty
        Enemy.Damage(enemy, cfg.damage * mult)
    end
end
0.6 ProcessingChain.lua 新建(~60行)职责:追踪每个敌人的加工链状态,决定 ATP 奖励倍率。核心接口:
ProcessingChain.OnEnemyKilled(enemy)  → 计算并发放 ATP
ProcessingChain.GetChainBonus(enemy)  → 返回 ATP 倍率(×2.0 或 ×0.5)
ProcessingChain.GetStats()            → {chainKills, directKills, totalATP}
ProcessingChain.Reset()
判定逻辑:lua
复制function ProcessingChain.OnEnemyKilled(enemy)
    local baseATP = enemy.config.baseATP
    local multiplier
    if enemy.isProcessed and enemy.processedLevel >= 2 then
        -- 完整加工链:物理拆解到最小 + 化学消化
        multiplier = Config.Processing.chainATPMultiplier  -- ×2.0
    else
        -- 直接击杀(未充分加工)
        multiplier = Config.Processing.directKillATPMult    -- ×0.5
    end
    local atp = math.floor(baseATP * multiplier)
    GameState.AddATP(atp)
    ComboTracker.AddHit()  -- 通知连击系统
    return atp
end
0.7 ComboTracker.lua 新建(~50行)职责:追踪连续有效分解的连击数,触发视觉反馈。核心接口:
ComboTracker.AddHit()               → 连击+1
ComboTracker.GetCombo()             → 当前连击数
ComboTracker.GetBonusMultiplier()   → 每5连击+20%
ComboTracker.OnBeatSettle()         → 节拍结算时重置/保持
ComboTracker.GetFloatingText()      → 返回待显示的浮动文本列表
ComboTracker.Update(dt)             → 更新浮动文本动画
ComboTracker.Reset()
连击奖励
  • 每 5 连击:额外 +20% ATP
  • 10+ 连击:屏幕中央显示 “PERFECT DIGESTION!”
0.8 GameState.lua 改造(~40行增量)lua
复制-- 重命名
gold → atp              -- 全局搜索替换
GetGold → GetATP
AddGold → AddATP
SpendGold → SpendATP
CanAfford → CanAffordATP
-- 新增状态
beatPhase = "preview"    -- 当前节拍阶段
beatCount = 0            -- 已完成节拍数
-- 新增接口
GameState.GetATP() / AddATP() / SpendATP() / CanAffordATP()
GameState.SetBeatPhase(phase)
GameState.GetBeatPhase()
GameState.IncrementBeat() → beatCount++
-- 状态枚举不变(STATE_PREPARE 变为"游戏未开始",STATE_WAVE 变为"游戏进行中")
0.9 Render.lua 改造(~100行增量)新增渲染元素
  1. 节拍指示条(屏幕底部,横向进度条):
  2. 碎裂动画
  3. 连击文本
  4. 闸门可视化
  5. 牙齿堡垒渲染
0.10 main.lua 改造(~120行修改)HUD 变更:顶部栏(修改):
  ❤️ 5  ⚡ 200  ⭐ 0  🦷 Beat 1
  ^lives ^ATP   ^score ^beatCount
波次信息 → 节拍阶段信息:
  "预告:面包块 ×3 + 炸鸡块 ×1"  (preview阶段)
  "涌入中..."                      (influx阶段)
  "加工中 — ×5 连击!"              (process阶段)
  "结算:+180 ATP"                 (settle阶段)
底部塔选择栏(简化):
  只有 [淀粉酶塔 ⚡50] 一个按钮
新增闸门控制栏(底部右侧):
  [正常▶] [快进⏩] [暂停⏸]
游戏循环变更:lua
复制function HandleUpdate(eventType, eventData)
    -- BeatSystem.Update(dt) 替代 Wave.Update(dt)
    -- GateController.Update(dt)
    -- ComboTracker.Update(dt)
    -- Enemy.UpdateAll(dt) 不变
    -- Tower.UpdateAll(dt) 不变
end
启动流程变更:lua
复制function StartNewGame(
)
    -- ...原有重置...
    BeatSystem.Init(
)
    GateController.Init(
)
    ProcessingChain.Reset(
)
    ComboTracker.Reset(
)
    Tower.InitFromMap(
)  -- 从地图瓦片自动创建牙齿堡垒
    BeatSystem.Start(
)   -- 开始第一个节拍周期
end
0.11 DigestiveSystem.lua 薄壳(<80行)纯接口预留,Phase 0 无实际逻辑:lua
复制local DigestiveSystem = {}
--- 当前器官 ID(Phase 0 固定为 "oral")
function DigestiveSystem.GetCurrentOrgan()
    return "oral"
end
--- 添加残渣到下游队列(Phase 0: 空实现,仅打印)
function DigestiveSystem.AddResidue(residue)
    -- Phase 4 实现:传递给胃
    print("[DigestiveSystem] Residue logged: " .. tostring(residue.type))
end
--- 查询暗线指标(Phase 0: 全返回0,Phase 1-2 实现)
function DigestiveSystem.GetIndicator(name)
    -- Phase 1-2 实现:血糖/血脂/血钠
    return 0
end
--- 触发返流事件(Phase 0: 空实现)
function DigestiveSystem.TriggerReflux(data)
    -- Phase 4 实现:A* swap start/end
    print("[DigestiveSystem] Reflux event (stub)")
end
--- 获取关卡结算数据(Phase 0: 基本统计)
function DigestiveSystem.GetSettlementData()
    return {
        organ = "oral",
        beatCount = GameState.GetBeatCount(),
        totalATP = ProcessingChain.GetStats().totalATP,
        chainKills = ProcessingChain.GetStats().chainKills,
    }
end
return DigestiveSystem
Wave.lua 处理保留文件但不再使用。BeatSystem.lua 完全取代其职责。main.lua 中移除 require("Wave"),改用 require("BeatSystem")。后续清理时可以删除 Wave.lua。
实施顺序 & 预估改动量步骤文件操作增量行数0.1Config.lua修改+100, -300.8GameState.lua修改+30, -100.2BeatSystem.lua新建~1200.3GateController.lua新建~800.4Enemy.lua修改+800.5Tower.lua修改+600.6ProcessingChain.lua新建~600.7ComboTracker.lua新建~500.9Render.lua修改+1000.10main.lua修改+120, -800.11DigestiveSystem.lua新建~50
总计~700行新增/修改
验收标准Phase 0 完成后,玩家应该能体验到:
  1. 节拍节奏感 — 预告→涌入→加工→结算的循环,有明确的视觉/信息反馈
  2. 加工链满足感 — 面包块被切牙切碎→淀粉酶分解→ATP 涌入,×2.0 vs ×0.5 的效率差明显可感知
  3. 闸门掌控感 — 快速放行赚更多但风险高,延迟放行有饥饿值压力
  4. 连击爽感 — 流水线高效运转时连击数上涨 + 视觉文字反馈
  5. 30+ 节拍的可玩时长 — 程序化波次逐渐变强,体验有弧线
这是完整的 Phase 0 实施计划。所有架构决策都遵循之前确认的方案:Plan A 单器官会话、薄壳接口预留、无 EventBus、无全局 HUD。要开始编码吗?我会按依赖顺序(Config → GameState → BeatSystem → … → main.lua)逐步实施。
Phase 0.10: main.lua 改造 — 5处修改:函数改动HandleUpdate()Wave.Update(dt) → BeatSystem.Update(dt) + GateController.Update(dt) + ComboTracker.Update(dt)CreateTopHUD()💰 Config.START_GOLD → ⚡ Config.START_ATP;Wave 0/#Waves → Beat 0CreateTowerSelector()Config.TowerTypes[typeName] → Config.EnzymeTowers[typeName];费用符号 $ → ⚡UpdateHUD()金币→ATP、波次→节拍计数、阶段信息改为4阶段显示(预览/涌入/加工/结算)UpdateTowerSelector()Config.TowerTypes → Config.EnzymeTowersPhase 0.11: DigestiveSystem.lua — 77行薄壳,预留接口:
  • GetCurrentOrgan() / SetCurrentOrgan() — 器官身份
  • AddResidue() / GetResidueList() / ClearResidue() — 漏怪残渣收集
  • GetIndicator(key) — 委托 GameState 查暗线指标
  • TriggerReflux(payload) — 反流事件预留(空操作)
  • GetSettlementData() — 关卡结算数据包
  • Reset() — 重置
1