Compare commits
5 Commits
b2cc25b32b
...
oh/0_7_1
| Author | SHA1 | Date | |
|---|---|---|---|
| f359eae788 | |||
| d3ca31fcfa | |||
| 509539760d | |||
| 7a7a6fa02c | |||
| 40c430546c |
File diff suppressed because it is too large
Load Diff
@@ -35,4 +35,64 @@
|
||||
冰封: 目标无法移动和攻击(cd继续), 3秒后自动解冻
|
||||
沉默: 目标一般技能和必杀技能技能cd清零
|
||||
击晕: 目标无移动和cd暂停
|
||||
击退: 后退15像素,cd减少5点,
|
||||
击退: 后退15像素,cd减少5点,
|
||||
|
||||
## 非关键成长三选一(示例池)
|
||||
用于非关键的成长选项,提供小步稳定增益,不抢关键天赋存在感。数值为建议区间,可按实际平衡调整。
|
||||
|
||||
| 组别 | 选项A | 选项B | 选项C | 推荐数值范围 | 阶段建议 | 说明 |
|
||||
| --- | --- | --- | --- | --- | --- | --- |
|
||||
| 基础属性(点数) | 力量 +3 | 智力 +3 | 敏捷 +3 | +3 点 | 全阶段 | 走职业系数转化,稳定推动 HP/AP/MAP/AS 等 |
|
||||
| 攻速系 | 攻速(AS) +10% | 技速(SS) +10% | 移速(SPEED) +8% | +8–12% | 中期 | 普攻/技能循环提速,维持心流 |
|
||||
| 暴击系 | 暴击率(CRITICAL) +10% | 暴伤(CRITICAL_DMG) +15% | 命中(HIT) +8% | +8–15% | 中后期 | 命中稳态配合暴击上限,防过度摇摆 |
|
||||
| 射击系 | 攻击距离(DIS) +10% | 作用范围(AOE) +10% | 穿透(PIERCE) +1 | +8–12% / +1 | 中期 | 影响站位与清杂效率,PIERCE建议≤2 |
|
||||
| 生存上限 | 生命上限(HP_MAX) +10% | 护盾上限(SHIELD_MAX) +12% | 生命回复(HP_REGEN) +15% | +10–15% | 早期 | 提升容错,抗压波次优先出现 |
|
||||
| 防御姿态 | 闪避(DODGE) +8% | 格挡(BLOCK) +10% | 减伤(DMG_RED) +10% | +8–10% | 中期 | 三防不叠加过猛,设软上限 50–60% |
|
||||
| 元素抗性 | 冰抗(ICE_RES) +12% | 火抗(FIRE_RES) +12% | 风抗(WIND_RES) +12% | +10–12% | 中后期 | 元素场景针对性减伤,补短板 |
|
||||
| 元素伤害 | 冰伤(ICE_POWER) +10% | 火伤(FIRE_POWER) +10% | 风伤(WIND_POWER) +10% | +8–10% | 中期 | 与技能元素类型联动,避免单系过度 |
|
||||
| 控制概率 | 眩晕(STUN_CHANCE) +6% | 沉默(SILENCE_CHANCE) +6% | 减速(SLOW_CHANCE) +10% | +6–10% | 中期 | 软控为主,CD/停顿联动合理抑制强控链 |
|
||||
| 妨害状态 | 冻结(FREEZE_CHANCE) +6% | 中毒(POISON_CHANCE) +8% | 燃烧(BURN_CHANCE) +8% | +6–8% | 中期 | 面向清杂、溃散,触发期望受控 |
|
||||
| 蓝量循环 | 蓝上限(MP_MAX) +10% | 蓝回复(MP_REGEN) +15% | 吸蓝(MANASTEAL) +6% | +10–15% | 早中期 | 技能密度稳定来源,支撑法系 |
|
||||
| 续航强化 | 吸血(LIFESTEAL) +6% | 治疗效果(HEAL_EFFECT) +12% | 护盾效果(SHIELD_UP) +12% | +6–12% | 中后期 | 对应不同生存风格,数值递减避免堆满 |
|
||||
| 稳定系 | 命中(HIT) +10% | 控抗(CON_RES) +10% | 暴抗(CRITICAL_RESIST) +10% | +8–10% | 中后期 | 降低波动,克制高暴击/高控敌群 |
|
||||
| 经济成长 | 经验(EXP_GAIN) +10% | 金币(GOLD_GAIN) +10% | 掉落(DROP_CHANCE) +8% | +8–10% | 转场期 | 低战力节点给经济,避免战斗失衡 |
|
||||
| 复活保障 | 复活次数(REVIVE_COUNT) +1 | 无敌时间(INVINCIBLE_TIME) +1s | 复活时间(REVIVE_TIME) -10% | +1 / +1s / -10% | 后期 | 高压波次救命,不与关键天赋冲突 |
|
||||
| 元素对抗 | 物抗(PHYS_RES) +10% | 魔抗(MAGIC_RES) +10% | 物伤加成(PHYS_POWER) +8% | +8–10% | 中后期 | 根据敌群构成动态出现 |
|
||||
| 资源提效 | 技能持续(SKILL_DURATION) +8% | 范围(AOE) +10% | 技速(SS) +8% | +8–10% | 中期 | DOT/场控/召唤类技能收益更佳 |
|
||||
|
||||
## 设计理念
|
||||
- 非关键增益:提供轻量、可叠加的稳定成长,不与关键三选一争夺注意力。
|
||||
- ERG需求:存在(生存)–关系(交互与反馈)–成长(能力提升)均衡覆盖,维持心流。
|
||||
- 小步快跑:每次选择形成可感知的小增量,累计 3–5 次后出现显著体感。
|
||||
- 动态补偿:三选一含“补缺/增强/探索”三类,提高决策质量与多样性。
|
||||
- 软上限与递减:概率类、穿透等设软上限并递减,避免极端堆叠破坏体验。
|
||||
|
||||
## 出现规则与阶段
|
||||
- 频率:每 2–3 波或每升 2 级出现一次,单局给予 3–5 次非关键成长选择。
|
||||
- 阶段:早期主生存与蓝量,中期主效率与控制,后期主稳定与复活保障。
|
||||
- 去重:同池短时间不重复,鼓励构筑分散与策略多样性。
|
||||
- 池权重:根据敌群/技能元素/职业类型动态调整池权重,提升贴合度。
|
||||
|
||||
## 数值与软上限建议
|
||||
- 概率类软上限 50–60%,暴击率软上限 60–70%,穿透 ≤ 2。
|
||||
- 递减系数:同类堆叠每层收益降低 15–30%,维持平衡与选择张力。
|
||||
|
||||
## IAA激励(可选)
|
||||
- 单局一次:允许“刷新一次三选一”或“临时解锁第四备选(低权重强项)”。
|
||||
- 公平性:激励数值较同池低 10–20%,避免破坏对局公平与关键天赋权重。
|
||||
|
||||
## 落地建议
|
||||
- 配置复用:非关键三选一统一走天赋 `BUFF` 模式,即时或升级触发。
|
||||
- 属性枚举:在 TalSet 的 `TalAttrs` 扩充基础属性(HP/MP/AS/SS/CRITICAL/HIT 等)。
|
||||
- 阶段配表:按波次/等级给不同池的权重与范围,避免压制关键天赋。
|
||||
- 上限与递减:对核心概率类与强度类属性设置软上限与递减曲线。
|
||||
|
||||
## 与代码映射(实现参考)
|
||||
- 触发类型:可用升级或初始触发,见 `assets/script/game/common/config/TalSet.ts:7` 枚举。
|
||||
- 效果类型:建议统一使用 `TalEffet.BUFF` + `vType(BType.VALUE/RATIO)`。
|
||||
- 可选属性来源:`assets/script/game/common/config/HeroAttrs.ts:27–113` 定义完整 `Attrs`。
|
||||
- 职业成长差异:`assets/script/game/common/config/HeroAttrs.ts:272–422` 提供成长系数。
|
||||
- 攻速/技速影响CD:`assets/script/game/hero/HeroSkills.ts:139–158`。
|
||||
- 命中/闪避/暴击联动:`assets/script/game/hero/HeroAtkSystem.ts:141–162`。
|
||||
- 元素伤害与抗性修正:`assets/script/game/hero/HeroAtkSystem.ts:295–306`。
|
||||
- 护盾吸收:`assets/script/game/hero/HeroAtkSystem.ts:422–450`。
|
||||
|
||||
@@ -21,6 +21,9 @@ export interface DamageEvent {
|
||||
|
||||
/** 伤害事件ID(用于去重和调试) */
|
||||
eventId: string;
|
||||
|
||||
ext_dmg:number //额外伤害
|
||||
dmg_ratio:number//伤害比例
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,7 +58,7 @@ export class DamageQueueComp extends ecs.Comp {
|
||||
/**
|
||||
* 添加伤害事件到队列
|
||||
*/
|
||||
addDamageEvent(attrs: any, caster: HeroViewComp, s_uuid: number): void {
|
||||
addDamageEvent(attrs: any, caster: HeroViewComp, s_uuid: number,ext_dmg:number=0,dmg_ratio:number=1): void {
|
||||
const timestamp = Date.now();
|
||||
const eventId = `${caster.ent.eid}_${s_uuid}_${timestamp}_${Math.random()}`;
|
||||
|
||||
@@ -64,7 +67,9 @@ export class DamageQueueComp extends ecs.Comp {
|
||||
caster: caster,
|
||||
s_uuid: s_uuid,
|
||||
timestamp: timestamp,
|
||||
eventId: eventId
|
||||
eventId: eventId,
|
||||
ext_dmg:ext_dmg,
|
||||
dmg_ratio:dmg_ratio,
|
||||
};
|
||||
|
||||
this.damageEvents.push(damageEvent);
|
||||
@@ -155,7 +160,7 @@ export class DamageQueueHelper {
|
||||
* 为实体添加伤害事件
|
||||
* 如果实体没有伤害队列组件,会自动创建
|
||||
*/
|
||||
static addDamageToEntity(entity: ecs.Entity, attrs: any, caster: HeroViewComp, s_uuid: number): void {
|
||||
static addDamageToEntity(entity: ecs.Entity, attrs: any, caster: HeroViewComp, s_uuid: number,ext_dmg:number=0,dmg_ratio:number=1): void {
|
||||
let damageQueue = entity.get(DamageQueueComp);
|
||||
|
||||
// 如果实体没有伤害队列组件,创建一个
|
||||
@@ -164,7 +169,7 @@ export class DamageQueueHelper {
|
||||
}
|
||||
|
||||
// 添加伤害事件到队列
|
||||
damageQueue.addDamageEvent(attrs, caster, s_uuid);
|
||||
damageQueue.addDamageEvent(attrs, caster, s_uuid,ext_dmg,dmg_ratio);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -66,16 +66,9 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
if (!damageEvent) break;
|
||||
|
||||
// 处理单个伤害事件
|
||||
const FDData = this.doAttack(e, damageEvent);
|
||||
this.doAttack(e, damageEvent);
|
||||
processedCount++;
|
||||
damageQueue.processedCount++;
|
||||
|
||||
if (this.debugMode) {
|
||||
const casterName = damageEvent.caster?.ent?.get(HeroAttrsComp)?.hero_name || "未知";
|
||||
const casterUuid = damageEvent.caster?.ent?.get(HeroAttrsComp)?.hero_uuid || 0;
|
||||
console.log(`[HeroAtkSystem] 英雄${TAttrsComp.hero_name} (uuid: ${TAttrsComp.hero_uuid}) 受到 ${casterName}(uuid: ${casterUuid})的 伤害 ${FDData.damage},${FDData.isCrit?"暴击":"普通"}攻击,技能ID ${damageEvent.s_uuid}`);
|
||||
}
|
||||
|
||||
// 如果目标已死亡,停止处理后续伤害
|
||||
if (TAttrsComp.is_dead) {
|
||||
if (this.debugMode) {
|
||||
@@ -134,7 +127,7 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
if (!TAttrsComp || TAttrsComp.is_dead) return reDate;
|
||||
|
||||
const caster = damageEvent.caster;
|
||||
const attackerTAttrsComp = caster?.ent?.get(HeroAttrsComp);
|
||||
const CAttrsComp = caster?.ent?.get(HeroAttrsComp);
|
||||
|
||||
// 获取技能配置
|
||||
const skillConf = SkillSet[damageEvent.s_uuid];
|
||||
@@ -158,6 +151,7 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
const isCrit = this.checkChance(damageEvent.Attrs[Attrs.CRITICAL]-TAttrsComp.Attrs[Attrs.CRITICAL_RESIST]);
|
||||
// 计算基础伤害
|
||||
let damage = this.dmgCount(damageEvent,TAttrsComp);
|
||||
if (this.debugMode) console.log("[HeroAtkSystem] dmgCount",damage)
|
||||
if (isCrit) {
|
||||
// 暴击伤害计算
|
||||
// 使用施法者的暴击伤害加成属性(damageEvent.Attrs 快照)
|
||||
@@ -165,22 +159,28 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
const casterCritDmg = damageEvent.Attrs[Attrs.CRITICAL_DMG] || 0;
|
||||
damage = Math.floor(damage * (1 + (FightSet.CRIT_DAMAGE + casterCritDmg) / 100));
|
||||
reDate.isCrit=true;
|
||||
attackerTAttrsComp?.useValueTalByAttr(Attrs.CRITICAL); // 清除施法者的暴击buff
|
||||
CAttrsComp?.useValueTalByAttr(Attrs.CRITICAL); // 清除施法者的暴击buff
|
||||
|
||||
}
|
||||
if (this.debugMode) console.log("[HeroAtkSystem] after crit",damage)
|
||||
// 护盾吸收
|
||||
damage =Math.floor(this.absorbShield(TAttrsComp, damage))
|
||||
if (this.debugMode) console.log("[HeroAtkSystem] after shield",damage)
|
||||
if (damage <= 0) return reDate;
|
||||
// 应用伤害到数据层
|
||||
TAttrsComp.hp -= damage;
|
||||
TAttrsComp.atked_count++;
|
||||
if (this.debugMode) {
|
||||
const casterName = damageEvent.caster?.ent?.get(HeroAttrsComp)?.hero_name || "未知";
|
||||
const casterUuid = damageEvent.caster?.ent?.get(HeroAttrsComp)?.hero_uuid || 0;
|
||||
console.log(`[HeroAtkSystem] 英雄${TAttrsComp.hero_name} (uuid: ${TAttrsComp.hero_uuid}) 受到 ${casterName}(uuid: ${casterUuid})的 伤害 ${damage},${isCrit?"暴击":"普通"}攻击,技能ID ${damageEvent.s_uuid}`);
|
||||
}
|
||||
//反伤判定 并应用到施法者
|
||||
this.check_thorns(TAttrsComp, caster?.ent,damage);
|
||||
// 击退判定
|
||||
// 使用施法者的击退概率属性(damageEvent.Attrs 快照)
|
||||
// 击退成功后需要清理施法者的相关天赋buff
|
||||
const isBack = this.checkChance(damageEvent.Attrs[Attrs.BACK_CHANCE] || 0);
|
||||
if (isBack) attackerTAttrsComp?.useValueTalByAttr(Attrs.BACK_CHANCE);
|
||||
if (isBack) CAttrsComp?.useValueTalByAttr(Attrs.BACK_CHANCE);
|
||||
|
||||
|
||||
// ✅ 触发视图层表现(伤害数字、受击动画、后退)
|
||||
@@ -189,6 +189,8 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
|
||||
// 检查死亡
|
||||
if (TAttrsComp.hp <= 0) {
|
||||
// 增加被击杀计数
|
||||
if (caster) CAttrsComp.Attrs.killed_count++;
|
||||
this.doDead(target);
|
||||
// ✅ 触发死亡视图表现
|
||||
if (targetView) {
|
||||
@@ -196,15 +198,14 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
}
|
||||
}
|
||||
|
||||
if (this.debugMode) {
|
||||
console.log(`[HeroAtkSystem] ${TAttrsComp.hero_name} 受到 ${damage} 点伤害 (暴击: ${isCrit})`);
|
||||
}
|
||||
if (this.debugMode) console.log(`[HeroAtkSystem] ${TAttrsComp.hero_name} 受到 ${damage} 点伤害 (暴击: ${isCrit})`);
|
||||
|
||||
|
||||
reDate.damage=damage;
|
||||
return reDate;
|
||||
}
|
||||
check_thorns(TAttrsComp:HeroAttrsComp, caster: ecs.Entity, damage:number) {
|
||||
// 检查目标是否有反伤属性
|
||||
// 检查目标是否有反伤属性,这里受伤的时时施法者
|
||||
if (!caster||damage<=0) return;
|
||||
let thornsDamage=0;
|
||||
thornsDamage=TAttrsComp.Attrs[Attrs.THORNS]||0+TAttrsComp.useCountValTal(Attrs.THORNS);
|
||||
@@ -217,6 +218,16 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
let CView=caster.get(HeroViewComp);
|
||||
// ✅ 触发视图层表现(伤害数字、受击动画、后退)
|
||||
if (CView) CView.do_atked(thornsDmg, false, SkillSet[5000].uuid, false);
|
||||
// 检查死亡
|
||||
if (CAttrs.hp <= 0) {
|
||||
this.doDead(caster);
|
||||
// 增加击杀计数
|
||||
if (caster) TAttrsComp.Attrs.killed_count++;
|
||||
// ✅ 触发死亡视图表现
|
||||
if (CView) {
|
||||
CView.do_dead();
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 详细伤害计算核心方法
|
||||
@@ -244,19 +255,21 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
* - 所有除法和乘法计算后都进行取整操作,确保游戏中的伤害值为整数
|
||||
* - 元素伤害只应用于魔法伤害部分
|
||||
*/
|
||||
private dmgCount(damageEvent:any,TAttrsComp:HeroAttrsComp){
|
||||
private dmgCount(damageEvent:DamageEvent,TAttrsComp:HeroAttrsComp){
|
||||
// 1. 获取技能配置 - 如果技能不存在,直接返回0伤害
|
||||
const CAttrs=damageEvent.Attrs;
|
||||
const TAttrs=TAttrsComp.Attrs;
|
||||
let sConf = SkillSet[damageEvent.s_uuid];
|
||||
if (!sConf) return 0;
|
||||
|
||||
if (this.debugMode) console.log(`[HeroAtkSystem] 伤害处理对象`,CAttrs,TAttrs);
|
||||
// 2. 计算原始物理伤害和魔法伤害
|
||||
// 物理伤害基础值 = 技能物理倍率 * (施法者物理攻击力 + 额外物理伤害) / 100 * 伤害比例
|
||||
// 物理伤害基础值 = 技能物理倍率 * (施法者物理攻击力 + 额外伤害) / 100 * 额外伤害比例
|
||||
let apBase = (sConf.ap||0)*(CAttrs[Attrs.AP]+damageEvent.ext_dmg)/100*damageEvent.dmg_ratio;
|
||||
// 魔法伤害基础值 = 技能魔法倍率 * (施法者魔法攻击力 + 额外魔法伤害) / 100 * 伤害比例
|
||||
// 魔法伤害基础值 = 技能魔法倍率 * (施法者魔法攻击力 + 额外伤害) / 100 * 额外伤害比例
|
||||
let mapBase = (sConf.map||0)*(CAttrs[Attrs.MAP]+damageEvent.ext_dmg)/100*damageEvent.dmg_ratio;
|
||||
|
||||
if (this.debugMode) console.log(`[HeroAtkSystem] 物理伤害基础值: ${apBase}, 技能ap=${sConf.ap},施法者物理攻击力: ${CAttrs[Attrs.AP]}, 魔法伤害基础值: ${mapBase}技能map=${sConf.map}
|
||||
额外伤害:${damageEvent.ext_dmg}, 额外伤害比例:${damageEvent.dmg_ratio}`);
|
||||
|
||||
// 3. 获取目标防御属性
|
||||
const def = (TAttrs[Attrs.DEF]||0); // 目标物理防御
|
||||
const mdef = (TAttrs[Attrs.MDEF]||0); // 目标魔法防御
|
||||
@@ -269,14 +282,15 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
let apAfter = Math.floor(apBase * (1 - apRed)); // 物理伤害 - 防御减免
|
||||
let mapAfter = Math.floor(mapBase * (1 - mapRed)); // 魔法伤害 - 防御减免
|
||||
|
||||
|
||||
|
||||
if (this.debugMode) console.log(`[HeroAtkSystem] 物理伤害基础值: ${apBase}, 物理伤害 - 防御减免: ${apAfter} 魔法伤害基础值: ${mapBase}, 魔法伤害 - 防御减免: ${mapAfter}`);
|
||||
|
||||
// 6. 应用物理/魔法攻击力和抗性修正
|
||||
// 物理伤害修正:基础伤害 * (1 + 物理攻击力加成%) * (1 - 目标物理抗性%)
|
||||
apAfter = this.applyPR(apAfter, CAttrs[Attrs.PHYS_POWER]||0, TAttrs[Attrs.PHYS_RES]||0);
|
||||
// 魔法伤害修正:基础伤害 * (1 + 魔法攻击力加成%) * (1 - 目标魔法抗性%)
|
||||
mapAfter = this.applyPR(mapAfter, CAttrs[Attrs.MAGIC_POWER]||0, TAttrs[Attrs.MAGIC_RES]||0);
|
||||
|
||||
if (this.debugMode) console.log(`[HeroAtkSystem] 物理伤害修正后: ${apAfter} 魔法伤害修正后: ${mapAfter} `);
|
||||
|
||||
// 7. 根据技能元素类型,应用元素属性加成和抗性修正
|
||||
switch (sConf.DType) {
|
||||
case DType.ICE:
|
||||
@@ -292,6 +306,7 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
mapAfter = this.applyPR(mapAfter, CAttrs[Attrs.WIND_POWER]||0, TAttrs[Attrs.WIND_RES]||0);
|
||||
break;
|
||||
}
|
||||
if (this.debugMode) console.log(`[HeroAtkSystem] 物理伤害修正后: ${apAfter} 元素伤害修正后: ${mapAfter}`);
|
||||
|
||||
// 8. 计算最终总伤害(物理伤害 + 魔法伤害)
|
||||
let total = apAfter + mapAfter;
|
||||
@@ -303,7 +318,7 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
total = Math.max(0,total);
|
||||
//11. 易伤减免 免伤属性免伤+天赋免伤
|
||||
total = Math.floor(total * (1 + ((DMG_INVUL-DMG_RED)/100)));
|
||||
|
||||
if (this.debugMode) console.log(`[HeroAtkSystem] 易伤减免后: ${total}`);
|
||||
return Math.max(0,total);
|
||||
}
|
||||
|
||||
@@ -449,7 +464,7 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
||||
private onAttacked(entity: ecs.Entity): void {
|
||||
const TAttrsComp = entity.get(HeroAttrsComp);
|
||||
if (!TAttrsComp || TAttrsComp.is_dead) return;
|
||||
|
||||
TAttrsComp.atked_count++;
|
||||
// 这里可以添加被攻击时的特殊处理逻辑
|
||||
if (TAttrsComp.fac === FacSet.MON) return;
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ export class HeroAttrsComp extends ecs.Comp {
|
||||
// ==================== 计数统计 ====================
|
||||
atk_count: number = 0; // 攻击次数
|
||||
atked_count: number = 0; // 被攻击次数
|
||||
|
||||
killed_count:number=0;
|
||||
// 注意:技能数据已迁移到 HeroSkillsComp,不再存储在这里
|
||||
|
||||
start(){
|
||||
@@ -561,6 +561,7 @@ export class HeroAttrsComp extends ecs.Comp {
|
||||
this.is_kalami = false;
|
||||
this.atk_count = 0;
|
||||
this.atked_count = 0;
|
||||
this.killed_count =0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -26,6 +26,20 @@ export interface BuffInfo {
|
||||
@ccclass('HeroViewComp') // 定义Cocos Creator 组件
|
||||
@ecs.register('HeroView', false) // 定义ECS 组件
|
||||
export class HeroViewComp extends CCComp {
|
||||
private debugMode: boolean = true; // 是否启用调试模式
|
||||
|
||||
// 添加条件日志方法
|
||||
private debugLog(...args: any[]): void {
|
||||
if (this.debugMode) {
|
||||
console.log(...args);
|
||||
}
|
||||
}
|
||||
|
||||
private debugWarn(...args: any[]): void {
|
||||
if (this.debugMode) {
|
||||
console.warn(...args);
|
||||
}
|
||||
}
|
||||
// ==================== View 层属性(表现相关)====================
|
||||
as: HeroSpine = null!
|
||||
status:String = "idle"
|
||||
@@ -43,7 +57,7 @@ export class HeroViewComp extends CCComp {
|
||||
get model() {
|
||||
// 🔥 修复:添加安全检查,防止ent为null时的访问异常
|
||||
if (!this.ent) {
|
||||
console.warn("[HeroViewComp] ent is null, returning null for model");
|
||||
this.debugWarn("[HeroViewComp] ent is null, returning null for model");
|
||||
return null;
|
||||
}
|
||||
return this.ent.get(HeroAttrsComp);
|
||||
@@ -89,7 +103,8 @@ export class HeroViewComp extends CCComp {
|
||||
this.top_node.getChildByName("hp").active = true;
|
||||
this.top_node.getChildByName("mp").active = true;
|
||||
// 初始隐藏血条(被攻击后才显示)
|
||||
this.top_node.active = false;
|
||||
this.top_node.active = true;
|
||||
|
||||
}
|
||||
|
||||
/** 初始化 UI 节点引用 */
|
||||
@@ -136,8 +151,8 @@ export class HeroViewComp extends CCComp {
|
||||
|
||||
// ✅ 更新 UI 显示(数据由 HeroAttrSystem 更新)
|
||||
// 移除了每帧调用的 hp_show,改为仅在需要时调用
|
||||
this.hp_show(this.model.hp, this.model.Attrs[Attrs.HP_MAX]);
|
||||
this.mp_show(this.model.mp, this.model.Attrs[Attrs.MP_MAX]);
|
||||
this.hp_show();
|
||||
this.mp_show();
|
||||
this.show_shield(this.model.shield, this.model.Attrs[Attrs.SHIELD_MAX]);
|
||||
}
|
||||
|
||||
@@ -155,20 +170,23 @@ export class HeroViewComp extends CCComp {
|
||||
}
|
||||
|
||||
/** 显示血量 */
|
||||
private hp_show(hp: number, hp_max: number) {
|
||||
private hp_show() {
|
||||
// 不再基于血量是否满来决定显示状态,只更新进度条
|
||||
if(!this.top_node.active) return;
|
||||
|
||||
let hp_progress = hp / hp_max;
|
||||
this.top_node.getChildByName("hp").getComponent(ProgressBar).progress = hp_progress;
|
||||
let hp=this.model.hp;
|
||||
let hp_max=this.model.Attrs[Attrs.HP_MAX];
|
||||
this.debugLog("hp_show",hp,hp_max)
|
||||
this.top_node.getChildByName("hp").getComponent(ProgressBar).progress = hp / hp_max;;
|
||||
this.scheduleOnce(() => {
|
||||
this.top_node.getChildByName("hp").getChildByName("hpb").getComponent(ProgressBar).progress = hp_progress;
|
||||
this.top_node.getChildByName("hp").getChildByName("hpb").getComponent(ProgressBar).progress = hp / hp_max;;
|
||||
}, 0.15);
|
||||
}
|
||||
|
||||
/** 显示魔法值 */
|
||||
private mp_show(mp: number, mp_max: number) {
|
||||
private mp_show() {
|
||||
if(!this.top_node.active) return
|
||||
let mp=this.model.mp;
|
||||
let mp_max=this.model.Attrs[Attrs.MP_MAX];
|
||||
this.debugLog("mp_show",mp,mp_max)
|
||||
this.top_node.getChildByName("mp").getComponent(ProgressBar).progress = mp / mp_max;
|
||||
this.scheduleOnce(() => {
|
||||
this.top_node.getChildByName("mp").getChildByName("mpb").getComponent(ProgressBar).progress = mp / mp_max;
|
||||
@@ -288,13 +306,13 @@ export class HeroViewComp extends CCComp {
|
||||
this.heathed();
|
||||
this.hp_tip(TooltipTypes.health, hp.toFixed(0));
|
||||
this.top_node.active=true
|
||||
this.hp_show(this.model.hp, this.model.Attrs[Attrs.HP_MAX]);
|
||||
this.hp_show();
|
||||
}
|
||||
mp_add(mp: number = 0) {
|
||||
// 生命值更新由 Model 层处理,这里只负责视图表现
|
||||
this.hp_tip(TooltipTypes.addmp, mp.toFixed(0));
|
||||
this.top_node.active=true
|
||||
this.mp_show(this.model.mp, this.model.Attrs[Attrs.MP_MAX]);
|
||||
this.mp_show();
|
||||
}
|
||||
|
||||
alive(){
|
||||
@@ -326,7 +344,7 @@ export class HeroViewComp extends CCComp {
|
||||
realDead(){
|
||||
// 🔥 修复:添加model安全检查,防止实体销毁过程中的空指针异常
|
||||
if (!this.model) {
|
||||
console.warn("[HeroViewComp] realDead called but model is null, skipping");
|
||||
this.debugWarn("[HeroViewComp] realDead called but model is null, skipping");
|
||||
return;
|
||||
}
|
||||
if(this.model.fac === FacSet.HERO){
|
||||
@@ -439,7 +457,7 @@ export class HeroViewComp extends CCComp {
|
||||
private showDamageImmediate(damage: number, isCrit: boolean, anm:string="atked") {
|
||||
if (!this.model) return;
|
||||
|
||||
this.hp_show(this.model.hp, this.model.Attrs[Attrs.HP_MAX]);
|
||||
this.hp_show();
|
||||
this.in_atked(anm, this.model.fac==FacSet.HERO?1:-1);
|
||||
if (isCrit) {
|
||||
this.hp_tip(TooltipTypes.crit, damage.toFixed(0));
|
||||
@@ -467,3 +485,8 @@ export class HeroViewComp extends CCComp {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -149,7 +149,9 @@ export class SkillView extends CCComp {
|
||||
target.ent,
|
||||
this.sData.Attrs,
|
||||
this.sData.caster,
|
||||
this.sData.s_uuid
|
||||
this.sData.s_uuid,
|
||||
this.sData.ext_dmg,
|
||||
this.sData.dmg_ratio,
|
||||
);
|
||||
// 更新技能命中次数
|
||||
this.sData.hit_count++
|
||||
|
||||
Reference in New Issue
Block a user