You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
AdLike2048/docs/方案-出怪逻辑实现.md

8.6 KiB

方案-出怪逻辑实现

状态:出怪 + 到达扣营地血 + 营地血条 + 胜负已落地。审阅基线见 Cursor Plan v2。

1. 目标与范围

项 说明
对战 PVE:玩家 vs AI(程序控制),双阵营地图对称出怪
进关 首页开始 → 按当天 Const 31~37 地图池随机 Level.id;GM「固定地图」可锁 id
出怪 Level.monster + Level.boss + Level.bosspro
出怪口 玩家 port1,AI port2,同一套波次配置
队列 每波口内 顺序段:先小怪段,再 Boss 段(WaveSpawner segment 顺序)
预制体 Monster.icon → battleGameMonster/prefab/monster/{icon}
本期不做 塔攻击

2. 配表

Level.monster(四列)

waveIndex,monsterId,count,spawnInterval

| 分隔 25 波。例:1,1001,10,1.6

  • 第 4 列:该波每只怪出现间隔(秒)
  • Monster1 行 id = waveIndex(不是第 4 列)

Level.boss

waveIndex|monsterId,...

例:5|1101,10|1101 → 第 5、10 波排队出 Boss 1101(在小怪段之后)。

Level.bosspro(万分比)

  • Boss 链未激活时,按 boss 顺序在对应波次掷一次概率。
  • 命中 → 该波出 Boss,链激活;之后所有 boss 配置波必出,不再掷概率。
  • 未命中 → 该波不出 Boss,等下一条 boss 配置再掷。

实现:LevelWaveParser.resolveBossSpawns
掷点须无符号再 % 10000:JS 有符号 % 会得到负数,负数 < bosspro 恒成立,链会提前激活。

Monster / Monster1

  • Monster:icon 为预制体名;speed 寻路;hp 参与血量公式;type:1 小怪 / 2 BOSS / 3 召唤。
  • Monster1:行 = waveIndex;列 = Rank.diffcult / Level 难度组。
  • 血量计算时机:出怪当下套公式 floor(Monster.hp × hp_multiple × port_hp × Monster1[波次] × 战力修正 × weapon_para),不以开局缓存为准。波次怪、营召唤、atk_type=8(含哮天犬)、万神幡 Boss 同一套;Monster1 行取当前波 waveIndex。

表现(五行新怪:不设皮肤、不区分阵营)

Spine 资源仅 default 皮;双口同一种表现。

type 预制体 皮肤 行进 死亡
1 五行小怪 prefab/monster/{icon}(如 小怪金) 不 setSkin {系}小怪(如 金小怪) {系}小怪2(如 金小怪2)
2 新 Boss prefab/monster/{icon}(如 Boss金) 不 setSkin 走路 按 Boss 资源轨(缺则 error)

Monster.icon → 行进 / 死亡:小怪金→金小怪/金小怪2,木/水/火/土同理。映射失败或动画不存在 → console.error,禁止静默兜底。

实现:MonsterDataManager.resolveElementMarchAnim / resolveElementDeathAnim + Monster.playWalk / 死亡播控;Presenter 对新怪跳过换皮。

营字强化出怪(Hero.id=5)

项 约定
触发 地图上每个激活的「营」独立计时、独立出怪
配表 Skill.atk_para:怪物id,数量(如 -1,1);间隔用 Skill.cd(1~5 级 10/8/6/5/4 秒)
-1 当前/最近一波小怪段 monsterId;准备期/Boss/波间仍按该 id 出小怪
出生 「攻击」0.5s 草字头打开后,怪出现在营格心上偏 30px(光的位置)、0.5 倍(相对落地)缩放,0.3s 放到 Monster.size×1.3;血条挂怪根上随身体放大;停 1s 再抛物线跳出
落点 同行最近可达进路格(出怪口格除外);与口同行或没有横向落点时,用普通怪出怪口跳跃落点(进路第一格)。出怪口不能作为跳跃目标
逻辑口 UnitMetaComp.spawnPoint 仍记己方营 port1 / 敌方营 port2(皮肤、阵营、复活)
表现 营预制体播「攻击」(开→持有→1.17s 合上)后回「待机」;无口特效、无冒怪
皮肤 Monster.res[营等级-1];敌方阵营加后缀 2;预制体仍用 icon
加成 atk_buff1/2:type3 移速、type4 血量上限,均为 ×(1+万分比/10000)(如 1000=+10%)。上限变化后保持原血量比(100/70 → 120/84);出生时不播 怪物加血
实现 YingCampSummonHost + WaveSpawner.spawnExtraEnemyAtCell + MovementSystem.assignPathVia;营不挂普攻 Ability

Skill.atk_type=8 召唤

