feat(技能系统): 添加治疗和护盾技能支持

实现治疗和护盾技能的基础功能,包括:
1. 在SACastSystem中添加对治疗和护盾技能类型的支持
2. 新增技能目标选择逻辑,根据技能类型选择敌人或友军
3. 添加buff动画效果和技能提示
4. 更新刘邦的技能配置为护盾技能
5. 移除不再使用的EndAnm相关文件
This commit is contained in:
walkpan
2025-12-31 19:50:27 +08:00
parent 35b677ec7a
commit beb0f9feb4
10 changed files with 204 additions and 88 deletions

View File

@@ -49,20 +49,24 @@ export class SACastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdat
const readySkills = skills.getReadySkills(heroAttrs.mp);
if (readySkills.length === 0) return;
// 选择第一个可施放的伤害技能
for (const s_uuid of readySkills) {
// 选择第一个可施放的技能(支持伤害/治疗/护盾)
for (const s_uuid of readySkills) {
const skill = skills.getSkill(s_uuid);
if (!skill) continue;
if (skill.hset === HSSet.max && !skills.max_auto) continue;
const config = SkillSet[skill.s_uuid];
if (!config || config.SType !== SType.damage) continue;
if (!config) continue;
// 检查是否有敌人在技能攻击范围内
if (!this.hasEnemyInSkillRange(heroView, heroAttrs, skill.dis)) continue;
// 根据技能类型检查目标
if (config.SType === SType.damage) {
if (!this.hasEnemyInSkillRange(heroView, heroAttrs, skill.dis)) continue;
} else if (config.SType === SType.heal || config.SType === SType.shield) {
if (!this.hasAllyInSkillRange(heroView, heroAttrs, skill.dis)) continue;
}
// ✅ 开始执行施法
this.startCast(e,skill,skill.hset);
this.startCast(e, skill, skill.hset);
// 一次只施放一个技能
break;
@@ -151,8 +155,15 @@ export class SACastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdat
if (hset === HSSet.max) talComp.updateCur(TriType.MAX);
}
/**********************天赋处理*************************************************************************/
// 获取目标位置
let targets = this.sTargets(heroView, s_uuid);
// 根据技能类型执行不同逻辑
if (config.SType === SType.heal) {
return this.executeHealSkill(casterEntity, s_uuid, heroView, hset);
} else if (config.SType === SType.shield) {
return this.executeShieldSkill(casterEntity, s_uuid, heroView, hset);
}
// 获取目标位置(伤害技能)
let targets = this.sTargets(heroView, s_uuid);
if (targets.length === 0) {
console.warn("[SACastSystem] 没有找到有效目标");
return false;
@@ -348,6 +359,159 @@ export class SACastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdat
});
return found;
}
/**
* 检查技能范围内是否有友军
*/
private hasAllyInSkillRange(heroView: HeroViewComp, heroAttrs: HeroAttrsComp, skillDistance: number): boolean {
if (!heroView || !heroView.node) return false;
const currentPos = heroView.node.position;
const team = heroAttrs.fac;
let found = false;
ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).some(e => {
const model = e.get(HeroAttrsComp);
const view = e.get(HeroViewComp);
if (!view || !view.node) return false;
const distance = Math.abs(currentPos.x - view.node.position.x);
if (model.fac === team && !model.is_dead) {
if (distance <= skillDistance) {
found = true;
return true;
}
}
});
return found;
}
/**
* 执行治疗技能
*/
private executeHealSkill(casterEntity: ecs.Entity, s_uuid: number, heroView: HeroViewComp, hset: HSSet): boolean {
const heroAttrs = casterEntity.get(HeroAttrsComp);
const config = SkillSet[s_uuid];
if (!config) return false;
const targets = this.sHealTargets(heroView, heroAttrs, config);
if (targets.length === 0) return false;
const healAmount = config.ap;
const delay = 0.3;
heroView.scheduleOnce(() => {
for (const targetEntity of targets) {
const targetAttrs = targetEntity.get(HeroAttrsComp);
const targetView = targetEntity.get(HeroViewComp);
if (!targetAttrs || !targetView) continue;
targetAttrs.add_hp(healAmount, false);
targetView.health(healAmount);
}
}, delay);
return true;
}
/**
* 执行护盾技能
*/
private executeShieldSkill(casterEntity: ecs.Entity, s_uuid: number, heroView: HeroViewComp, hset: HSSet): boolean {
const heroAttrs = casterEntity.get(HeroAttrsComp);
const config = SkillSet[s_uuid];
if (!config) return false;
const targets = this.sShieldTargets(heroView, heroAttrs, config);
if (targets.length === 0) return false;
const shieldAmount = config.ap;
const delay = 0.3;
heroView.scheduleOnce(() => {
for (const targetEntity of targets) {
const targetAttrs = targetEntity.get(HeroAttrsComp);
const targetView = targetEntity.get(HeroViewComp);
if (!targetAttrs || !targetView) continue;
targetAttrs.add_shield(shieldAmount, false);
targetView.add_shield(shieldAmount);
}
}, delay);
return true;
}
/**
* 选择治疗目标
*/
private sHealTargets(caster: HeroViewComp, heroAttrs: HeroAttrsComp, config: any): ecs.Entity[] {
const targets: ecs.Entity[] = [];
const maxTargets = Math.max(1, Number(config.t_num ?? 1));
const range = Number(config.dis ?? 300);
ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).forEach(e => {
const model = e.get(HeroAttrsComp);
const view = e.get(HeroViewComp);
if (!model || !view || !view.node) return;
if (model.fac !== heroAttrs.fac) return;
if (model.is_dead) return;
const distance = Math.abs(caster.node.position.x - view.node.position.x);
if (distance <= range) {
targets.push(e);
}
});
targets.sort((a, b) => {
const attrsA = a.get(HeroAttrsComp);
const attrsB = b.get(HeroAttrsComp);
if (!attrsA || !attrsB) return 0;
return attrsA.hp - attrsB.hp;
});
return targets.slice(0, maxTargets);
}
/**
* 选择护盾目标
*/
private sShieldTargets(caster: HeroViewComp, heroAttrs: HeroAttrsComp, config: any): ecs.Entity[] {
const targets: ecs.Entity[] = [];
const maxTargets = Math.max(1, Number(config.t_num ?? 1));
const range = Number(config.dis ?? 300);
ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).forEach(e => {
const model = e.get(HeroAttrsComp);
const view = e.get(HeroViewComp);
if (!model || !view || !view.node) return;
if (model.fac !== heroAttrs.fac) return;
if (model.is_dead) return;
const distance = Math.abs(caster.node.position.x - view.node.position.x);
if (distance <= range) {
targets.push(e);
}
});
return targets.slice(0, maxTargets);
}
/**
* 根据位置查找实体
*/
private findEntityAtPosition(pos: Vec3): ecs.Entity | null {
let foundEntity: ecs.Entity | null = null;
ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).some(e => {
const view = e.get(HeroViewComp);
if (!view || !view.node) return false;
const distance = Vec3.distance(pos, view.node.position);
if (distance < 50) {
foundEntity = e;
return true;
}
return false;
});
return foundEntity;
}
}