Compare commits
3 Commits
50c9205e0f
...
ab32b0e09d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab32b0e09d | ||
|
|
dc67f42a33 | ||
|
|
04a77ac60c |
@@ -358,11 +358,13 @@ export class SingletonModuleComp extends ecs.Comp {
|
||||
*/
|
||||
public syncStageProgressToView(): void {
|
||||
const p = this.data.stage_progress;
|
||||
this.vmdata.stage_progress = {
|
||||
chapter: p?.chapter ?? 1,
|
||||
stage: p?.stage ?? 1,
|
||||
section: p?.section ?? 1,
|
||||
};
|
||||
// 就地更新字段而非整体替换对象:oops VM(JsonOb)只通知被赋值属性的精确路径,
|
||||
// 整体替换仅派发 VC:data.stage_progress,不会触发 HUD 绑定的
|
||||
// data.stage_progress.section 等嵌套末端路径刷新,导致进度显示停留在老节
|
||||
const view = this.vmdata.stage_progress;
|
||||
view.chapter = p?.chapter ?? 1;
|
||||
view.stage = p?.stage ?? 1;
|
||||
view.section = p?.section ?? 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,8 +30,8 @@ export const BOSS_MUL = 3.0;
|
||||
export const NORMAL_MON_COUNT = 9;
|
||||
/** 普通关开局立即刷出数量 */
|
||||
export const NORMAL_FIRST_SPAWN = 3;
|
||||
/** 普通关后续刷怪间隔(秒) */
|
||||
export const NORMAL_SPAWN_INTERVAL = 5;
|
||||
/** 普通关后续刷怪间隔(秒):前 3 只立即刷,后续每 2s 刷 1 只 */
|
||||
export const NORMAL_SPAWN_INTERVAL = 2;
|
||||
/** 精英关精英数量 */
|
||||
export const ELITE_COUNT = 3;
|
||||
/** Boss 关精英数量 */
|
||||
|
||||
@@ -28,6 +28,10 @@ export class Monster extends ecs.Entity {
|
||||
static readonly MAX_POOL_SIZE: number = 12;
|
||||
/** 所有路径合计池容量上限 */
|
||||
static readonly MAX_POOL_TOTAL: number = 60;
|
||||
/** 落地震退范围(码):怪物砸地时击退落点范围内的英雄 */
|
||||
static readonly LANDING_SHOCK_RANGE: number = 100;
|
||||
/** 英雄实体查询匹配器(惰性缓存,落地震退用) */
|
||||
private static heroMatcher: any = null;
|
||||
|
||||
/** 计算当前所有对象池节点总量 */
|
||||
private static totalPoolSize(): number {
|
||||
@@ -279,6 +283,11 @@ export class Monster extends ecs.Entity {
|
||||
collider.apply();
|
||||
}
|
||||
|
||||
// 高处砸地:震退落点范围内的英雄
|
||||
if (dropDistance > 0) {
|
||||
this.applyLandingShock(pos.x);
|
||||
}
|
||||
|
||||
// 落地后触发 call 技能
|
||||
SkillTriggerHelper.trigger(SkillTriggerType.Call, model, view);
|
||||
};
|
||||
@@ -302,6 +311,33 @@ export class Monster extends ecs.Entity {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 落地震退:怪物从高处砸地时,击退落点 LANDING_SHOCK_RANGE 范围内的英雄
|
||||
* Why: 复用 HeroAtkSystem 的击退通道(MoveComp.knockbackVelocity),
|
||||
* 由 MoveSystem 统一指数衰减位移并受 HERO 左边界钳制,不会把英雄推出屏幕
|
||||
* @param posX 落点 X 坐标
|
||||
*/
|
||||
private applyLandingShock(posX: number) {
|
||||
if (!Monster.heroMatcher) {
|
||||
Monster.heroMatcher = ecs.allOf(HeroAttrsComp);
|
||||
}
|
||||
// 击退初速度 = 距离 × 16(0.1s 时间常数衰减,总位移约等于距离),与 HeroAtkSystem 一致
|
||||
const knockbackSpeed = FightSet.BACK_RANG * 16;
|
||||
ecs.query(Monster.heroMatcher).forEach(entity => {
|
||||
const attrs = entity.get(HeroAttrsComp);
|
||||
const view = entity.get(HeroViewComp);
|
||||
if (!attrs || !view || attrs.is_dead || attrs.fac !== FacSet.HERO) return;
|
||||
if (!view.node || !view.node.isValid) return;
|
||||
// 仅按 X 轴距离判定(纵向战场无意义)
|
||||
if (Math.abs(view.node.position.x - posX) > Monster.LANDING_SHOCK_RANGE) return;
|
||||
const move = entity.get(MoveComp);
|
||||
if (move) {
|
||||
// 英雄被击退方向为负(向左后退),叠加而非覆盖,避免打断已有击退
|
||||
move.knockbackVelocity -= knockbackSpeed;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** 重置入口:复用 destroy 的释放流程 */
|
||||
reset() {
|
||||
super.destroy();
|
||||
|
||||
@@ -321,22 +321,18 @@ export class MissionComp extends CCComp {
|
||||
return MissionComp.COUNTDOWN_NORMAL;
|
||||
}
|
||||
|
||||
/** 更新倒计时:写入 vmdata 驱动 VMLabel 显示("下一节 Xs") */
|
||||
/** 更新倒计时 UI(显示剩余秒数) */
|
||||
private updateCountdownUI(force: boolean = false) {
|
||||
if (!this.isWaveCountdown) return;
|
||||
const remain = Math.max(0, Math.ceil(this.waveCountdown));
|
||||
if (!force && remain === this.lastTimeSecond) return;
|
||||
this.lastTimeSecond = remain;
|
||||
|
||||
// MVVM:借用 section 字段承载倒计时秒数,VMLabel 模板自动刷新
|
||||
smc.vmdata.stage_progress.section = remain;
|
||||
}
|
||||
|
||||
/** 结束回合间倒计时(恢复 vmdata 进度镜像,VMLabel 回到"第 X 节"显示) */
|
||||
/** 结束回合间倒计时 */
|
||||
private stopWaveCountdown() {
|
||||
this.isWaveCountdown = false;
|
||||
this.lastTimeSecond = -1;
|
||||
smc.syncStageProgressToView();
|
||||
}
|
||||
|
||||
// ======================== 奖励与广告 ========================
|
||||
@@ -479,9 +475,6 @@ export class MissionComp extends CCComp {
|
||||
this.playTooltipAnim(phaseName);
|
||||
}
|
||||
|
||||
// 阶段文本由 VMLabel 绑定 vmdata.stage_progress 自动刷新,此处仅同步数据
|
||||
smc.syncStageProgressToView();
|
||||
|
||||
// 重置状态机的计时器
|
||||
if (this.PhaseTime) {
|
||||
this.PhaseTime.reset();
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* 职责:
|
||||
* 1. 按小节配置刷怪:监听 SectionStart 事件,从 StageSpawningEngine 获取怪物列表。
|
||||
* 2. 普通关:前 3 只立即刷,后续每 5s 刷 1 只(共 9 只)。
|
||||
* 2. 普通关:前 3 只立即刷,后续每 2s 刷 1 只(共 9 只),均从高处掉落入场。
|
||||
* 3. 精英关:3 只精英同时刷出。
|
||||
* 4. Boss 关:2 精英先刷,Boss 延迟 1s 刷出。
|
||||
* 5. 维护小节刷怪计数,供 MissionComp 检测小节结束。
|
||||
@@ -36,8 +36,8 @@ const { ccclass, property } = _decorator;
|
||||
export class MissionMonCompComp extends CCComp {
|
||||
// ======================== 常量 ========================
|
||||
|
||||
/** 怪物出生掉落高度 */
|
||||
private static readonly MON_DROP_HEIGHT = 0;
|
||||
/** 怪物出生掉落高度(码):从高处砸落入场,落地时震退范围内英雄 */
|
||||
private static readonly MON_DROP_HEIGHT = 400;
|
||||
|
||||
/**
|
||||
* 怪物类型 → 编队优先级(与英雄 HRole 枚举值升序一致):
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* 游戏机制:
|
||||
* - 玩家线性推进 1 章 10 关 × 每关 10 小节,进度精确到小节并持久化。
|
||||
* - 普通关(1~4, 6~9):9 只小怪,前 3 只立即刷,后续每 5s 刷 1 只。
|
||||
* - 普通关(1~4, 6~9):9 只小怪,前 3 只立即刷,后续每 2s 刷 1 只。
|
||||
* - 精英关(5):3 只精英同时刷出。
|
||||
* - Boss 关(10):2 精英先刷,Boss 延迟 1s 刷出。
|
||||
* - 怪物属性 = 基础 × 0.8 × (1 + 0.05×(lv-1)) × 类型倍率(精英1.5 / Boss3.0)。
|
||||
|
||||
Reference in New Issue
Block a user