技能逻辑修改,怪物只攻击最前方,友方和地方逻辑分开
This commit is contained in:
@@ -131,59 +131,49 @@ export class HeroSkillSystem extends ecs.ComblockSystem implements ecs.ISystemUp
|
|||||||
view.at = view.at-view.cd; // 重置普攻计时器
|
view.at = view.at-view.cd; // 重置普攻计时器
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (config.TargetGroup === TargetGroup.Enemy) {
|
||||||
|
const targets = this.selectEnemyTargets(caster, config);
|
||||||
|
if (targets.length === 0) return;
|
||||||
|
const skillEntity = ecs.getEntity<Skill>(Skill);
|
||||||
|
skillEntity.load(
|
||||||
|
view.node.position, // 起始位置
|
||||||
|
view.fac, // 阵营
|
||||||
|
view.node.parent, // 父节点
|
||||||
|
config.uuid, // 技能ID
|
||||||
|
targets[0]?.get(HeroViewComp).node.position // 目标位置
|
||||||
|
);
|
||||||
|
targets.forEach(target => {
|
||||||
|
this.applySkillEffect(caster, target, config);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
if (config.TargetGroup === TargetGroup.Ally) {
|
||||||
|
const targets = this.selectAllyTargets(caster, config);
|
||||||
|
if (targets.length === 0) return;
|
||||||
|
targets.forEach(target => {
|
||||||
|
this.applySkillEffect(caster, target, config);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 选择目标
|
if (config.TargetGroup === TargetGroup.Self) {
|
||||||
const targets = this.selectTargets(caster, config);
|
this.applySkillEffect(caster, caster, config);
|
||||||
if (targets.length === 0) return;
|
}
|
||||||
|
|
||||||
// 创建技能实体
|
|
||||||
const skillEntity = ecs.getEntity<Skill>(Skill);
|
|
||||||
skillEntity.load(
|
|
||||||
view.node.position, // 起始位置
|
|
||||||
view.fac, // 阵营
|
|
||||||
view.node.parent, // 父节点
|
|
||||||
config.uuid, // 技能ID
|
|
||||||
targets[0]?.get(HeroViewComp).node.position // 目标位置
|
|
||||||
);
|
|
||||||
|
|
||||||
// 应用技能效果
|
|
||||||
targets.forEach(target => {
|
|
||||||
this.applySkillEffect(caster, target, config);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 选择技能目标 */
|
private selectEnemyTargets(caster: ecs.Entity, config: typeof SkillSet[keyof typeof SkillSet]): ecs.Entity[] {
|
||||||
private selectTargets(caster: ecs.Entity, config: typeof SkillSet[keyof typeof SkillSet]): ecs.Entity[] {
|
|
||||||
const casterView = caster.get(HeroViewComp);
|
const casterView = caster.get(HeroViewComp);
|
||||||
const team = casterView.fac;
|
const team = casterView.fac;
|
||||||
const isEnemyTeam = team === 0 ? 1 : 0;
|
const isEnemyTeam = team === 0 ? 1 : 0;
|
||||||
|
const candidates= ecs.query(ecs.allOf(HeroViewComp)).filter(e => e.get(HeroViewComp).fac !== team);
|
||||||
// 第一阶段:基础目标筛选
|
return this.filterFrontRow(candidates, isEnemyTeam);
|
||||||
let candidates = ecs.query(ecs.allOf(HeroViewComp)).filter(e => {
|
}
|
||||||
const view = e.get(HeroViewComp);
|
private selectAllyTargets(caster: ecs.Entity, config: typeof SkillSet[keyof typeof SkillSet]): ecs.Entity[] {
|
||||||
// 根据技能目标类型筛选
|
const casterView = caster.get(HeroViewComp);
|
||||||
switch(config.TargetGroup) {
|
const team = casterView.fac;
|
||||||
case TargetGroup.Enemy:
|
const candidates= ecs.query(ecs.allOf(HeroViewComp)).filter(e => e.get(HeroViewComp).fac === team);
|
||||||
return view.fac !== team;
|
|
||||||
case TargetGroup.Ally:
|
|
||||||
return view.fac === team && e !== caster;
|
|
||||||
case TargetGroup.Self:
|
|
||||||
return e === caster;
|
|
||||||
default:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 第二阶段:位置/血量等精细筛选
|
// 第二阶段:位置/血量等精细筛选
|
||||||
switch(config.TargetType) {
|
switch(config.TargetType) {
|
||||||
case TargetType.Frontline:
|
|
||||||
return this.filterFrontRow(candidates, isEnemyTeam);
|
|
||||||
// case TargetType.Backline:
|
|
||||||
// return this.filterBackRow(candidates, isEnemyTeam);
|
|
||||||
// case TargetType.LowestHP:
|
|
||||||
// return this.filterLowestHealth(candidates);
|
|
||||||
// case TargetType.HighestHP:
|
|
||||||
// return this.filterHighestHealth(candidates);
|
|
||||||
case TargetType.Melee:
|
case TargetType.Melee:
|
||||||
return candidates.filter(e => e.get(HeroViewComp).type === 0);
|
return candidates.filter(e => e.get(HeroViewComp).type === 0);
|
||||||
case TargetType.Ranged:
|
case TargetType.Ranged:
|
||||||
@@ -196,7 +186,7 @@ export class HeroSkillSystem extends ecs.ComblockSystem implements ecs.ISystemUp
|
|||||||
return candidates;
|
return candidates;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 筛选最前排单位 */
|
/** 筛选最前排单位 */
|
||||||
private filterFrontRow(entities: ecs.Entity[], isEnemyTeam: number): ecs.Entity[] {
|
private filterFrontRow(entities: ecs.Entity[], isEnemyTeam: number): ecs.Entity[] {
|
||||||
// 敌方最前排是x坐标最大的,我方最前排是x坐标最小的
|
// 敌方最前排是x坐标最大的,我方最前排是x坐标最小的
|
||||||
@@ -209,30 +199,6 @@ export class HeroSkillSystem extends ecs.ComblockSystem implements ecs.ISystemUp
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 筛选最后排单位 */
|
|
||||||
private filterBackRow(entities: ecs.Entity[], isEnemyTeam: number): ecs.Entity[] {
|
|
||||||
// 敌方最后排是x坐标最小的,我方最后排是x坐标最大的
|
|
||||||
const keyPos = isEnemyTeam ?
|
|
||||||
Math.max(...entities.map(e => e.get(HeroViewComp).node.position.x)) :
|
|
||||||
Math.min(...entities.map(e => e.get(HeroViewComp).node.position.x));
|
|
||||||
|
|
||||||
return entities.filter(e =>
|
|
||||||
Math.abs(e.get(HeroViewComp).node.position.x - keyPos) < 10
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 筛选血量最低单位 */
|
|
||||||
private filterLowestHealth(entities: ecs.Entity[]): ecs.Entity[] {
|
|
||||||
const minHp = Math.min(...entities.map(e => e.get(HeroViewComp).hp));
|
|
||||||
return entities.filter(e => e.get(HeroViewComp).hp === minHp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 筛选血量最高单位 */
|
|
||||||
private filterHighestHealth(entities: ecs.Entity[]): ecs.Entity[] {
|
|
||||||
const maxHp = Math.max(...entities.map(e => e.get(HeroViewComp).hp));
|
|
||||||
return entities.filter(e => e.get(HeroViewComp).hp === maxHp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 随机选择目标 */
|
/** 随机选择目标 */
|
||||||
private pickRandomTarget(entities: ecs.Entity[], count: number): ecs.Entity[] {
|
private pickRandomTarget(entities: ecs.Entity[], count: number): ecs.Entity[] {
|
||||||
const shuffled = [...entities].sort(() => 0.5 - Math.random());
|
const shuffled = [...entities].sort(() => 0.5 - Math.random());
|
||||||
@@ -272,7 +238,6 @@ export class HeroSkillSystem extends ecs.ComblockSystem implements ecs.ISystemUp
|
|||||||
result.delay = distance / config.speed;
|
result.delay = distance / config.speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
const targetView = target.get(HeroViewComp);
|
|
||||||
const sourceView = caster.get(HeroViewComp);
|
const sourceView = caster.get(HeroViewComp);
|
||||||
let final = sourceView.ap * config.ap / 100;
|
let final = sourceView.ap * config.ap / 100;
|
||||||
|
|
||||||
@@ -281,34 +246,8 @@ export class HeroSkillSystem extends ecs.ComblockSystem implements ecs.ISystemUp
|
|||||||
final *= damageFloat;
|
final *= damageFloat;
|
||||||
final = Math.round(final);
|
final = Math.round(final);
|
||||||
|
|
||||||
|
|
||||||
// 闪避判定
|
|
||||||
if (Math.random()*100 < targetView.dodge) {
|
|
||||||
result.isDodged = true
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// 护甲减伤
|
|
||||||
if (!result.ignoreDefense) {
|
|
||||||
const effectiveArmor = Math.min(targetView.def, 300); // 最大减伤75%
|
|
||||||
const damageReduction = effectiveArmor / (effectiveArmor + 100);
|
|
||||||
final *= (1 - damageReduction);
|
|
||||||
final = Math.round(final); // 四舍五入取整
|
|
||||||
}
|
|
||||||
|
|
||||||
// 暴击判定
|
|
||||||
let isCrit = false;
|
|
||||||
if (result.canCrit) {
|
|
||||||
const critRate = sourceView.crit;
|
|
||||||
if (Math.random() * 100 < critRate) {
|
|
||||||
final *= 1.5;
|
|
||||||
isCrit = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result.value = Math.max(1, final); // 确保最小伤害为1
|
result.value = Math.max(1, final); // 确保最小伤害为1
|
||||||
result.isCrit = isCrit;
|
result.isCrit = false;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,12 +257,7 @@ export class HeroSkillSystem extends ecs.ComblockSystem implements ecs.ISystemUp
|
|||||||
callback: () => {
|
callback: () => {
|
||||||
const view = target.get(HeroViewComp);
|
const view = target.get(HeroViewComp);
|
||||||
if (!view?.ent.has(HeroViewComp)) return;
|
if (!view?.ent.has(HeroViewComp)) return;
|
||||||
|
|
||||||
if(result.isDodged){
|
|
||||||
view.BUFFCOMP.tooltip(5,"*闪避*");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let remainingDamage = result.value;
|
let remainingDamage = result.value;
|
||||||
if (view.shield > 0) {
|
if (view.shield > 0) {
|
||||||
const shieldAbsorb = Math.min(view.shield, remainingDamage);
|
const shieldAbsorb = Math.min(view.shield, remainingDamage);
|
||||||
@@ -341,7 +275,7 @@ export class HeroSkillSystem extends ecs.ComblockSystem implements ecs.ISystemUp
|
|||||||
view.BUFFCOMP.dead()
|
view.BUFFCOMP.dead()
|
||||||
view.to_grave();
|
view.to_grave();
|
||||||
}
|
}
|
||||||
view.showDamage(result.value, result.isCrit);
|
view.showDamage(result.value, true);
|
||||||
} else {
|
} else {
|
||||||
view.BUFFCOMP.tooltip(5,"*吸收*");
|
view.BUFFCOMP.tooltip(5,"*吸收*");
|
||||||
}
|
}
|
||||||
@@ -364,17 +298,6 @@ export class HeroSkillSystem extends ecs.ComblockSystem implements ecs.ISystemUp
|
|||||||
// 实现debuff逻辑...
|
// 实现debuff逻辑...
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 外部调用重置冷却 */
|
|
||||||
public resetSkillCooldown(entity: ecs.Entity, skillId: number) {
|
|
||||||
const comp = entity.get(HeroSkillsComp);
|
|
||||||
comp.resetCooldown(skillId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 重置所有技能冷却 */
|
|
||||||
public resetAllCooldowns(entity: ecs.Entity) {
|
|
||||||
const comp = entity.get(HeroSkillsComp);
|
|
||||||
comp.resetAllCooldowns();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user