技能系统修改为 只负责普通技能
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
import { Node, Vec3 } from "cc";
|
||||
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
||||
import { HeroViewComp } from "../hero/HeroViewComp";
|
||||
import { HeroSkillsComp } from "./heroSkillsComp";
|
||||
import { SkillSet, TargetGroup, TargetType } from "../common/config/SkillSet";
|
||||
import { CdType } from "../common/config/SkillSet";
|
||||
import { oops } from "db://oops-framework/core/Oops";
|
||||
@@ -23,109 +22,45 @@ export class HeroSkillSystem extends ecs.ComblockSystem implements ecs.ISystemUp
|
||||
oops.message.on(GameEvent.MissionEnd, this.clear_timer, this);
|
||||
}
|
||||
filter(): ecs.IMatcher {
|
||||
return ecs.allOf(HeroSkillsComp, HeroViewComp);
|
||||
return ecs.allOf(HeroViewComp);
|
||||
}
|
||||
|
||||
|
||||
update(e: ecs.Entity) {
|
||||
//return false
|
||||
// 处理伤害队列
|
||||
this.processDamageQueue();
|
||||
const view = e.get(HeroViewComp);
|
||||
const skills = e.get(HeroSkillsComp);
|
||||
|
||||
// 使用固定时间步长更新
|
||||
|
||||
// 只在攻击状态触发技能
|
||||
if (view.is_atking) {
|
||||
this.processSkills(e, skills);
|
||||
if (view.is_atking &&view.at > view.cd) {
|
||||
const config = SkillSet[view.atk_skill];
|
||||
if (!config) return;
|
||||
this.castSkill(e, view.atk_skill, config);
|
||||
view.at = 0;
|
||||
}
|
||||
|
||||
// 更新所有技能冷却
|
||||
skills.skills.forEach(skillId => {
|
||||
this.updateCooldown(skills, skillId);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private processDamageQueue() {
|
||||
const delta = this.dt;
|
||||
for (let i = this._damageQueue.length - 1; i >= 0; i--) {
|
||||
this._damageQueue[i].timer -= delta;
|
||||
if (this._damageQueue[i].timer <= 0) {
|
||||
this._damageQueue[i].callback();
|
||||
this._damageQueue.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 处理所有技能逻辑 */
|
||||
private processSkills(entity: ecs.Entity, comp: HeroSkillsComp) {
|
||||
comp.skills.forEach(skillId => {
|
||||
const config = SkillSet[skillId];
|
||||
if (!config) return;
|
||||
|
||||
// 检查释放条件
|
||||
if (this.checkSkillCondition(entity, config)) {
|
||||
this.castSkill(entity, skillId, config);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** 更新技能冷却 */
|
||||
private updateCooldown(comp: HeroSkillsComp, skillId: number) {
|
||||
let cd = comp.cooldowns.has(skillId) ? comp.cooldowns.get(skillId)! : 0;
|
||||
if (cd > 0) {
|
||||
comp.cooldowns.set(skillId, cd - this.dt);
|
||||
}
|
||||
}
|
||||
|
||||
/** 检查技能释放条件 */
|
||||
private checkSkillCondition(entity: ecs.Entity, config: typeof SkillSet[keyof typeof SkillSet]): boolean {
|
||||
const view = entity.get(HeroViewComp);
|
||||
const comp = entity.get(HeroSkillsComp);
|
||||
switch(config.CdType){
|
||||
case CdType.SkillCD:
|
||||
return (comp.cooldowns.get(config.uuid as number) ?? 0) <= 0;
|
||||
case CdType.HeroCD:
|
||||
return view.at >= view.cd;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** 施放技能 */
|
||||
private castSkill(caster: ecs.Entity, skillId: number, config: typeof SkillSet[keyof typeof SkillSet]) {
|
||||
const view = caster.get(HeroViewComp);
|
||||
const comp = caster.get(HeroSkillsComp);
|
||||
const skillEntity = ecs.getEntity<Skill>(Skill);
|
||||
console.log(view.hero_name+"施放技能:"+config.uuid+"=>"+view.hero_name);
|
||||
|
||||
// 处理CD和消耗
|
||||
switch(config.CdType) {
|
||||
case CdType.SkillCD:
|
||||
view.as.max()
|
||||
comp.cooldowns.set(skillId, config.cd); // 重置冷却时间
|
||||
break;
|
||||
case CdType.HeroCD:
|
||||
view.as.atk()
|
||||
view.at = view.at-view.cd; // 重置普攻计时器
|
||||
break;
|
||||
}
|
||||
if (config.TargetGroup === TargetGroup.Enemy) {
|
||||
const targets = this.selectEnemyTargets(caster, config);
|
||||
if (targets.length === 0) return;
|
||||
skillEntity.load(
|
||||
view.node.position, // 起始位置
|
||||
view.fac, // 阵营
|
||||
view.box_group, // 阵营
|
||||
view.node.parent, // 父节点
|
||||
config.uuid, // 技能ID
|
||||
targets[0]?.get(HeroViewComp).node.position // 目标位置
|
||||
targets[0]?.get(HeroViewComp).node.position, // 目标位置
|
||||
targets[0]?.get(HeroViewComp),
|
||||
view
|
||||
);
|
||||
targets.forEach(target => {
|
||||
this.applySkillEffect(caster, target, config,skillEntity);
|
||||
console.log("施放技能:"+config.uuid+"=>"+target.get(HeroViewComp).hero_name);
|
||||
});
|
||||
}
|
||||
|
||||
if (config.TargetGroup === TargetGroup.Ally) {
|
||||
const targets = this.selectAllyTargets(caster, config);
|
||||
if (targets.length === 0) return;
|
||||
@@ -190,10 +125,7 @@ export class HeroSkillSystem extends ecs.ComblockSystem implements ecs.ISystemUp
|
||||
|
||||
// 直接计算伤害(包含防御减免)
|
||||
const damageResult = this.calculateDamage(caster, target, config);
|
||||
|
||||
// 将施法者传入applyDamage方法
|
||||
this.applyDamage(caster, target, damageResult,skillEntity);
|
||||
|
||||
|
||||
// 播放技能特效
|
||||
casterView.playSkillEffect(config.uuid);
|
||||
console.log(`${casterView.hero_name} 对 ${targetView.hero_name} 造成 ${damageResult.value}伤害`);
|
||||
@@ -231,61 +163,6 @@ export class HeroSkillSystem extends ecs.ComblockSystem implements ecs.ISystemUp
|
||||
return result;
|
||||
}
|
||||
|
||||
private applyDamage(caster: ecs.Entity, target: ecs.Entity, result: any,skillEntity:ecs.Entity) {
|
||||
const casterView = caster.get(HeroViewComp);
|
||||
const targetView = target.get(HeroViewComp);
|
||||
const skillView = skillEntity.get(SkillCom);
|
||||
if (!casterView || !targetView || !skillView) return;
|
||||
|
||||
// 计算距离
|
||||
const distance = this.calculateDistance(
|
||||
skillView.node.position,
|
||||
targetView.node.position
|
||||
);
|
||||
|
||||
|
||||
// 计算实际延迟时间(秒)
|
||||
const actualDelay = distance / (skillView.speed+targetView.speed);
|
||||
console.log("skillView:"+skillView.node.position+ " targetView:"+targetView.node.position+ " actualDelay:"+actualDelay + " dis:"+distance+ " skillView.speed:"+skillView.speed+ " targetView.speed:"+targetView.speed);
|
||||
|
||||
|
||||
this._damageQueue.push({
|
||||
timer: actualDelay,
|
||||
callback: () => {
|
||||
if (!targetView?.ent.has(HeroViewComp)) return;
|
||||
|
||||
let remainingDamage = result.value;
|
||||
if (targetView.shield > 0) {
|
||||
const shieldAbsorb = Math.min(targetView.shield, remainingDamage);
|
||||
targetView.shield -= shieldAbsorb;
|
||||
remainingDamage -= shieldAbsorb;
|
||||
|
||||
if (targetView.shield <= 0) {
|
||||
targetView.BUFFCOMP.show_shield(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (remainingDamage > 0) {
|
||||
targetView.hp -= remainingDamage;
|
||||
if(targetView.hp <= 0) {
|
||||
targetView.BUFFCOMP.dead()
|
||||
targetView.to_grave();
|
||||
}
|
||||
targetView.showDamage(result.value, true);
|
||||
} else {
|
||||
targetView.BUFFCOMP.tooltip(5,"*吸收*");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 添加计算距离的辅助方法
|
||||
private calculateDistance(pos1: Vec3, pos2: Vec3): number {
|
||||
const dx = pos2.x - pos1.x;
|
||||
const dy = pos2.y - pos1.y;
|
||||
return Math.sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
public clear_timer() {
|
||||
console.log("clear_timer");
|
||||
Object.values(this._timers).forEach(clearTimeout);
|
||||
|
||||
159
assets/script/game/skill/SkillSystem.ts
Normal file
159
assets/script/game/skill/SkillSystem.ts
Normal file
@@ -0,0 +1,159 @@
|
||||
import { Node, Vec3 } from "cc";
|
||||
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
||||
import { HeroViewComp } from "../hero/HeroViewComp";
|
||||
import { HeroSkillsComp } from "./heroSkillsComp";
|
||||
import { SkillSet, TargetGroup, TargetType } from "../common/config/SkillSet";
|
||||
import { CdType } from "../common/config/SkillSet";
|
||||
import { oops } from "db://oops-framework/core/Oops";
|
||||
import { GameEvent } from "../common/config/GameEvent";
|
||||
import { Skill } from "../skills/Skill";
|
||||
import { SkillCom } from "../skills/SkillCom";
|
||||
import { AnimType } from "../common/config/SkillSet";
|
||||
|
||||
|
||||
/** 技能系统 */
|
||||
@ecs.register('SkillSystem')
|
||||
export class SkillSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate {
|
||||
private _timers: { [key: string]: number } = {};
|
||||
private _damageQueue: Array<{ timer: number; callback: () => void }> = [];
|
||||
private readonly SKILL_RANGE_X = 10; // x轴判定范围
|
||||
private readonly SKILL_RANGE_Y = 10; // y轴判定范围
|
||||
init(): void {
|
||||
oops.message.on(GameEvent.MissionEnd, this.clear_timer, this);
|
||||
}
|
||||
filter(): ecs.IMatcher {
|
||||
return ecs.allOf(SkillCom);
|
||||
}
|
||||
|
||||
|
||||
update(e: ecs.Entity) {
|
||||
const skill = e.get(SkillCom);
|
||||
if(this.checkSkill(skill)){
|
||||
if(skill.atk_count < 1){
|
||||
skill.atk_count++;
|
||||
console.log("技能命中目标",skill.target.hero_name);
|
||||
this.applySkillEffect(skill.caster,skill.target,SkillSet[skill.s_uuid],skill);
|
||||
}
|
||||
}
|
||||
this.processDamageQueue();
|
||||
|
||||
}
|
||||
|
||||
private processDamageQueue() {
|
||||
const delta = this.dt;
|
||||
for (let i = this._damageQueue.length - 1; i >= 0; i--) {
|
||||
this._damageQueue[i].timer -= delta;
|
||||
if (this._damageQueue[i].timer <= 0) {
|
||||
this._damageQueue[i].callback();
|
||||
this._damageQueue.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
checkSkill(skill: SkillCom) {
|
||||
const targetPos = skill.target.node.position;
|
||||
const target = skill.target;
|
||||
const skillPos = skill.node.position;
|
||||
// 根据技能配置获取判定范围
|
||||
const config = SkillSet[skill.s_uuid];
|
||||
const rangeX = config?.rangeX || 20; // 默认值为10
|
||||
const rangeY = config?.rangeY || 20;
|
||||
const distanceX = Math.abs(targetPos.x - skillPos.x);
|
||||
const distanceY = Math.abs(targetPos.y - skillPos.y);
|
||||
const isInRange = distanceX < rangeX && distanceY < rangeY;
|
||||
return isInRange;
|
||||
}
|
||||
/** 应用技能效果 */
|
||||
private applySkillEffect(casterView:HeroViewComp, targetView: HeroViewComp, config: typeof SkillSet[keyof typeof SkillSet],skill:SkillCom) {
|
||||
|
||||
// 直接计算伤害(包含防御减免)
|
||||
const damageResult = this.calculateDamage(casterView, casterView, config);
|
||||
// 将施法者传入applyDamage方法
|
||||
this.applyDamage(targetView,damageResult);
|
||||
// 播放技能特效
|
||||
casterView.playSkillEffect(config.uuid);
|
||||
console.log(`${casterView.hero_name} 对 ${targetView.hero_name} 造成 ${damageResult.value}伤害`);
|
||||
}
|
||||
|
||||
private calculateDamage(caster: HeroViewComp, target: HeroViewComp, config: typeof SkillSet[keyof typeof SkillSet]) {
|
||||
const result = {
|
||||
value: 0,
|
||||
isCrit: false,
|
||||
isDodged: false,
|
||||
delay: 0.3, // 默认延迟
|
||||
ignoreDefense: false,
|
||||
canCrit: true,
|
||||
}
|
||||
|
||||
// 计算延迟时间
|
||||
if (config.AnimType === AnimType.parabolic) {
|
||||
const sourcePos = caster.node.position;
|
||||
const targetPos = target.node.position;
|
||||
// 计算距离除以速度得到时间
|
||||
const distance = Math.abs(targetPos.x - sourcePos.x);
|
||||
result.delay = distance / config.speed;
|
||||
}
|
||||
|
||||
const sourceView = caster;
|
||||
let final = sourceView.ap * config.ap / 100;
|
||||
|
||||
// 伤害浮动(±10%)
|
||||
const damageFloat = 0.9 + Math.random() * 0.2; // 0.9~1.1
|
||||
final *= damageFloat;
|
||||
final = Math.round(final);
|
||||
|
||||
result.value = Math.max(1, final); // 确保最小伤害为1
|
||||
result.isCrit = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
private applyDamage(targetView: HeroViewComp, result: any,) {;
|
||||
|
||||
this._damageQueue.push({
|
||||
timer: 0,
|
||||
callback: () => {
|
||||
if (!targetView?.ent.has(HeroViewComp)) return;
|
||||
|
||||
let remainingDamage = result.value;
|
||||
if (targetView.shield > 0) {
|
||||
const shieldAbsorb = Math.min(targetView.shield, remainingDamage);
|
||||
targetView.shield -= shieldAbsorb;
|
||||
remainingDamage -= shieldAbsorb;
|
||||
|
||||
if (targetView.shield <= 0) {
|
||||
targetView.BUFFCOMP.show_shield(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (remainingDamage > 0) {
|
||||
targetView.hp -= remainingDamage;
|
||||
if(targetView.hp <= 0) {
|
||||
targetView.BUFFCOMP.dead()
|
||||
targetView.to_grave();
|
||||
}
|
||||
targetView.showDamage(result.value, true);
|
||||
} else {
|
||||
targetView.BUFFCOMP.tooltip(5,"*吸收*");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public clear_timer() {
|
||||
console.log("clear_timer");
|
||||
Object.values(this._timers).forEach(clearTimeout);
|
||||
}
|
||||
onDestroy() {
|
||||
Object.values(this._timers).forEach(clearTimeout);
|
||||
}
|
||||
|
||||
|
||||
/** 应用负面状态 */
|
||||
private applyDebuff(target: ecs.Entity, config: typeof SkillSet[keyof typeof SkillSet]) {
|
||||
// 实现debuff逻辑...
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
9
assets/script/game/skill/SkillSystem.ts.meta
Normal file
9
assets/script/game/skill/SkillSystem.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.23",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "9b14bcef-b9c5-4132-ab96-e089fc1d8545",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
Reference in New Issue
Block a user