feat: 添加击晕状态相关功能

1. 新增击晕概率、抗性属性配置与组件字段
2. 实现击晕判定逻辑与视图特效播放
3. 增加击晕时技能CD暂停清零的处理
4. 配置默认击晕持续时间为2秒
This commit is contained in:
panFD
2026-06-12 21:34:39 +08:00
parent 3ea1a4d44c
commit 44ce6cd30c
7 changed files with 65 additions and 2 deletions

View File

@@ -35,6 +35,7 @@ export enum FightSet {
FiIGHT_TIME = 30,//战斗时间 FiIGHT_TIME = 30,//战斗时间
// BACK_CHANCE=40,//击退概率 // BACK_CHANCE=40,//击退概率
FROST_TIME = 3,//冰冻时间 FROST_TIME = 3,//冰冻时间
STUN_TIME = 2,//击晕时间
SKILL_CAST_DELAY = 0.15, SKILL_CAST_DELAY = 0.15,
CSKILL_START_X = -340, CSKILL_START_X = -340,
CSKILL_START_Y = 30, CSKILL_START_Y = 30,

View File

@@ -29,6 +29,8 @@ export enum Attrs {
// ==================== 特殊效果属性 ==================== // ==================== 特殊效果属性 ====================
freeze_chance = "freeze_chance", // 冰冻概率 freeze_chance = "freeze_chance", // 冰冻概率
freeze_res = "freeze_res", // 冰冻抗性 freeze_res = "freeze_res", // 冰冻抗性
stun_chance = "stun_chance", // 击晕概率
stun_res = "stun_res", // 击晕抗性
knockback_chance = "knockback_chance", // 击退概率 knockback_chance = "knockback_chance", // 击退概率
knockback_distance = "knockback_distance", // 击退距离强化 knockback_distance = "knockback_distance", // 击退距离强化
knockback_res = "knockback_res", // 击退抗性 knockback_res = "knockback_res", // 击退抗性

View File

@@ -184,17 +184,31 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
const freezeChance = (damageEvent.Attrs[Attrs.freeze_chance] || 0) - (TAttrsComp.freeze_res || 0); const freezeChance = (damageEvent.Attrs[Attrs.freeze_chance] || 0) - (TAttrsComp.freeze_res || 0);
const isFrost = !TAttrsComp.isFrost() && this.checkChance(freezeChance); const isFrost = !TAttrsComp.isFrost() && this.checkChance(freezeChance);
// 击晕判定
const stunChance = (damageEvent.Attrs[Attrs.stun_chance] || 0) - (TAttrsComp.stun_res || 0);
const isStun = !TAttrsComp.isStun() && this.checkChance(stunChance);
// 击退判定 // 击退判定
const knockbackChance = (damageEvent.Attrs[Attrs.knockback_chance] || 0) - (TAttrsComp.knockback_res || 0); const knockbackChance = (damageEvent.Attrs[Attrs.knockback_chance] || 0) - (TAttrsComp.knockback_res || 0);
const isKnockback = this.checkChance(knockbackChance); const isKnockback = this.checkChance(knockbackChance);
// ✅ 触发视图层表现(伤害数字、受击动画、冰冻、击退) // ✅ 触发视图层表现(伤害数字、受击动画、冰冻、击晕、击退)
if (targetView) { if (targetView) {
targetView.do_atked(damage, isCrit, damageEvent.s_uuid, false); targetView.do_atked(damage, isCrit, damageEvent.s_uuid, false);
targetView.playEnd(skillConf.endAnm); targetView.playEnd(skillConf.endAnm);
if (isFrost) { if (isFrost) {
TAttrsComp.toFrost(); TAttrsComp.toFrost();
targetView.in_iced(TAttrsComp.frost_end_time); targetView.in_iced(TAttrsComp.frost_end_time);
if (damageEvent.Attrs.fac === FacSet.HERO) {
smc.vmdata.scores.freeze_count++;
}
}
if (isStun) {
TAttrsComp.toStun();
targetView.in_stun(TAttrsComp.stun_end_time);
if (damageEvent.Attrs.fac === FacSet.HERO) {
smc.vmdata.scores.stun_count++;
}
} }
if (isKnockback) { if (isKnockback) {
targetView.back(damageEvent.Attrs[Attrs.knockback_distance] || 0); targetView.back(damageEvent.Attrs[Attrs.knockback_distance] || 0);

View File

@@ -49,6 +49,8 @@ export class HeroAttrsComp extends ecs.Comp {
critical_res: number = 0; // 暴击抗性 critical_res: number = 0; // 暴击抗性
freeze_chance: number = 0; // 冰冻概率 freeze_chance: number = 0; // 冰冻概率
freeze_res: number = 0; // 冰冻抗性 freeze_res: number = 0; // 冰冻抗性
stun_chance: number = 0; // 击晕概率
stun_res: number = 0; // 击晕抗性
knockback_chance: number = 0; // 击退概率 knockback_chance: number = 0; // 击退概率
knockback_distance: number = 0; // 击退距离强化 knockback_distance: number = 0; // 击退距离强化
knockback_res: number = 0; // 击退抗性 knockback_res: number = 0; // 击退抗性
@@ -61,6 +63,7 @@ export class HeroAttrsComp extends ecs.Comp {
frost_end_time: number = 0; frost_end_time: number = 0;
stun_end_time: number = 0;
boom: boolean = false; // 自爆怪 boom: boolean = false; // 自爆怪
@@ -100,6 +103,7 @@ export class HeroAttrsComp extends ecs.Comp {
*/ */
initAttrs() { initAttrs() {
this.frost_end_time = 0; this.frost_end_time = 0;
this.stun_end_time = 0;
} }
/*******************基础属性管理********************/ /*******************基础属性管理********************/
@@ -163,10 +167,34 @@ export class HeroAttrsComp extends ecs.Comp {
this.frost_end_time = Math.max(this.frost_end_time, frostTime); this.frost_end_time = Math.max(this.frost_end_time, frostTime);
} }
toStun(time: number=1) {
const stunTime = FightSet.STUN_TIME * time;
this.stun_end_time = Math.max(this.stun_end_time, stunTime);
// 击晕时 CD 清零
for (const key in this.skills) {
const skill = this.skills[key];
if (skill) {
skill.ccd = 0;
}
}
}
updateCD(dt: number){ updateCD(dt: number){
// 如果处于冰冻状态,则技能 CD 暂停刷新 // 如果处于冰冻状态,则技能 CD 暂停刷新
if (this.isFrost()) return; if (this.isFrost()) return;
// 如果处于击晕状态,则技能 CD 暂停刷新(且保持清零状态)
if (this.isStun()) {
for (const key in this.skills) {
const skill = this.skills[key];
if (skill) {
skill.ccd = 0;
}
}
return;
}
for (const key in this.skills) { for (const key in this.skills) {
const skill = this.skills[key]; const skill = this.skills[key];
if (!skill) continue; if (!skill) continue;
@@ -185,6 +213,9 @@ export class HeroAttrsComp extends ecs.Comp {
isFrost(): boolean { isFrost(): boolean {
return this.frost_end_time > 0 return this.frost_end_time > 0
} }
isStun(): boolean {
return this.stun_end_time > 0
}
getSkillLevel(skillId: number): number { getSkillLevel(skillId: number): number {
if (!skillId) return 0; if (!skillId) return 0;
return this.skills[skillId]?.lv ?? 0; return this.skills[skillId]?.lv ?? 0;
@@ -352,6 +383,8 @@ export class HeroAttrsComp extends ecs.Comp {
this.critical_res = 0; this.critical_res = 0;
this.freeze_chance = 0; this.freeze_chance = 0;
this.freeze_res = 0; this.freeze_res = 0;
this.stun_chance = 0;
this.stun_res = 0;
this.knockback_chance = 0; this.knockback_chance = 0;
this.knockback_distance = 0; this.knockback_distance = 0;
this.knockback_res = 0; this.knockback_res = 0;
@@ -363,6 +396,7 @@ export class HeroAttrsComp extends ecs.Comp {
this.boom = false; this.boom = false;
this.frost_end_time = 0; this.frost_end_time = 0;
this.stun_end_time = 0;
// 重置技能距离缓存 // 重置技能距离缓存
this.maxSkillDistance = 0; this.maxSkillDistance = 0;
@@ -406,7 +440,12 @@ export class HeroBuffSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
attrsComp.frost_end_time = 0; attrsComp.frost_end_time = 0;
} }
} }
if(attrsComp.stun_end_time > 0){
attrsComp.stun_end_time -= 0.1;
if(attrsComp.stun_end_time <= 0){
attrsComp.stun_end_time = 0;
}
}
} }
void e; void e;
} }

View File

@@ -308,6 +308,11 @@ export class HeroViewComp extends CCComp {
this.spawnTimedFx("game/skill/buff/iced", this.node, t); this.spawnTimedFx("game/skill/buff/iced", this.node, t);
} }
/** 击晕特效 */
in_stun(t: number = 1) {
this.spawnTimedFx("game/skill/buff/stun", this.node, t);
}
/** 技能提示 */ /** 技能提示 */
private tooltip(type: number = 1, value: string = "", s_uuid: number = 1001, y: number = 50) { private tooltip(type: number = 1, value: string = "", s_uuid: number = 1001, y: number = 50) {
let pos = v3(0, 60); let pos = v3(0, 60);

View File

@@ -110,6 +110,7 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
mockAttrs.ap = highestAp; mockAttrs.ap = highestAp;
mockAttrs.critical = 0; mockAttrs.critical = 0;
mockAttrs.freeze_chance = 0; mockAttrs.freeze_chance = 0;
mockAttrs.stun_chance = 0;
mockAttrs.puncture_chance = 0; mockAttrs.puncture_chance = 0;
mockAttrs.fac = FacSet.HERO; mockAttrs.fac = FacSet.HERO;
mockAttrs.type = HType.Long; // 假定为远程,拥有较长索敌范围 mockAttrs.type = HType.Long; // 假定为远程,拥有较长索敌范围

View File

@@ -212,6 +212,7 @@ export class Skill extends ecs.Entity {
sDataCom.Attrs[Attrs.critical] = cAttrsComp.getRuntimeCritical() + sCrt; sDataCom.Attrs[Attrs.critical] = cAttrsComp.getRuntimeCritical() + sCrt;
sDataCom.Attrs[Attrs.critical_damage] = cAttrsComp.getRuntimeCritDamageBonus(); sDataCom.Attrs[Attrs.critical_damage] = cAttrsComp.getRuntimeCritDamageBonus();
sDataCom.Attrs[Attrs.freeze_chance] = cAttrsComp.getRuntimeFreezeChance() + sFrz; sDataCom.Attrs[Attrs.freeze_chance] = cAttrsComp.getRuntimeFreezeChance() + sFrz;
sDataCom.Attrs[Attrs.stun_chance] = cAttrsComp.stun_chance || 0;
sDataCom.Attrs[Attrs.knockback_chance] = cAttrsComp.knockback_chance || 0; sDataCom.Attrs[Attrs.knockback_chance] = cAttrsComp.knockback_chance || 0;
sDataCom.Attrs[Attrs.knockback_distance] = cAttrsComp.knockback_distance || 0; sDataCom.Attrs[Attrs.knockback_distance] = cAttrsComp.knockback_distance || 0;
sDataCom.Attrs[Attrs.puncture_chance] = cAttrsComp.getRuntimePunctureChance(); // 初始化携带施法者的穿透概率 sDataCom.Attrs[Attrs.puncture_chance] = cAttrsComp.getRuntimePunctureChance(); // 初始化携带施法者的穿透概率