feat(刷怪): 添加特殊怪物定时刷怪机制
- 在 MissionComp 中添加特殊刷怪检查,根据时间表触发精英/Boss - MissionMonComp 监听刷怪事件,将特殊怪物插入队列头部优先生成 - 调整刷怪配置,移除随机刷怪中的精英/Boss,改为固定时间生成 - 降低同屏怪物数量,提高单体质量,优化游戏节奏
This commit is contained in:
@@ -4,7 +4,7 @@ import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/modu
|
|||||||
import { smc } from "../common/SingletonModuleComp";
|
import { smc } from "../common/SingletonModuleComp";
|
||||||
import { oops } from "../../../../extensions/oops-plugin-framework/assets/core/Oops";
|
import { oops } from "../../../../extensions/oops-plugin-framework/assets/core/Oops";
|
||||||
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
|
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
|
||||||
import { MonsterCost, MonType, calculateMonsterGold, getLevelExp, calculateMonsterExp } from "./RogueConfig";
|
import { MonsterCost, MonType, calculateMonsterGold, getLevelExp, calculateMonsterExp, SpecialMonsterSchedule } from "./RogueConfig";
|
||||||
import { GameEvent } from "../common/config/GameEvent";
|
import { GameEvent } from "../common/config/GameEvent";
|
||||||
import { HeroViewComp } from "../hero/HeroViewComp";
|
import { HeroViewComp } from "../hero/HeroViewComp";
|
||||||
import { UIID } from "../common/config/GameUIConfig";
|
import { UIID } from "../common/config/GameUIConfig";
|
||||||
@@ -40,6 +40,10 @@ export class MissionComp extends CCComp {
|
|||||||
gold:0,
|
gold:0,
|
||||||
diamond:0
|
diamond:0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 记录已触发的特殊刷怪索引
|
||||||
|
private spawnedSpecialIndices: Set<number> = new Set();
|
||||||
|
|
||||||
onLoad(){
|
onLoad(){
|
||||||
this.on(GameEvent.MissionStart,this.mission_start,this)
|
this.on(GameEvent.MissionStart,this.mission_start,this)
|
||||||
this.on(GameEvent.MonDead,this.do_mon_dead,this)
|
this.on(GameEvent.MonDead,this.do_mon_dead,this)
|
||||||
@@ -58,9 +62,26 @@ export class MissionComp extends CCComp {
|
|||||||
if(smc.mission.stop_mon_action) return
|
if(smc.mission.stop_mon_action) return
|
||||||
smc.vmdata.mission_data.fight_time+=dt
|
smc.vmdata.mission_data.fight_time+=dt
|
||||||
smc.vmdata.mission_data.time-=dt
|
smc.vmdata.mission_data.time-=dt
|
||||||
|
|
||||||
|
// 检查特殊刷怪时间
|
||||||
|
this.checkSpecialSpawns(smc.vmdata.mission_data.fight_time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private checkSpecialSpawns(fightTime: number) {
|
||||||
|
SpecialMonsterSchedule.forEach((item, index) => {
|
||||||
|
if (!this.spawnedSpecialIndices.has(index) && fightTime >= item.time) {
|
||||||
|
this.spawnedSpecialIndices.add(index);
|
||||||
|
console.log(`[MissionComp] 触发特殊刷怪: ${item.desc}`);
|
||||||
|
oops.message.dispatchEvent("SpawnSpecialMonster", {
|
||||||
|
uuid: item.uuid,
|
||||||
|
type: item.type,
|
||||||
|
level: item.level
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 升级奖励触发
|
// 升级奖励触发
|
||||||
onLevelUp(event: string, args: any) {
|
onLevelUp(event: string, args: any) {
|
||||||
console.log(`[MissionComp] 英雄升级到 ${args.lv} 级!`);
|
console.log(`[MissionComp] 英雄升级到 ${args.lv} 级!`);
|
||||||
@@ -249,6 +270,7 @@ do_ad(){
|
|||||||
smc.vmdata.mission_data.time=15*60
|
smc.vmdata.mission_data.time=15*60
|
||||||
this.rewards=[] // 改为数组,用于存储掉落物品列表
|
this.rewards=[] // 改为数组,用于存储掉落物品列表
|
||||||
this.revive_times = 1; // 每次任务开始重置复活次数
|
this.revive_times = 1; // 每次任务开始重置复活次数
|
||||||
|
this.spawnedSpecialIndices.clear(); // 重置特殊刷怪记录
|
||||||
|
|
||||||
// 重置英雄数据,确保新一局是初始状态
|
// 重置英雄数据,确保新一局是初始状态
|
||||||
smc.vmdata.hero = {
|
smc.vmdata.hero = {
|
||||||
|
|||||||
@@ -43,6 +43,32 @@ export class MissionMonCompComp extends CCComp {
|
|||||||
onLoad(){
|
onLoad(){
|
||||||
this.on(GameEvent.FightReady,this.fight_ready,this)
|
this.on(GameEvent.FightReady,this.fight_ready,this)
|
||||||
this.on(GameEvent.NewWave,this.fight_ready,this)
|
this.on(GameEvent.NewWave,this.fight_ready,this)
|
||||||
|
// 监听特殊刷怪事件 (精英/Boss)
|
||||||
|
this.on("SpawnSpecialMonster", this.onSpawnSpecialMonster, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理特殊刷怪事件
|
||||||
|
* @param event 事件名
|
||||||
|
* @param args 参数 { uuid, type, level, position?, buffs? }
|
||||||
|
*/
|
||||||
|
private onSpawnSpecialMonster(event: string, args: any) {
|
||||||
|
if (!args) return;
|
||||||
|
console.log(`[MissionMonComp] 收到特殊刷怪指令:`, args);
|
||||||
|
|
||||||
|
// 插入队列头部,优先生成
|
||||||
|
this.MonQueue.unshift({
|
||||||
|
uuid: args.uuid,
|
||||||
|
position: args.position !== undefined ? args.position : 2, // 默认中间
|
||||||
|
type: args.type,
|
||||||
|
level: args.level,
|
||||||
|
buffs: args.buffs || []
|
||||||
|
});
|
||||||
|
|
||||||
|
// 让刷怪计时器立即满足条件,以便尽快生成
|
||||||
|
// 注意:不直接调用 spawnNextMonster 是为了保持 update 循环的一致性
|
||||||
|
const config = getRogueConfig();
|
||||||
|
this.spawnTimer = config.spawnInterval + 0.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 视图层逻辑代码分离演示 */
|
/** 视图层逻辑代码分离演示 */
|
||||||
|
|||||||
@@ -92,16 +92,25 @@ export interface IRogueGlobalConfig {
|
|||||||
* 默认配置
|
* 默认配置
|
||||||
*/
|
*/
|
||||||
export const DefaultRogueConfig: IRogueGlobalConfig = {
|
export const DefaultRogueConfig: IRogueGlobalConfig = {
|
||||||
maxMonsterCount: 10, // 默认同屏10只 (原25) - 追求极致质量
|
maxMonsterCount: 5, // 默认同屏5只 - 降低数量,提高单体质量
|
||||||
spawnLogicInterval: 1.0, // 每秒计算一次
|
spawnLogicInterval: 1.0, // 每秒计算一次
|
||||||
spawnInterval: 2.5, // 队列出怪间隔2.5秒 (原1.2) - 降低频率适配总量
|
spawnInterval: 2.0, // 队列出怪间隔
|
||||||
baseBudget: 1.0, // 基础预算 (原2.5) - 降低产出适配总量
|
baseBudget: 1.0, // 基础预算
|
||||||
timeDifficultyFactor: 0.5, // 每分钟增加50%预算
|
timeDifficultyFactor: 0.5, // 每分钟增加50%预算
|
||||||
survivalHpThreshold: 0.4, // 40%血量触发保护
|
survivalHpThreshold: 0.4, // 40%血量触发保护
|
||||||
survivalBudgetMultiplier: 0.7, // 保护时预算打7折
|
survivalBudgetMultiplier: 0.7, // 保护时预算打7折
|
||||||
maxSpawnPerLogic: 2 // 单次最多生成2只 (原3)
|
maxSpawnPerLogic: 2 // 单次最多生成2只
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 精英怪和Boss刷新时间配置 (时间单位: 秒)
|
||||||
|
export const SpecialMonsterSchedule = [
|
||||||
|
{ time: 60, uuid: 5601, type: MonType.ELITE, level: 5, desc: "1分钟: 精英自爆兵" },
|
||||||
|
{ time: 180, uuid: 5601, type: MonType.ELITE, level: 10, desc: "3分钟: 精英自爆兵" },
|
||||||
|
{ time: 300, uuid: 5701, type: MonType.BOSS, level: 15, desc: "5分钟: 兽人首领" },
|
||||||
|
{ time: 600, uuid: 5701, type: MonType.BOSS, level: 25, desc: "10分钟: 兽人首领" },
|
||||||
|
{ time: 900, uuid: 5701, type: MonType.BOSS, level: 30, desc: "15分钟: 最终Boss" }
|
||||||
|
];
|
||||||
|
|
||||||
// 当前配置实例
|
// 当前配置实例
|
||||||
let currentConfig: IRogueGlobalConfig = { ...DefaultRogueConfig };
|
let currentConfig: IRogueGlobalConfig = { ...DefaultRogueConfig };
|
||||||
|
|
||||||
@@ -157,16 +166,6 @@ export function calculateBudget(timeInSeconds: number, heroHpRatio: number = 1.0
|
|||||||
export function generateMonstersFromBudget(timeInSeconds: number, heroHpRatio: number = 1.0): IMonsConfig[] {
|
export function generateMonstersFromBudget(timeInSeconds: number, heroHpRatio: number = 1.0): IMonsConfig[] {
|
||||||
const config = getRogueConfig();
|
const config = getRogueConfig();
|
||||||
|
|
||||||
// 15分钟后只生成Boss
|
|
||||||
if (timeInSeconds >= 15 * 60) {
|
|
||||||
return [{
|
|
||||||
uuid: 5701,
|
|
||||||
type: MonType.BOSS,
|
|
||||||
level: Math.floor(timeInSeconds / 60),
|
|
||||||
position: 2
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
const budget = calculateBudget(timeInSeconds, heroHpRatio);
|
const budget = calculateBudget(timeInSeconds, heroHpRatio);
|
||||||
const weights = getSpawnWeights(timeInSeconds);
|
const weights = getSpawnWeights(timeInSeconds);
|
||||||
const monsters: IMonsConfig[] = [];
|
const monsters: IMonsConfig[] = [];
|
||||||
@@ -193,9 +192,9 @@ export function generateMonstersFromBudget(timeInSeconds: number, heroHpRatio: n
|
|||||||
if (currentBudget >= cost) {
|
if (currentBudget >= cost) {
|
||||||
currentBudget -= cost;
|
currentBudget -= cost;
|
||||||
|
|
||||||
|
// 随机刷怪只生成普通怪,精英和Boss由固定时间控制
|
||||||
let type = MonType.NORMAL;
|
let type = MonType.NORMAL;
|
||||||
if (uuid === 5701) type = MonType.BOSS;
|
// 即使随机到了高Cost怪,在这里也只按普通怪处理,或者在配置中彻底移除高Cost怪
|
||||||
else if (MonsterCost[uuid] >= 10) type = MonType.ELITE;
|
|
||||||
|
|
||||||
monsters.push({
|
monsters.push({
|
||||||
uuid: uuid,
|
uuid: uuid,
|
||||||
@@ -217,6 +216,7 @@ export function generateMonstersFromBudget(timeInSeconds: number, heroHpRatio: n
|
|||||||
* @param stage 当前波次
|
* @param stage 当前波次
|
||||||
* @param timeInSeconds 游戏进行时间(秒)
|
* @param timeInSeconds 游戏进行时间(秒)
|
||||||
* @returns 波次因子 (0-1之间,15分钟时达到最大)
|
* @returns 波次因子 (0-1之间,15分钟时达到最大)
|
||||||
|
* @returns 波次因子 (0-1之间,15分钟时达到最大)
|
||||||
*/
|
*/
|
||||||
function calculateWaveFactor(stage: number, timeInSeconds: number = 0): number {
|
function calculateWaveFactor(stage: number, timeInSeconds: number = 0): number {
|
||||||
const MAX_GAME_TIME = 15 * 60; // 15分钟 = 900秒
|
const MAX_GAME_TIME = 15 * 60; // 15分钟 = 900秒
|
||||||
@@ -428,17 +428,21 @@ function getSpawnWeights(timeInSeconds: number): SpawnWeight[] {
|
|||||||
{ uuid: 5301, weight: 30 }
|
{ uuid: 5301, weight: 30 }
|
||||||
];
|
];
|
||||||
} else if (minutes < 14) {
|
} else if (minutes < 14) {
|
||||||
// 8-14min: 阵地博弈 - 40% 战士, 30% 刺客, 20% 攻城/治疗/精英
|
// 8-14min: 阵地博弈 - 移除精英怪,只保留普通怪
|
||||||
return [
|
return [
|
||||||
{ uuid: 5201, weight: 40 },
|
{ uuid: 5201, weight: 40 },
|
||||||
{ uuid: 5301, weight: 30 },
|
{ uuid: 5301, weight: 30 },
|
||||||
{ uuid: 5401, weight: 10 },
|
{ uuid: 5401, weight: 15 },
|
||||||
{ uuid: 5603, weight: 10 },
|
{ uuid: 5603, weight: 15 }
|
||||||
{ uuid: 5701, weight: 10 }
|
|
||||||
];
|
];
|
||||||
} else {
|
} else {
|
||||||
// 15min: 剧情杀/决战 - 100% Boss
|
// 15min+: 混合兵种,Boss由固定时间控制
|
||||||
return [{ uuid: 5701, weight: 100 }];
|
return [
|
||||||
|
{ uuid: 5201, weight: 30 },
|
||||||
|
{ uuid: 5301, weight: 30 },
|
||||||
|
{ uuid: 5401, weight: 20 },
|
||||||
|
{ uuid: 5603, weight: 20 }
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user