atk_para:怪物id,数量,间隔,出怪类型(1=施法处出现后跳入进路,2=自身周围出现)。非法第 4 段 warn,不猜默认。

出怪类型 逻辑 表现
1 施法处跳入 spawnExtraEnemyAtCell:施法格出生,横向最近进路汇入(不含出怪口);与口同行或没有则用普通怪出怪口跳跃落点。逻辑口仍记己方 port1 / 敌方 port2 召唤哮天犬 播完后,在预兆点上偏 45px 出现,缩放 0→0.5,停 1s 再抛物线跳出,停顿+跳跃期间放到 1 倍
2 自身周围 施法者格及邻格生成,阵营与施法者一致 unitSpawned.spawnPort=0,落在实体格,不出跳

杨戬主动(10176~10178)10001,1,0,1 → 施法处出 哮天犬(Monster.id=10001)再跳入进路。实现:SkillTableSummonExecutor。血量按召唤当时波次与波次怪同一公式,不锁开局第 1 波。

3. 代码结构

LevelWaveParser          ← 解析 + bosspro + 生成 WaveDef(双口)
ChapterLevelBuilder      ← 组装 LevelDef,wallHp 默认 3
WaveSpawner              ← port.playerId,口内 segment 队列;spawnExtraEnemy / spawnExtraEnemyAtCell
YingCampSummonHost       ← 营强化:营格水平进路出怪
SkillTableSummonExecutor ← atk_type=8(营地 / 自身周围)
UIBattleGame             ← 地图 + 拓扑 + Presenter + startCombat
UIPanelHome              ← pickRandomBattleLevelId 进关

数据流

  1. UIPanelHome.click_btnStart → 随机 Level
  2. GameController.enterBattle → 预载 → gg.battle.start
  3. ChapterLevelBuilder.build → LevelWaveParser.toWaveDefs
  4. UIBattleGame → loadMap → applyMapTopologyToSession(..., 'pvp')
  5. CocosBattleMonsterPresenter.bind;本机玩家第一次把数字放到地图后,或开局 10 秒仍未放置,startCombat → 双口出怪 + 寻路表现

4. 默认参数

  • 双方基地 HP:3(DEFAULT_BATTLE_WALL_HP)
  • 中间波结波:waveClearRequiresKillAll: false(出怪队列耗尽即下一波)
  • 最后一波:出完且场上进攻本机的怪清零 → endBattle(true) → BattleRuntime.gameOver(true) 弹 BattleSuccess
  • 敌方营地 wallHp 归零 → 胜利;己方归零 → 复活或失败
  • 到达攻击点:ReachGoalBaseDamageSystem 对 ownerId 槽 -1 并 despawn(默认 3 血)

5. 营地血条与胜负

  • ReachGoalBaseDamageSystem(priority 55):reachedGoal && hasAttackGoal → PlayerSlot.damageWall(1) → lifecycle.despawn
  • 血条预制体 battleGame/prefab/营地血条:挂在地图根上,对齐该图 spawnPoint_N(营地外观);己方在营下、敌方在营上,相对贴图 AABB 内收以免悬空;血量 下格数=当前血,宽=60/maxHp,扣血渐隐回收;血格与根节点同样打 Sorting2D,避免被血量底盖成空槽
  • spawnPoint_1 → 玩家 0(己营),spawnPoint_2 → 玩家 1(敌营)
  • 胜负:BattleRuntime 听 WallDamaged / BattleEnd;己方口怪不挡住最后一波清场胜利

6. 战斗预载(进关)

ResPkgBuilder 仅预载:

  • 地图 mapLayerN、出怪口
  • 本关怪物 + 状态特效 + 怪物血条
  • 营地血条 营地血条
  • battleHero 包全部英雄体(prefab/hero/)+ 全部攻效(prefab/ 根目录;后续迁入 prefab/skill/ 时在 BattleHeroResCollector 维护)

已移除老项目:芭蕉扇/围栏/机制包、局内飘字与受击特效 bulk 预载、按章节裁剪 HERO_ACTOR_RES。

7. 验收(出怪阶段)

  • 首页多次进关按当天 Const 31~37 地图池随机 Level.id
  • 玩家/AI 同时从出怪口 1/2 按表出怪
  • Boss 概率链符合 bosspro 规则
  • 同波小怪出完后排队出 Boss
  • 怪物沿本阵营路径移动
  • 皮肤来自 Monster.icon
  • 双方营地血条贴营地:己方在下、敌方在上;进关即 3 格绿条、格宽=20
  • 对方怪到达营地后消失且该营 -1 格(渐隐)
  • 己方营地扣完失败(或复活);敌方扣完胜利
  • 敌方波次怪全部击杀完胜利(己方口怪不挡住)