feat(技能): 为友方技能添加飞行特效并优化目标选择逻辑
- 新增友方技能释放时的飞行特效,包括抛物线动画和缩放旋转效果 - 重构 applyFriendlySkillEffects 方法,将特效播放与实际效果应用分离 - 调整 buff.prefab 的缩放比例从 0.2 增大到 0.5 以适配新特效 - 优化友方技能目标选择逻辑,确保特效从施法位置正确飞向目标
This commit is contained in:
@@ -99,8 +99,8 @@
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0.2,
|
||||
"y": 0.2,
|
||||
"x": 0.5,
|
||||
"y": 0.5,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
||||
import { Vec3 } from "cc";
|
||||
import { Vec3, Prefab, instantiate, tween, Node } from "cc";
|
||||
import { HeroAttrsComp } from "./HeroAttrsComp";
|
||||
import { HeroViewComp } from "./HeroViewComp";
|
||||
import { DTType, RType, SkillConfig, SkillKind, SkillSet, SkillUpList, TGroup } from "../common/config/SkillSet";
|
||||
@@ -113,7 +113,7 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
if (isFriendly) {
|
||||
const friendlyTargets = this.resolveFriendlyTargets(targetEids, FacSet.HERO);
|
||||
if (friendlyTargets.length === 0) continue;
|
||||
this.applyFriendlySkillEffects(s_uuid, cardLv, config, null as any, mockAttrs, friendlyTargets, null);
|
||||
this.applyFriendlySkillEffects(s_uuid, cardLv, config, null as any, mockAttrs, friendlyTargets, spawnPos);
|
||||
} else {
|
||||
const enemyTargetPos = this.resolveRepeatCastTargetPos(new Vec3(spawnPos.x + 300, spawnPos.y, spawnPos.z), i);
|
||||
this.createSkillEntityForCard(s_uuid, cardLv, mockAttrs, spawnPos, enemyTargetPos, i);
|
||||
@@ -384,37 +384,114 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
const applyTargets = kind === SkillKind.Heal
|
||||
? this.pickHealTargetsByMostMissingHp(targets, sHit)
|
||||
: this.pickRandomFriendlyTargets(targets, sHit);
|
||||
|
||||
for (const target of applyTargets) {
|
||||
if (!target.ent) continue;
|
||||
const model = target.ent.get(HeroAttrsComp);
|
||||
if (!model || model.is_dead) continue;
|
||||
if (kind === SkillKind.Heal && sAp !== 0) {
|
||||
const addHp = Math.floor(sAp*_cAttrsComp.ap/100);//技能的ap是百分值 需要/100
|
||||
model.add_hp(addHp);
|
||||
target.health(addHp);
|
||||
} else if (kind === SkillKind.Shield && sAp !== 0) {
|
||||
const addShield = Math.max(0, Math.floor(sAp));
|
||||
model.add_shield(addShield);
|
||||
}
|
||||
if (!config.buffs || config.buffs.length === 0) continue;
|
||||
for (const buffConf of config.buffs) {
|
||||
if (!buffConf) continue;
|
||||
const sBuffAp=buffConf.value+sUp.buff_ap
|
||||
const sBuffHp=buffConf.value+sUp.buff_hp
|
||||
switch (buffConf.buff){
|
||||
case Attrs.ap:
|
||||
model.add_ap(sBuffAp)
|
||||
//加工动画
|
||||
break
|
||||
case Attrs.hp_max:
|
||||
model.add_hp_max(sBuffHp)
|
||||
//加最大生命值动画
|
||||
break
|
||||
}
|
||||
const startPos = _heroView?.node?.position || _targetPos;
|
||||
if (startPos) {
|
||||
this.playFriendlyCastEffect(startPos, target, () => {
|
||||
this.applyActualFriendlyEffect(target, kind, sAp, _cAttrsComp, config, sUp);
|
||||
});
|
||||
} else {
|
||||
this.applyActualFriendlyEffect(target, kind, sAp, _cAttrsComp, config, sUp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private playFriendlyCastEffect(startPos: Vec3, target: HeroViewComp, callback: Function) {
|
||||
if (!target.node || !target.node.isValid) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
const prefabPath = "game/skill/buff/buff";
|
||||
const prefab = oops.res.get(prefabPath, Prefab);
|
||||
if (!prefab) {
|
||||
oops.res.load(prefabPath, Prefab, (err, res) => {
|
||||
if (err) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
this.doPlayFriendlyCastEffect(startPos.clone(), target, res as Prefab, callback);
|
||||
});
|
||||
} else {
|
||||
this.doPlayFriendlyCastEffect(startPos.clone(), target, prefab as Prefab, callback);
|
||||
}
|
||||
}
|
||||
|
||||
private doPlayFriendlyCastEffect(startPos: Vec3, target: HeroViewComp, prefab: Prefab, callback: Function) {
|
||||
if (!target.node || !target.node.isValid) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
const scene = smc.map?.MapView?.scene;
|
||||
const parent = scene?.entityLayer?.node?.getChildByName("SKILL") || target.node.parent;
|
||||
if (!parent) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
const node = instantiate(prefab);
|
||||
node.parent = parent;
|
||||
node.setPosition(startPos);
|
||||
|
||||
const targetPos = target.node.position.clone();
|
||||
targetPos.y += 50;
|
||||
|
||||
const midX = (startPos.x + targetPos.x) / 2;
|
||||
const midY = Math.max(startPos.y, targetPos.y) + 200;
|
||||
|
||||
const dist = Vec3.distance(startPos, targetPos);
|
||||
const duration = Math.min(0.6, Math.max(0.3, dist / 800));
|
||||
|
||||
const proxy = { ratio: 0 };
|
||||
tween(proxy)
|
||||
.to(duration, { ratio: 1 }, {
|
||||
easing: 'sineOut',
|
||||
onUpdate: () => {
|
||||
if (!node.isValid) return;
|
||||
const r = proxy.ratio;
|
||||
const x = (1 - r) * (1 - r) * startPos.x + 2 * r * (1 - r) * midX + r * r * targetPos.x;
|
||||
const y = (1 - r) * (1 - r) * startPos.y + 2 * r * (1 - r) * midY + r * r * targetPos.y;
|
||||
node.setPosition(new Vec3(x, y, startPos.z));
|
||||
node.setScale(new Vec3(1 - r * 0.3, 1 - r * 0.3, 1));
|
||||
node.angle = -r * 720;
|
||||
}
|
||||
})
|
||||
.call(() => {
|
||||
if (node.isValid) node.destroy();
|
||||
callback();
|
||||
})
|
||||
.start();
|
||||
}
|
||||
|
||||
private applyActualFriendlyEffect(target: HeroViewComp, kind: SkillKind, sAp: number, _cAttrsComp: HeroAttrsComp, config: SkillConfig, sUp: any) {
|
||||
if (!target.ent) return;
|
||||
const model = target.ent.get(HeroAttrsComp);
|
||||
if (!model || model.is_dead) return;
|
||||
if (kind === SkillKind.Heal && sAp !== 0) {
|
||||
const addHp = Math.floor(sAp*_cAttrsComp.ap/100);
|
||||
model.add_hp(addHp);
|
||||
target.health(addHp);
|
||||
} else if (kind === SkillKind.Shield && sAp !== 0) {
|
||||
const addShield = Math.max(0, Math.floor(sAp));
|
||||
model.add_shield(addShield);
|
||||
}
|
||||
if (!config.buffs || config.buffs.length === 0) return;
|
||||
for (const buffConf of config.buffs) {
|
||||
if (!buffConf) continue;
|
||||
const sBuffAp=buffConf.value+sUp.buff_ap
|
||||
const sBuffHp=buffConf.value+sUp.buff_hp
|
||||
switch (buffConf.buff){
|
||||
case Attrs.ap:
|
||||
model.add_ap(sBuffAp)
|
||||
break
|
||||
case Attrs.hp_max:
|
||||
model.add_hp_max(sBuffHp)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private pickRandomFriendlyTargets(targets: HeroViewComp[], hitCount: number): HeroViewComp[] {
|
||||
if (!targets || targets.length === 0) return [];
|
||||
const validHitCount = Math.max(1, Math.floor(hitCount));
|
||||
|
||||
Reference in New Issue
Block a user