feat: 完成肉鸽回合制游戏核心玩法迭代
新增连杀系统、金币飞行特效、波次HUD、屏幕震动等表现功能,重构怪物刷出逻辑与难度动态调节,调整回合回血比例,优化游戏节奏与体验。 主要变更: 1. 调整回合回血比例从0.5到0.4,优化前期节奏 2. 新增连杀计数与奖励系统,支持5/10/20连杀触发对应表现 3. 实现怪物死亡掉落金币的抛物线飞行特效 4. 增加波次进度HUD,显示剩余怪物与全局回合进度 5. 新增屏幕震动工具与战斗横幅统一展示系统 6. 重构怪物刷出逻辑,支持按回合类型调整刷怪间隔,加入清场加速机制 7. 优化动态难度调节算法,增加滞回与指数平滑,避免难度突变 8. 新增Boss预警、登场事件与回合清屏事件,完善事件总线 9. 调整怪物数量阈值与回合倒计时档位,适配新的节奏设计
This commit is contained in:
@@ -22,7 +22,7 @@ import { Monster } from "../hero/Mon";
|
||||
import { smc } from "../common/SingletonModuleComp";
|
||||
import { GameEvent } from "../common/config/GameEvent";
|
||||
import { BoxSet, FacSet } from "../common/config/GameSet";
|
||||
import { spawningEngine, GeneratedMonster, TestModeConfig, MAX_MONSTERS, BATCH_COUNT, BATCH_INTERVAL } from "./RogueConfig";
|
||||
import { spawningEngine, GeneratedMonster, TestModeConfig, MAX_MONSTERS, BATCH_COUNT, BATCH_INTERVAL, getWaveType, SPAWN_INTERVAL_BY_TYPE } from "./RogueConfig";
|
||||
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
|
||||
import { MonMoveComp } from "../hero/MonMoveComp";
|
||||
|
||||
@@ -37,7 +37,7 @@ export class MissionMonCompComp extends CCComp {
|
||||
private static readonly MON_DROP_HEIGHT = 0;
|
||||
/** 怪物统一从右侧 X=400 出生点逐个刷出,随后向左推进 */
|
||||
private static readonly MON_SPAWN_X = 400;
|
||||
/** 逐个刷怪间隔(秒):保证怪物排成纵队,避免堆叠 */
|
||||
/** 逐个刷怪默认间隔(秒):保证怪物排成纵队,避免堆叠;运行时按回合类型查 SPAWN_INTERVAL_BY_TYPE 覆盖 */
|
||||
private static readonly MON_SPAWN_INTERVAL = 0.3;
|
||||
|
||||
/**
|
||||
@@ -88,6 +88,20 @@ export class MissionMonCompComp extends CCComp {
|
||||
private spawnQueue: GeneratedMonster[] = [];
|
||||
/** 逐个刷怪累计计时(秒) */
|
||||
private spawnTimer: number = 0;
|
||||
/** 当前回合的逐个刷怪间隔(秒),按回合类型查 SPAWN_INTERVAL_BY_TYPE */
|
||||
private spawnInterval: number = MissionMonCompComp.MON_SPAWN_INTERVAL;
|
||||
/** 当前批已刷出的怪物数(清场加速存活比例分母) */
|
||||
private batchReleasedCount: number = 0;
|
||||
/** 当前批是否已通过清场加速提前推进过(每批只触发一次) */
|
||||
private batchFastForwarded: boolean = false;
|
||||
/** 清场加速检测节流计时器(秒) */
|
||||
private aliveCheckTimer: number = 0;
|
||||
/** 本回合因清场加速累计节省的秒数(供 MissionComp 还原 DDA 判定口径,避免双重惩罚) */
|
||||
public waveEarlySkipTotal: number = 0;
|
||||
/** 清场加速触发阈值:当前批存活比例低于此值时提前推进(0.25 = 清掉 75%) */
|
||||
private static readonly BATCH_EARLY_RATIO = 0.25;
|
||||
/** 清场加速提前量(秒):等效 batchTimer 快进,保底批间隔不被瞬间叠爆 */
|
||||
private static readonly BATCH_EARLY_SKIP = 2.0;
|
||||
|
||||
// ======================== 生命周期 ========================
|
||||
|
||||
@@ -105,6 +119,10 @@ export class MissionMonCompComp extends CCComp {
|
||||
}
|
||||
smc.vmdata.mission_data.pending_mon_num = pendingCount;
|
||||
|
||||
// 场上怪物超阈值时暂停释放:冻结批次推进与逐个刷出计时(不推进计时器,恢复后从断点平滑续接)
|
||||
// 注意 pending 统计必须在 return 之前执行,保证回合结束检测(pending==0)语义不受暂停影响
|
||||
if (smc.mission.stop_spawn_mon) return;
|
||||
|
||||
// 分批释放:按 BATCH_INTERVAL 节奏推进批次
|
||||
if (this.isReleasing) {
|
||||
this.batchTimer += dt;
|
||||
@@ -112,12 +130,19 @@ export class MissionMonCompComp extends CCComp {
|
||||
this.batchTimer = 0;
|
||||
this.advanceBatch();
|
||||
}
|
||||
|
||||
// 清场加速:0.2s 节流检测当前批存活比例,清得快则快进批次计时(学 PvZ 血量阈值提前刷新)
|
||||
this.aliveCheckTimer += dt;
|
||||
if (this.aliveCheckTimer >= 0.2) {
|
||||
this.aliveCheckTimer = 0;
|
||||
this.checkBatchEarlyAdvance();
|
||||
}
|
||||
}
|
||||
|
||||
// 逐个刷怪:按 MON_SPAWN_INTERVAL 节奏从队列释放
|
||||
// 逐个刷怪:按 spawnInterval 节奏从队列释放
|
||||
if (this.spawnQueue.length > 0) {
|
||||
this.spawnTimer += dt;
|
||||
if (this.spawnTimer >= MissionMonCompComp.MON_SPAWN_INTERVAL) {
|
||||
if (this.spawnTimer >= this.spawnInterval) {
|
||||
this.spawnTimer = 0;
|
||||
const monData = this.spawnQueue.shift()!;
|
||||
const targetPosIndex = this.waveSpawnedCount % MissionMonCompComp.MON_POSITIONS.length;
|
||||
@@ -127,7 +152,7 @@ export class MissionMonCompComp extends CCComp {
|
||||
}
|
||||
}
|
||||
|
||||
start() {}
|
||||
start() { }
|
||||
|
||||
private setupWaveData(monsters: GeneratedMonster[]) {
|
||||
// 按批次分组
|
||||
@@ -167,6 +192,10 @@ export class MissionMonCompComp extends CCComp {
|
||||
this.isReleasing = false;
|
||||
this.spawnQueue = [];
|
||||
this.spawnTimer = 0;
|
||||
this.batchReleasedCount = 0;
|
||||
this.batchFastForwarded = false;
|
||||
this.aliveCheckTimer = 0;
|
||||
this.waveEarlySkipTotal = 0;
|
||||
|
||||
// 预生成第一回合数据以获取数量和 Boss 信息
|
||||
const monsters = spawningEngine.generateWave(this.currentWave);
|
||||
@@ -195,6 +224,9 @@ export class MissionMonCompComp extends CCComp {
|
||||
private onPhasePrepareEnd() {
|
||||
this.resetSlotSpawnData();
|
||||
|
||||
// 按回合类型确定本回合刷怪间隔(放松回合快速倾泻,压力回合稍慢聚焦)
|
||||
this.spawnInterval = SPAWN_INTERVAL_BY_TYPE[getWaveType(this.currentWave)] ?? MissionMonCompComp.MON_SPAWN_INTERVAL;
|
||||
|
||||
// 准备结束阶段:启动分批释放,
|
||||
// 第一批立即转入 spawnQueue,后续批次由 update 按 BATCH_INTERVAL 推进。
|
||||
this.startBatchRelease();
|
||||
@@ -238,10 +270,39 @@ export class MissionMonCompComp extends CCComp {
|
||||
for (const m of batch) {
|
||||
this.spawnQueue.push(m);
|
||||
}
|
||||
this.batchReleasedCount = batch.length;
|
||||
this.batchFastForwarded = false;
|
||||
batch.length = 0;
|
||||
|
||||
// 让首个怪物在下一帧立即刷出,避免额外延迟
|
||||
this.spawnTimer = MissionMonCompComp.MON_SPAWN_INTERVAL;
|
||||
this.spawnTimer = this.spawnInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清场加速检测:当前批已放完且存活比例 ≤ BATCH_EARLY_RATIO 时,快进批次计时器。
|
||||
* 只奖励"清得快"的 build(压缩批间垃圾时间),弱 build 清不完则不触发、不叠加压力。
|
||||
*/
|
||||
private checkBatchEarlyAdvance() {
|
||||
if (this.batchFastForwarded) return;
|
||||
if (this.currentBatch >= BATCH_COUNT - 1) return;
|
||||
if (this.spawnQueue.length > 0) return; // 本批还没放完,不判断
|
||||
if (this.batchReleasedCount <= 0) return;
|
||||
|
||||
let alive = 0;
|
||||
ecs.query(ecs.allOf(HeroAttrsComp)).forEach(e => {
|
||||
const a = e.get(HeroAttrsComp);
|
||||
if (a && a.fac === FacSet.MON && !a.is_dead) alive++;
|
||||
});
|
||||
// alive 含前几批残留,比例 clamp 防低估
|
||||
const aliveRatio = Math.min(1, alive / this.batchReleasedCount);
|
||||
if (aliveRatio <= MissionMonCompComp.BATCH_EARLY_RATIO) {
|
||||
this.batchFastForwarded = true;
|
||||
this.batchTimer += MissionMonCompComp.BATCH_EARLY_SKIP;
|
||||
this.waveEarlySkipTotal += MissionMonCompComp.BATCH_EARLY_SKIP;
|
||||
smc.vmdata.mission_data.wave_early_skip = this.waveEarlySkipTotal;
|
||||
mLogger.log(this.debugMode, 'MissionMonComp',
|
||||
`[EarlyAdvance] batch=${this.currentBatch} alive=${alive}/${this.batchReleasedCount},快进 ${MissionMonCompComp.BATCH_EARLY_SKIP}s`);
|
||||
}
|
||||
}
|
||||
|
||||
// ======================== 槽位管理 ========================
|
||||
@@ -264,6 +325,11 @@ export class MissionMonCompComp extends CCComp {
|
||||
this.isReleasing = false;
|
||||
this.currentBatch = 0;
|
||||
this.batchTimer = 0;
|
||||
this.batchReleasedCount = 0;
|
||||
this.batchFastForwarded = false;
|
||||
this.aliveCheckTimer = 0;
|
||||
this.waveEarlySkipTotal = 0;
|
||||
smc.vmdata.mission_data.wave_early_skip = 0;
|
||||
}
|
||||
|
||||
// ======================== 怪物生成 ========================
|
||||
@@ -292,6 +358,11 @@ export class MissionMonCompComp extends CCComp {
|
||||
|
||||
mon.load(spawnPos, scale, monData.uuid, monData.isBoss, landingY, monLv, posIndex);
|
||||
|
||||
// oops.message 全局事件总线:Boss 登场(震屏/音效由表现层消费)
|
||||
if (monData.isBoss) {
|
||||
oops.message.dispatchEvent(GameEvent.BossSpawn, { pos: spawnPos.clone() });
|
||||
}
|
||||
|
||||
const move = mon.get(MonMoveComp);
|
||||
if (move) {
|
||||
move.spawnOrder = this.globalSpawnOrder;
|
||||
@@ -307,5 +378,5 @@ export class MissionMonCompComp extends CCComp {
|
||||
}
|
||||
|
||||
/** ECS 组件移除时触发 */
|
||||
reset() {}
|
||||
reset() { }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user