技能系统修改为 只负责普通技能

This commit is contained in:
2025-03-26 16:42:52 +08:00
parent 8e0aa200a6
commit 8b33abb973
9 changed files with 267 additions and 206 deletions

View File

@@ -299,7 +299,7 @@
"bullet": false, "bullet": false,
"awakeOnLoad": true, "awakeOnLoad": true,
"_group": 4, "_group": 4,
"_type": 1, "_type": 3,
"_allowSleep": true, "_allowSleep": true,
"_gravityScale": 1, "_gravityScale": 1,
"_linearDamping": 0, "_linearDamping": 0,

View File

@@ -14,6 +14,11 @@ const { ccclass, property } = _decorator;
@ccclass('Main') @ccclass('Main')
export class Main extends Root { export class Main extends Root {
start() { start() {
PhysicsSystem2D.instance.debugDrawFlags = EPhysics2DDrawFlags.Aabb |
EPhysics2DDrawFlags.Pair |
EPhysics2DDrawFlags.CenterOfMass |
EPhysics2DDrawFlags.Joint |
EPhysics2DDrawFlags.Shape;
} }
protected async run() { protected async run() {
smc.initialize = ecs.getEntity<Initialize>(Initialize); smc.initialize = ecs.getEntity<Initialize>(Initialize);

View File

@@ -32,42 +32,42 @@ export const HeroSet = {
StartPos:[-300,-350,-350] StartPos:[-300,-350,-350]
} }
export const HeroInfo = { export const HeroInfo = {
5001:{uuid:5001,name:"神圣守护",path:"k2", quality:3,kind:1,type:0,hp:200,ap:10,dis:180,a_cd:1,speed:500,skills:[6005],tals:"说明"}, 5001:{uuid:5001,name:"神圣守护",path:"k2", quality:3,kind:1,type:0,hp:200,ap:10,dis:400,a_cd:1,speed:50,skills:[6005],tals:"说明"},
5002:{uuid:5002,name:"幻影剑豪",path:"k1", quality:3,kind:2,type:0,hp:200,ap:10,dis:180,a_cd:1,speed:500,skills:[6005],tals:"说明"}, 5002:{uuid:5002,name:"幻影剑豪",path:"k1", quality:3,kind:2,type:0,hp:200,ap:10,dis:400,a_cd:1,speed:50,skills:[6005],tals:"说明"},
5003:{uuid:5003,name:"战争领主",path:"k5", quality:3,kind:2,type:0,hp:200,ap:10,dis:180,a_cd:1,speed:500,skills:[6005],tals:"说明"}, 5003:{uuid:5003,name:"战争领主",path:"k5", quality:3,kind:2,type:0,hp:200,ap:10,dis:400,a_cd:1,speed:50,skills:[6005],tals:"说明"},
5004:{uuid:5004,name:"混沌法师",path:"zh1", quality:3,kind:2,type:2,hp:200,ap:10,dis:500,a_cd:1.5,speed:500,skills:[6003],tals:"说明"}, 5004:{uuid:5004,name:"混沌法师",path:"zh1", quality:3,kind:2,type:2,hp:200,ap:10,dis:500,a_cd:1.5,speed:50,skills:[6003],tals:"说明"},
5005:{uuid:5005,name:"火焰法师",path:"zh2", quality:3,kind:2,type:2,hp:200,ap:15,dis:500,a_cd:1.5,speed:500,skills:[6003],tals:"说明"}, 5005:{uuid:5005,name:"火焰法师",path:"zh2", quality:3,kind:2,type:2,hp:200,ap:15,dis:500,a_cd:1.5,speed:50,skills:[6003],tals:"说明"},
5006:{uuid:5006,name:"风暴精灵",path:"m4", quality:3,kind:2,type:2,hp:200,ap:15,dis:500,a_cd:1.5,speed:500,skills:[6001],tals:"说明"}, 5006:{uuid:5006,name:"风暴精灵",path:"m4", quality:3,kind:2,type:2,hp:200,ap:15,dis:500,a_cd:1.5,speed:50,skills:[6001],tals:"说明"},
5007:{uuid:5007,name:"生命圣者",path:"d1", quality:3,kind:2,type:2,hp:200,ap:10,dis:500,a_cd:1.5,speed:500,skills:[6003],tals:"说明"}, 5007:{uuid:5007,name:"生命圣者",path:"d1", quality:3,kind:2,type:2,hp:200,ap:10,dis:500,a_cd:1.5,speed:50,skills:[6003],tals:"说明"},
5008:{uuid:5008,name:"战争祭祀",path:"d2", quality:3,kind:2,type:2,hp:200,ap:10,dis:500,a_cd:1.5,speed:500,skills:[6003],tals:"说明"}, 5008:{uuid:5008,name:"战争祭祀",path:"d2", quality:3,kind:2,type:2,hp:200,ap:10,dis:500,a_cd:1.5,speed:50,skills:[6003],tals:"说明"},
5009:{uuid:5009,name:"暴风射手",path:"a5", quality:3,kind:2,type:1,hp:200,ap:15,dis:400,a_cd:1.2,speed:500,skills:[6006],tals:"说明"}, 5009:{uuid:5009,name:"暴风射手",path:"a5", quality:3,kind:2,type:1,hp:200,ap:15,dis:400,a_cd:1.2,speed:50,skills:[6006],tals:"说明"},
5010:{uuid:5010,name:"苍穹射手",path:"a3", quality:3,kind:1,type:1,hp:200,ap:15,dis:400,a_cd:1.2,speed:500,skills:[6006],tals:"说明"}, 5010:{uuid:5010,name:"苍穹射手",path:"a3", quality:3,kind:1,type:1,hp:200,ap:15,dis:400,a_cd:1.2,speed:50,skills:[6006],tals:"说明"},
5011:{uuid:5011,name:"幽灵射手",path:"a4", quality:3,kind:2,type:1,hp:200,ap:15,dis:400,a_cd:1.2,speed:500,skills:[6006],tals:"说明"}, 5011:{uuid:5011,name:"幽灵射手",path:"a4", quality:3,kind:2,type:1,hp:200,ap:15,dis:400,a_cd:1.2,speed:50,skills:[6006],tals:"说明"},
5201:{uuid:5201,name:"兽人战士",path:"mor1", quality:1,kind:1,type:0,hp:200,ap:10,dis:180,a_cd:1,speed:500,skills:[6005],tals:"说明"}, 5201:{uuid:5201,name:"兽人战士",path:"mor1", quality:1,kind:1,type:0,hp:200,ap:10,dis:400,a_cd:1,speed:50,skills:[6005],tals:"说明"},
5202:{uuid:5202,name:"兽人刺客",path:"mor2", quality:1,kind:1,type:0,hp:200,ap:10,dis:180,a_cd:1,speed:500,skills:[6005],tals:"说明"}, 5202:{uuid:5202,name:"兽人刺客",path:"mor2", quality:1,kind:1,type:0,hp:200,ap:10,dis:400,a_cd:1,speed:50,skills:[6005],tals:"说明"},
5203:{uuid:5203,name:"兽人护卫",path:"mor3", quality:1,kind:1,type:1,hp:200,ap:15,dis:400,a_cd:1.2,speed:500,skills:[6007],tals:"说明"}, 5203:{uuid:5203,name:"兽人护卫",path:"mor3", quality:1,kind:1,type:1,hp:200,ap:15,dis:400,a_cd:1.2,speed:50,skills:[6007],tals:"说明"},
5204:{uuid:5204,name:"石卫", path:"mgem1",quality:1,kind:1,type:0,hp:200,ap:10,dis:180,a_cd:1,speed:500,skills:[6005],tals:"说明"}, 5204:{uuid:5204,name:"石卫", path:"mgem1",quality:1,kind:1,type:0,hp:200,ap:10,dis:400,a_cd:1,speed:50,skills:[6005],tals:"说明"},
5205:{uuid:5205,name:"土卫", path:"mgem2",quality:1,kind:1,type:0,hp:200,ap:10,dis:180,a_cd:1,speed:500,skills:[6005],tals:"说明"}, 5205:{uuid:5205,name:"土卫", path:"mgem2",quality:1,kind:1,type:0,hp:200,ap:10,dis:400,a_cd:1,speed:50,skills:[6005],tals:"说明"},
5206:{uuid:5206,name:"树人", path:"mgem3",quality:1,kind:1,type:0,hp:200,ap:10,dis:180,a_cd:1,speed:500,skills:[6005],tals:"说明"}, 5206:{uuid:5206,name:"树人", path:"mgem3",quality:1,kind:1,type:0,hp:200,ap:10,dis:400,a_cd:1,speed:50,skills:[6005],tals:"说明"},
5207:{uuid:5207,name:"小骷髅", path:"mkl1", quality:1,kind:1,type:0,hp:200,ap:10,dis:180,a_cd:1,speed:500,skills:[6005],tals:"说明"}, 5207:{uuid:5207,name:"小骷髅", path:"mkl1", quality:1,kind:1,type:0,hp:200,ap:10,dis:400,a_cd:1,speed:50,skills:[6005],tals:"说明"},
5208:{uuid:5208,name:"小骷髅", path:"mkl2", quality:1,kind:1,type:0,hp:200,ap:10,dis:180,a_cd:1,speed:500,skills:[6005],tals:"说明"}, 5208:{uuid:5208,name:"小骷髅", path:"mkl2", quality:1,kind:1,type:0,hp:200,ap:10,dis:400,a_cd:1,speed:50,skills:[6005],tals:"说明"},
5209:{uuid:5209,name:"小骷髅", path:"mkl3", quality:1,kind:1,type:0,hp:200,ap:10,dis:180,a_cd:1,speed:500,skills:[6005],tals:"说明"}, 5209:{uuid:5209,name:"小骷髅", path:"mkl3", quality:1,kind:1,type:0,hp:200,ap:10,dis:400,a_cd:1,speed:50,skills:[6005],tals:"说明"},
5210:{uuid:5210,name:"骷髅战士",path:"mkl4", quality:1,kind:1,type:0,hp:200,ap:10,dis:180,a_cd:1,speed:500,skills:[6005],tals:"说明"}, 5210:{uuid:5210,name:"骷髅战士",path:"mkl4", quality:1,kind:1,type:0,hp:200,ap:10,dis:400,a_cd:1,speed:50,skills:[6005],tals:"说明"},
5211:{uuid:5211,name:"骷髅战士",path:"mkl5", quality:1,kind:1,type:0,hp:200,ap:10,dis:180,a_cd:1,speed:500,skills:[6005],tals:"说明"}, 5211:{uuid:5211,name:"骷髅战士",path:"mkl5", quality:1,kind:1,type:0,hp:200,ap:10,dis:400,a_cd:1,speed:50,skills:[6005],tals:"说明"},
5212:{uuid:5212,name:"骷髅战士",path:"mkl6", quality:1,kind:1,type:0,hp:200,ap:10,dis:180,a_cd:1,speed:500,skills:[6005],tals:"说明"}, 5212:{uuid:5212,name:"骷髅战士",path:"mkl6", quality:1,kind:1,type:0,hp:200,ap:10,dis:400,a_cd:1,speed:50,skills:[6005],tals:"说明"},
5213:{uuid:5213,name:"骷髅射手",path:"mkla1",quality:1,kind:1,type:1,hp:200,ap:15,dis:400,a_cd:1.2,speed:500,skills:[6005],tals:"说明"}, 5213:{uuid:5213,name:"骷髅射手",path:"mkla1",quality:1,kind:1,type:1,hp:200,ap:15,dis:400,a_cd:1.2,speed:50,skills:[6005],tals:"说明"},
5214:{uuid:5214,name:"骷髅射手",path:"mkla2",quality:1,kind:1,type:1,hp:200,ap:15,dis:400,a_cd:1.2,speed:500,skills:[6005],tals:"说明"}, 5214:{uuid:5214,name:"骷髅射手",path:"mkla2",quality:1,kind:1,type:1,hp:200,ap:15,dis:400,a_cd:1.2,speed:50,skills:[6005],tals:"说明"},
5215:{uuid:5215,name:"骷髅射手",path:"mkla3",quality:1,kind:1,type:1,hp:200,ap:15,dis:400,a_cd:1.2,speed:500,skills:[6005],tals:"说明"}, 5215:{uuid:5215,name:"骷髅射手",path:"mkla3",quality:1,kind:1,type:1,hp:200,ap:15,dis:400,a_cd:1.2,speed:50,skills:[6005],tals:"说明"},
5216:{uuid:5216,name:"元素1", path:"my1", quality:2,kind:1,type:2,hp:200,ap:15,dis:500,a_cd:1.5,speed:500,skills:[6001],tals:"说明"}, 5216:{uuid:5216,name:"元素1", path:"my1", quality:2,kind:1,type:2,hp:200,ap:15,dis:500,a_cd:1.5,speed:50,skills:[6001],tals:"说明"},
5217:{uuid:5217,name:"元素2", path:"my2", quality:2,kind:1,type:2,hp:200,ap:15,dis:500,a_cd:1.5,speed:500,skills:[6002],tals:"说明"}, 5217:{uuid:5217,name:"元素2", path:"my2", quality:2,kind:1,type:2,hp:200,ap:15,dis:500,a_cd:1.5,speed:50,skills:[6002],tals:"说明"},
5218:{uuid:5218,name:"元素3", path:"my3", quality:2,kind:1,type:2,hp:200,ap:15,dis:500,a_cd:1.5,speed:500,skills:[6003],tals:"说明"}, 5218:{uuid:5218,name:"元素3", path:"my3", quality:2,kind:1,type:2,hp:200,ap:15,dis:500,a_cd:1.5,speed:50,skills:[6003],tals:"说明"},
5219:{uuid:5219,name:"牛头战士",path:"mn1", quality:2,kind:1,type:0,hp:200,ap:10,dis:180,a_cd:1,speed:500,skills:[6005],tals:"说明"}, 5219:{uuid:5219,name:"牛头战士",path:"mn1", quality:2,kind:1,type:0,hp:200,ap:10,dis:400,a_cd:1,speed:50,skills:[6005],tals:"说明"},
5220:{uuid:5220,name:"牛头战士",path:"mn2", quality:1,kind:1,type:1,hp:200,ap:15,dis:400,a_cd:1.2,speed:500,skills:[6010],tals:"说明"}, 5220:{uuid:5220,name:"牛头战士",path:"mn2", quality:1,kind:1,type:1,hp:200,ap:15,dis:400,a_cd:1.2,speed:50,skills:[6010],tals:"说明"},
5221:{uuid:5221,name:"牛头战士",path:"mn3", quality:1,kind:1,type:0,hp:200,ap:10,dis:180,a_cd:1,speed:500,skills:[6005],tals:"说明"}, 5221:{uuid:5221,name:"牛头战士",path:"mn3", quality:1,kind:1,type:0,hp:200,ap:10,dis:400,a_cd:1,speed:50,skills:[6005],tals:"说明"},
5222:{uuid:5222,name:"独眼巨人",path:"md1", quality:1,kind:1,type:0,hp:200,ap:10,dis:180,a_cd:1,speed:500,skills:[6005],tals:"说明"}, 5222:{uuid:5222,name:"独眼巨人",path:"md1", quality:1,kind:1,type:0,hp:200,ap:10,dis:400,a_cd:1,speed:50,skills:[6005],tals:"说明"},
5223:{uuid:5223,name:"独眼巨人",path:"md2", quality:1,kind:1,type:0,hp:200,ap:10,dis:180,a_cd:1,speed:500,skills:[6008],tals:"说明"}, 5223:{uuid:5223,name:"独眼巨人",path:"md2", quality:1,kind:1,type:0,hp:200,ap:10,dis:400,a_cd:1,speed:50,skills:[6008],tals:"说明"},
5224:{uuid:5224,name:"独眼巨人",path:"md3", quality:1,kind:1,type:1,hp:200,ap:15,dis:400,a_cd:1.2,speed:500,skills:[6005],tals:"说明"}, 5224:{uuid:5224,name:"独眼巨人",path:"md3", quality:1,kind:1,type:1,hp:200,ap:15,dis:400,a_cd:1.2,speed:50,skills:[6005],tals:"说明"},
5225:{uuid:5225,name:"精英独眼",path:"md4", quality:3,kind:1,type:2,hp:200,ap:15,dis:500,a_cd:1,speed:500,skills:[6009],tals:"说明"}, 5225:{uuid:5225,name:"精英独眼",path:"md4", quality:3,kind:1,type:2,hp:200,ap:15,dis:500,a_cd:1,speed:50,skills:[6009],tals:"说明"},
5226:{uuid:5226,name:"精英牛头",path:"mn4", quality:3,kind:1,type:2,hp:200,ap:15,dis:500,a_cd:1,speed:500,skills:[6010],tals:"说明"}, 5226:{uuid:5226,name:"精英牛头",path:"mn4", quality:3,kind:1,type:2,hp:200,ap:15,dis:500,a_cd:1,speed:50,skills:[6010],tals:"说明"},
5227:{uuid:5227,name:"精英兽人",path:"mor4", quality:3,kind:1,type:2,hp:200,ap:15,dis:500,a_cd:1,speed:500,skills:[6009],tals:"说明"} 5227:{uuid:5227,name:"精英兽人",path:"mor4", quality:3,kind:1,type:2,hp:200,ap:15,dis:500,a_cd:1,speed:50,skills:[6009],tals:"说明"}
}; };

View File

@@ -16,12 +16,10 @@ export class Hero extends ecs.Entity {
HeroModel!: HeroModelComp; HeroModel!: HeroModelComp;
HeroView!: HeroViewComp; HeroView!: HeroViewComp;
BattleMove!: BattleMoveComp; BattleMove!: BattleMoveComp;
HeroSkills!: HeroSkillsComp;
protected init() { protected init() {
this.addComponents<ecs.Comp>( this.addComponents<ecs.Comp>(
BattleMoveComp, BattleMoveComp,
HeroSkillsComp,
HeroModelComp HeroModelComp
); );
} }
@@ -61,12 +59,12 @@ export class Hero extends ecs.Entity {
hv.atk_skill=hero.skills[0] hv.atk_skill=hero.skills[0]
this.add(hv); this.add(hv);
// 初始化多个技能组件 // // 初始化多个技能组件
const skillsComp = this.get(HeroSkillsComp); // const skillsComp = this.get(HeroSkillsComp);
// 正确初始化已有技能 // // 正确初始化已有技能
hero.skills.forEach(skillId => { // hero.skills.forEach(skillId => {
this.addSkill(skillId); // 使用addSkill方法确保初始化 // this.addSkill(skillId); // 使用addSkill方法确保初始化
}); // });
// 初始化移动参数 // 初始化移动参数
const move = this.get(BattleMoveComp); const move = this.get(BattleMoveComp);

View File

@@ -1,7 +1,6 @@
import { Node, Vec3 } from "cc"; import { Node, Vec3 } from "cc";
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
import { HeroViewComp } from "../hero/HeroViewComp"; import { HeroViewComp } from "../hero/HeroViewComp";
import { HeroSkillsComp } from "./heroSkillsComp";
import { SkillSet, TargetGroup, TargetType } from "../common/config/SkillSet"; import { SkillSet, TargetGroup, TargetType } from "../common/config/SkillSet";
import { CdType } from "../common/config/SkillSet"; import { CdType } from "../common/config/SkillSet";
import { oops } from "db://oops-framework/core/Oops"; 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); oops.message.on(GameEvent.MissionEnd, this.clear_timer, this);
} }
filter(): ecs.IMatcher { filter(): ecs.IMatcher {
return ecs.allOf(HeroSkillsComp, HeroViewComp); return ecs.allOf(HeroViewComp);
} }
update(e: ecs.Entity) { update(e: ecs.Entity) {
//return false //return false
// 处理伤害队列 // 处理伤害队列
this.processDamageQueue();
const view = e.get(HeroViewComp); const view = e.get(HeroViewComp);
const skills = e.get(HeroSkillsComp);
// 使用固定时间步长更新
// 只在攻击状态触发技能 // 只在攻击状态触发技能
if (view.is_atking) { if (view.is_atking &&view.at > view.cd) {
this.processSkills(e, skills); 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]) { private castSkill(caster: ecs.Entity, skillId: number, config: typeof SkillSet[keyof typeof SkillSet]) {
const view = caster.get(HeroViewComp); const view = caster.get(HeroViewComp);
const comp = caster.get(HeroSkillsComp);
const skillEntity = ecs.getEntity<Skill>(Skill); const skillEntity = ecs.getEntity<Skill>(Skill);
console.log(view.hero_name+"施放技能:"+config.uuid+"=>"+view.hero_name); 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) { if (config.TargetGroup === TargetGroup.Enemy) {
const targets = this.selectEnemyTargets(caster, config); const targets = this.selectEnemyTargets(caster, config);
if (targets.length === 0) return; if (targets.length === 0) return;
skillEntity.load( skillEntity.load(
view.node.position, // 起始位置 view.node.position, // 起始位置
view.fac, // 阵营 view.box_group, // 阵营
view.node.parent, // 父节点 view.node.parent, // 父节点
config.uuid, // 技能ID config.uuid, // 技能ID
targets[0]?.get(HeroViewComp).node.position // 目标位置 targets[0]?.get(HeroViewComp).node.position, // 目标位置
targets[0]?.get(HeroViewComp),
view
); );
targets.forEach(target => { targets.forEach(target => {
this.applySkillEffect(caster, target, config,skillEntity); this.applySkillEffect(caster, target, config,skillEntity);
console.log("施放技能:"+config.uuid+"=>"+target.get(HeroViewComp).hero_name); console.log("施放技能:"+config.uuid+"=>"+target.get(HeroViewComp).hero_name);
}); });
} }
if (config.TargetGroup === TargetGroup.Ally) { if (config.TargetGroup === TargetGroup.Ally) {
const targets = this.selectAllyTargets(caster, config); const targets = this.selectAllyTargets(caster, config);
if (targets.length === 0) return; 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); const damageResult = this.calculateDamage(caster, target, config);
// 将施法者传入applyDamage方法
this.applyDamage(caster, target, damageResult,skillEntity);
// 播放技能特效 // 播放技能特效
casterView.playSkillEffect(config.uuid); casterView.playSkillEffect(config.uuid);
console.log(`${casterView.hero_name}${targetView.hero_name} 造成 ${damageResult.value}伤害`); 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; 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() { public clear_timer() {
console.log("clear_timer"); console.log("clear_timer");
Object.values(this._timers).forEach(clearTimeout); Object.values(this._timers).forEach(clearTimeout);

View 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逻辑...
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "9b14bcef-b9c5-4132-ab96-e089fc1d8545",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -26,7 +26,9 @@ export class Skill extends ecs.Entity {
group: number, // 阵营 group: number, // 阵营
parent: Node, // 父节点 parent: Node, // 父节点
uuid: number, // 技能ID uuid: number, // 技能ID
targetPos: Vec3 // 目标位置 targetPos: Vec3, // 目标位置
target:any=null, // 目标
caster:any=null // 施法者
) { ) {
const config = SkillSet[uuid]; const config = SkillSet[uuid];
if (!config) return; if (!config) return;
@@ -46,11 +48,14 @@ export class Skill extends ecs.Entity {
skillComp.endType = config.endType; skillComp.endType = config.endType;
skillComp.speed = config.speed; skillComp.speed = config.speed;
skillComp.inTime = config.in; skillComp.inTime = config.in;
skillComp.atk_count = 0;
skillComp.startPos = v3(startPos.x,BoxSet.GAME_LINE+35,0) skillComp.startPos = v3(startPos.x,BoxSet.GAME_LINE+35,0)
skillComp.targetPos = v3(targetPos.x,BoxSet.GAME_LINE+50,0) skillComp.targetPos = v3(targetPos.x,BoxSet.GAME_LINE+50,0)
skillComp.target = target;
skillComp.caster = caster;
skillComp.prefabName = config.sp_name; skillComp.prefabName = config.sp_name;
skillComp.group = group; skillComp.group = group;
console.log(config.sp_name+"技能配置",skillComp);
// 初始化动画名称 // 初始化动画名称
skillComp.animName = config.animName; // 从配置获取动画名称 skillComp.animName = config.animName; // 从配置获取动画名称
this.add(skillComp); this.add(skillComp);

View File

@@ -6,6 +6,7 @@ import { oops } from "../../../../extensions/oops-plugin-framework/assets/core/O
import { GameEvent } from "../common/config/GameEvent"; import { GameEvent } from "../common/config/GameEvent";
import { AnimType, endType } from "../common/config/SkillSet"; import { AnimType, endType } from "../common/config/SkillSet";
import { EndAnmCom } from './EndAnmCom'; import { EndAnmCom } from './EndAnmCom';
import { BoxSet } from "../common/config/BoxSet";
const { ccclass, property } = _decorator; const { ccclass, property } = _decorator;
@@ -14,12 +15,14 @@ const { ccclass, property } = _decorator;
@ccclass('SkillCom') @ccclass('SkillCom')
@ecs.register('SkillCom') @ecs.register('SkillCom')
export class SkillCom extends CCComp { export class SkillCom extends CCComp {
s_uuid:number = 0; s_uuid:number = 0;
s_name:string = ""; s_name:string = "";
hero:number = 0; hero:number = 0;
speed:number = 200; speed:number = 200;
scale:number = 1; scale:number = 1;
angle:number = 0; angle:number = 0;
atk_count:number = 0;
is_destroy:boolean = false; is_destroy:boolean = false;
enemys:any = []; enemys:any = [];
animType: number = 0; // 运动类型 animType: number = 0; // 运动类型
@@ -32,36 +35,37 @@ export class SkillCom extends CCComp {
animName: string = ""; animName: string = "";
group:number = 0; //阵营 group:number = 0; //阵营
rigid:RigidBody2D=null!; // 动画名称 rigid:RigidBody2D=null!; // 动画名称
target:any=null;
caster:any=null;
protected onLoad(): void { protected onLoad(): void {
}
start() {
oops.message.on(GameEvent.MissionEnd, this.doDestroy, this);
this.node.active = true;
let collider = this.getComponent(Collider2D); let collider = this.getComponent(Collider2D);
console.log(this.group +"技能 collider ",collider);
collider.group = this.group; collider.group = this.group;
// console.log("hero collider ",this.scale,collider);
if (collider) { if (collider) {
collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this); collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
// collider.on(Contact2DType.END_CONTACT, this.onEndContact, this);
collider.on(Contact2DType.PRE_SOLVE, this.onPreSolve, this);
// collider.on(Contact2DType.POST_SOLVE, this.onPostSolve, this);
} }
this.rigid = this.getComponent(RigidBody2D); this.rigid = this.getComponent(RigidBody2D);
if(this.rigid.sleep){ if(this.rigid.sleep){
console.log("hero rigid sleep ",this.scale,this.rigid); console.log(this.scale+"技能 rigid sleep ",this.rigid);
this.rigid.wakeUp(); this.rigid.wakeUp();
} }
}
onBeginContact (seCol: Collider2D, oCol: Collider2D) {
console.log("碰撞开始 ",this.scale,seCol,oCol);
}
onEndContact (seCol: Collider2D, oCol: Collider2D) { console.log("碰撞结束 ",this.scale,seCol,oCol);}
onPreSolve (seCol: Collider2D, oCol: Collider2D) {console.log("碰撞预处理 ",this.scale,seCol,oCol);}
onPostSolve (seCol: Collider2D, oCol: Collider2D) {console.log("碰撞后处理 ",this.scale,seCol,oCol); }
start() {
oops.message.on(GameEvent.MissionEnd, this.doDestroy, this);
this.node.active = true;
// 根据动画类型开始相应的运动 // 根据动画类型开始相应的运动
this.startMovement(); this.startMovement();
} }
onBeginContact (seCol: Collider2D, oCol: Collider2D) {
console.log(this.scale+"碰撞开始 ",seCol,oCol);
}
private startMovement() { private startMovement() {
switch(this.animType) { switch(this.animType) {
@@ -84,10 +88,14 @@ export class SkillCom extends CCComp {
} }
private startLinearMove() { private startLinearMove() {
if (!this.targetPos) return; if(this.group==BoxSet.HERO){
const duration = Vec3.distance(this.startPos, this.targetPos) / this.speed; this.targetPos.x=720
tween(this.node) }else{
.to(duration, { position: this.targetPos }) this.targetPos.x=-720
}
const duration = Vec3.distance(this.startPos, this.targetPos) / this.speed;
tween(this.node)
.to(duration, { position: this.targetPos })
.call(() => { .call(() => {
this.is_destroy = true; this.is_destroy = true;
}) })