refactor(战斗系统): 优化伤害计算与技能释放逻辑,下一步 将伤害信标处理,改为队列处理
- 移除HeroViewComp中的调试日志 - 缩短技能释放前摇时间从0.3秒到0.1秒 - 重构Skill类,清理无用导入并优化属性传递 - 改进HeroAtkSystem,添加伤害数据深拷贝避免重复处理 - 完善SkillView,增加技能结束类型处理并优化伤害应用逻辑
This commit is contained in:
@@ -27,7 +27,7 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
|||||||
private debugMode: boolean = false; // 是否启用调试模式
|
private debugMode: boolean = false; // 是否启用调试模式
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 过滤器:只处理拥有 HeroAttrsComp 的实体
|
* 过滤器:只处理拥有伤害数据的实体
|
||||||
*/
|
*/
|
||||||
filter(): ecs.IMatcher {
|
filter(): ecs.IMatcher {
|
||||||
return ecs.allOf(HeroAttrsComp, DmgDataCom);
|
return ecs.allOf(HeroAttrsComp, DmgDataCom);
|
||||||
@@ -38,22 +38,38 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
|||||||
*/
|
*/
|
||||||
entityEnter(e: ecs.Entity): void {
|
entityEnter(e: ecs.Entity): void {
|
||||||
const model = e.get(HeroAttrsComp);
|
const model = e.get(HeroAttrsComp);
|
||||||
const dmgData=e.get(DmgDataCom)
|
const dmgData = e.get(DmgDataCom);
|
||||||
if (!model || !dmgData) return;
|
if (!model || !dmgData) return;
|
||||||
let FDData = this.doAttack(e,dmgData)
|
const caster = dmgData.caster;
|
||||||
e.remove(DmgDataCom)
|
// 深度拷贝伤害数据,避免组件移除后数据丢失
|
||||||
console.log(`[HeroAtkSystem] 英雄${model.hero_name} (uuid: ${model.hero_uuid}) 受到伤害 ${FDData.damage},技能ID ${dmgData.s_uuid}`);
|
const dmgDataCopy = this.deepCopyDmgData(dmgData);
|
||||||
|
// 立即移除组件,避免重复处理
|
||||||
|
e.remove(DmgDataCom);
|
||||||
|
|
||||||
|
// 使用拷贝的数据进行伤害计算
|
||||||
|
let FDData = this.doAttack(e, dmgDataCopy);
|
||||||
|
console.log(`[HeroAtkSystem] 英雄${model.hero_name} (uuid: ${model.hero_uuid}) 受到 ${caster.ent.get(HeroAttrsComp).hero_name}(uuid: ${caster.ent.get(HeroAttrsComp).hero_uuid})的 伤害 ${FDData.damage},${FDData.isCrit?"暴击":"普通"}攻击,技能ID ${dmgDataCopy.s_uuid}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 深度拷贝伤害数据
|
||||||
|
*/
|
||||||
|
private deepCopyDmgData(dmgData: DmgDataCom): any {
|
||||||
|
return {
|
||||||
|
Attrs: dmgData.Attrs ? { ...dmgData.Attrs } : null,
|
||||||
|
s_uuid: dmgData.s_uuid
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理角色被攻击
|
* 处理角色被攻击
|
||||||
* @param target 被攻击的目标实体
|
* @param target 被攻击的目标实体
|
||||||
* @param remainingDamage 基础伤害值
|
* @param dmgData 伤害数据(可以是组件或拷贝的对象)
|
||||||
* @param attackerAttrs 攻击者的属性
|
|
||||||
* @param skillId 技能ID
|
|
||||||
* @returns 实际造成的伤害
|
* @returns 实际造成的伤害
|
||||||
*/
|
*/
|
||||||
public doAttack(target: ecs.Entity,dmgData:DmgDataCom): FDData {
|
public doAttack(target: ecs.Entity, dmgDataCopy: any): FDData {
|
||||||
const targetModel = target.get(HeroAttrsComp);
|
const targetModel = target.get(HeroAttrsComp);
|
||||||
const targetView = target.get(HeroViewComp);
|
const targetView = target.get(HeroViewComp);
|
||||||
let reDate:FDData={
|
let reDate:FDData={
|
||||||
@@ -61,11 +77,10 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
|||||||
isCrit:false,
|
isCrit:false,
|
||||||
isDodge:false,
|
isDodge:false,
|
||||||
}
|
}
|
||||||
console.log("[HeroAtkSystem] doAttack",target,dmgData)
|
|
||||||
if (!targetModel || targetModel.is_dead) return reDate;
|
if (!targetModel || targetModel.is_dead) return reDate;
|
||||||
|
|
||||||
// 获取技能配置
|
// 获取技能配置
|
||||||
const skillConf = SkillSet[dmgData.s_uuid];
|
const skillConf = SkillSet[dmgDataCopy.s_uuid];
|
||||||
if (!skillConf) return reDate;
|
if (!skillConf) return reDate;
|
||||||
|
|
||||||
// 触发被攻击事件
|
// 触发被攻击事件
|
||||||
@@ -80,8 +95,7 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
|||||||
|
|
||||||
// 暴击判定
|
// 暴击判定
|
||||||
const isCrit = this.checkCrit(targetModel.Attrs[Attrs.CRITICAL]);
|
const isCrit = this.checkCrit(targetModel.Attrs[Attrs.CRITICAL]);
|
||||||
let damage = this.dmgCount(dmgData.Attrs,dmgData.s_uuid);
|
let damage = this.dmgCount(dmgDataCopy.Attrs,dmgDataCopy.s_uuid);
|
||||||
|
|
||||||
if (isCrit) {
|
if (isCrit) {
|
||||||
damage = Math.floor(damage * (1 + (FightSet.CRIT_DAMAGE + targetModel.Attrs[Attrs.CRITICAL_DMG]) / 100));
|
damage = Math.floor(damage * (1 + (FightSet.CRIT_DAMAGE + targetModel.Attrs[Attrs.CRITICAL_DMG]) / 100));
|
||||||
reDate.isCrit=true;
|
reDate.isCrit=true;
|
||||||
@@ -91,8 +105,7 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
|||||||
damage = this.calculateDamage(targetModel, damage);
|
damage = this.calculateDamage(targetModel, damage);
|
||||||
|
|
||||||
// 护盾吸收
|
// 护盾吸收
|
||||||
damage = this.absorbShield(targetModel, damage);
|
damage =Math.floor(this.absorbShield(targetModel, damage))
|
||||||
|
|
||||||
if (damage <= 0) return reDate;
|
if (damage <= 0) return reDate;
|
||||||
|
|
||||||
// 应用伤害到数据层
|
// 应用伤害到数据层
|
||||||
@@ -101,7 +114,7 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
|||||||
|
|
||||||
// ✅ 触发视图层表现(伤害数字、受击动画、后退)
|
// ✅ 触发视图层表现(伤害数字、受击动画、后退)
|
||||||
if (targetView) {
|
if (targetView) {
|
||||||
targetView.do_atked(damage, isCrit, dmgData.s_uuid);
|
targetView.do_atked(damage, isCrit, dmgDataCopy.s_uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查死亡
|
// 检查死亡
|
||||||
@@ -121,10 +134,10 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
|
|||||||
return reDate;
|
return reDate;
|
||||||
}
|
}
|
||||||
//伤害计算,暂时简单计算
|
//伤害计算,暂时简单计算
|
||||||
private dmgCount(Attrs:any,s_uuid){
|
private dmgCount(CAttrs:any,s_uuid:number){
|
||||||
let sConf = SkillSet[s_uuid];
|
let sConf = SkillSet[s_uuid];
|
||||||
if (!sConf) return 0;
|
if (!sConf) return 0;
|
||||||
let AP = sConf.ap*Attrs[Attrs.AP];
|
let AP = sConf.ap*CAttrs[Attrs.AP]/100;
|
||||||
return AP;
|
return AP;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -297,7 +297,6 @@ export class HeroViewComp extends CCComp {
|
|||||||
let SConf=SkillSet[s_uuid]
|
let SConf=SkillSet[s_uuid]
|
||||||
this.back()
|
this.back()
|
||||||
this.showDamage(damage, isCrit, SConf.AtkedName); // 暴击状态由战斗系统内部处理
|
this.showDamage(damage, isCrit, SConf.AtkedName); // 暴击状态由战斗系统内部处理
|
||||||
console.log("[HeroViewComp] do_atked",damage,isCrit,SConf.AtkedName)
|
|
||||||
}
|
}
|
||||||
//后退
|
//后退
|
||||||
back(){
|
back(){
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ export class SACastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdat
|
|||||||
heroView.playSkillEffect(s_uuid);
|
heroView.playSkillEffect(s_uuid);
|
||||||
|
|
||||||
// 2. 延迟创建技能实体(等待动画)
|
// 2. 延迟创建技能实体(等待动画)
|
||||||
const delay = config.with ?? 0.3; // 施法前摇时间
|
const delay = 0.1
|
||||||
heroView.scheduleOnce(() => {
|
heroView.scheduleOnce(() => {
|
||||||
this.createSkill(s_uuid, heroView);
|
this.createSkill(s_uuid, heroView);
|
||||||
}, delay);
|
}, delay);
|
||||||
|
|||||||
@@ -1,17 +1,11 @@
|
|||||||
import { instantiate, Node, Prefab, v3, Vec3 } from "cc";
|
import { instantiate, Node, Prefab, v3, 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 { Hero } from "../hero/Hero";
|
|
||||||
import { Monster } from "../hero/Mon";
|
|
||||||
import { ECSEntity } from "db://oops-framework/libs/ecs/ECSEntity";
|
|
||||||
import { SkillSet } from "../common/config/SkillSet";
|
import { SkillSet } from "../common/config/SkillSet";
|
||||||
import { oops } from "db://oops-framework/core/Oops";
|
import { oops } from "db://oops-framework/core/Oops";
|
||||||
import { AtkConCom } from "./AtkConCom";
|
|
||||||
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
|
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
|
||||||
import { BoxSet, FacSet } from "../common/config/BoxSet";
|
|
||||||
import { HType } from "../common/config/heroSet";
|
|
||||||
import { SkillView } from "./SkillView";
|
import { SkillView } from "./SkillView";
|
||||||
import { SDataCom } from "./SDataCom";
|
import { SDataCom } from "./SDataCom";
|
||||||
import { Attrs } from "../common/config/HeroAttrs";
|
|
||||||
import { SMoveDataComp } from "../skill/SMoveComp";
|
import { SMoveDataComp } from "../skill/SMoveComp";
|
||||||
import { HeroViewComp } from "../hero/HeroViewComp";
|
import { HeroViewComp } from "../hero/HeroViewComp";
|
||||||
|
|
||||||
@@ -75,13 +69,14 @@ export class Skill extends ecs.Entity {
|
|||||||
sMoveCom.s_uuid=s_uuid
|
sMoveCom.s_uuid=s_uuid
|
||||||
sMoveCom.scale=caster.node.scale.x < 0 ? -1 : 1
|
sMoveCom.scale=caster.node.scale.x < 0 ? -1 : 1
|
||||||
|
|
||||||
let casterAttrs=caster.ent.get(HeroAttrsComp).Attrs
|
let cAttrsComp=caster.ent.get(HeroAttrsComp)
|
||||||
// 初始化数据组件
|
// 初始化数据组件
|
||||||
const sDataCom = this.get(SDataCom);
|
const sDataCom = this.get(SDataCom);
|
||||||
sDataCom.group=caster.box_group
|
sDataCom.group=caster.box_group
|
||||||
sDataCom.caster=caster
|
sDataCom.caster=caster
|
||||||
sDataCom.Attrs=casterAttrs
|
sDataCom.Attrs=cAttrsComp.Attrs
|
||||||
sDataCom.s_uuid=s_uuid
|
sDataCom.s_uuid=s_uuid
|
||||||
|
sDataCom.fac=cAttrsComp.fac
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 模块资源释放 */
|
/** 模块资源释放 */
|
||||||
|
|||||||
@@ -2,14 +2,15 @@ import { _decorator, Animation, CCInteger, Collider2D, Contact2DType, UITransfor
|
|||||||
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
||||||
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
|
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
|
||||||
import { HeroViewComp } from "../hero/HeroViewComp";
|
import { HeroViewComp } from "../hero/HeroViewComp";
|
||||||
import { DTType, EType, RType, SkillSet } from "../common/config/SkillSet";
|
import { DTType, EType, RType, SkillConfig, SkillSet } from "../common/config/SkillSet";
|
||||||
import { BezierMove } from "../BezierMove/BezierMove";
|
import { BezierMove } from "../BezierMove/BezierMove";
|
||||||
import { BoxSet } from "../common/config/BoxSet";
|
import { BoxSet, FacSet } from "../common/config/BoxSet";
|
||||||
import { DmgDataCom, SDataCom } from "./SDataCom";
|
import { DmgDataCom, SDataCom } from "./SDataCom";
|
||||||
import { SMoveDataComp } from "./SMoveComp";
|
import { SMoveDataComp } from "./SMoveComp";
|
||||||
import { Attrs } from "../common/config/HeroAttrs";
|
import { Attrs } from "../common/config/HeroAttrs";
|
||||||
import { MonMoveComp } from "../hero/MonMove";
|
import { MonMoveComp } from "../hero/MonMove";
|
||||||
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
|
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
|
||||||
|
import { HeroMoveComp } from "../hero/HeroMove";
|
||||||
|
|
||||||
const { ccclass, property } = _decorator;
|
const { ccclass, property } = _decorator;
|
||||||
|
|
||||||
@@ -23,15 +24,18 @@ export class SkillView extends CCComp {
|
|||||||
@property({ type: CCInteger })
|
@property({ type: CCInteger })
|
||||||
atk_y: number = 0
|
atk_y: number = 0
|
||||||
@property({ type: CCInteger })
|
@property({ type: CCInteger })
|
||||||
runType: number = 0 //技能运行类型 0-线性 1-贝塞尔 2-开始位置固定 3-目标位置固定
|
runType: RType = 0 //技能运行类型 0-线性 1-贝塞尔 2-开始位置固定 3-目标位置固定
|
||||||
|
@property({ type: CCInteger })
|
||||||
|
endType: EType = 0 //
|
||||||
|
|
||||||
anim:Animation=null;
|
anim:Animation=null;
|
||||||
group:number=0;
|
group:number=0;
|
||||||
SConf:any=null;
|
SConf:SkillConfig=null;
|
||||||
|
sData:SDataCom=null;
|
||||||
s_uuid:number=1001
|
s_uuid:number=1001
|
||||||
start() {
|
start() {
|
||||||
console.log("SkillView start scale",this.node.scale)
|
|
||||||
this.SConf = SkillSet[this.s_uuid]
|
this.SConf = SkillSet[this.s_uuid]
|
||||||
|
this.sData=this.ent.get(SDataCom)
|
||||||
this.anim=this.node.getComponent(Animation)
|
this.anim=this.node.getComponent(Animation)
|
||||||
this.node.active = true;
|
this.node.active = true;
|
||||||
let collider = this.getComponent(Collider2D);
|
let collider = this.getComponent(Collider2D);
|
||||||
@@ -67,11 +71,13 @@ export class SkillView extends CCComp {
|
|||||||
if(oCol.group!=this.group){
|
if(oCol.group!=this.group){
|
||||||
if(target == null) return;
|
if(target == null) return;
|
||||||
if (!this.SConf) return;
|
if (!this.SConf) return;
|
||||||
|
if(this.endType==EType.collision){
|
||||||
|
this.apply_damage(target)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
do_bezier(startPos:Vec3,targetPos:Vec3){
|
do_bezier(startPos:Vec3,targetPos:Vec3){
|
||||||
console.log("do_bezier",startPos,targetPos)
|
|
||||||
let bm=this.node.getComponent(BezierMove)
|
let bm=this.node.getComponent(BezierMove)
|
||||||
this.node.angle +=10
|
this.node.angle +=10
|
||||||
// bm.speed=700
|
// bm.speed=700
|
||||||
@@ -80,7 +86,6 @@ export class SkillView extends CCComp {
|
|||||||
bm.moveTo(targetPos)
|
bm.moveTo(targetPos)
|
||||||
}
|
}
|
||||||
do_linear(startPos:Vec3,targetPos:Vec3){
|
do_linear(startPos:Vec3,targetPos:Vec3){
|
||||||
console.log("do_linear",startPos,targetPos)
|
|
||||||
let bm=this.node.getComponent(BezierMove)
|
let bm=this.node.getComponent(BezierMove)
|
||||||
let s_x=startPos.x
|
let s_x=startPos.x
|
||||||
let s_y=startPos.y
|
let s_y=startPos.y
|
||||||
@@ -101,12 +106,11 @@ export class SkillView extends CCComp {
|
|||||||
bm.moveTo(targetPos);
|
bm.moveTo(targetPos);
|
||||||
}
|
}
|
||||||
do_fixedEnd(startPos:Vec3,targetPos:Vec3){
|
do_fixedEnd(startPos:Vec3,targetPos:Vec3){
|
||||||
console.log("do_fixedEnd",startPos,targetPos)
|
|
||||||
this.node.setPosition(targetPos.x > 360?300:targetPos.x,this.node.position.y,0)
|
this.node.setPosition(targetPos.x > 360?300:targetPos.x,this.node.position.y,0)
|
||||||
this.do_anim()
|
this.do_anim()
|
||||||
}
|
}
|
||||||
do_fixedStart(startPos:Vec3,targetPos:Vec3){
|
do_fixedStart(startPos:Vec3,targetPos:Vec3){
|
||||||
console.log("do_fixedStart",startPos,targetPos)
|
// console.log("do_fixedStart",startPos,targetPos)
|
||||||
this.node.setPosition(startPos.x,this.node.position.y,0)
|
this.node.setPosition(startPos.x,this.node.position.y,0)
|
||||||
this.do_anim()
|
this.do_anim()
|
||||||
}
|
}
|
||||||
@@ -118,18 +122,18 @@ export class SkillView extends CCComp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
onAnimationFinished(){
|
onAnimationFinished(){
|
||||||
|
if(this.endType==EType.animationEnd){
|
||||||
|
this.ent.destroy()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//动画帧事件 atk 触发
|
//动画帧事件 atk 触发
|
||||||
public atk(args:any){
|
public atk(args:any){
|
||||||
let dis=this.node.getComponent(UITransform).width/2
|
let dis=this.node.getComponent(UITransform).width/2
|
||||||
let sData=this.ent.get(SDataCom)
|
|
||||||
let fac=sData.fac
|
|
||||||
let enemys:any=[]
|
let enemys:any=[]
|
||||||
if(fac==BoxSet.HERO){
|
if( this.sData.fac==FacSet.HERO){
|
||||||
enemys=ecs.query(ecs.allOf(MonMoveComp))
|
enemys=ecs.query(ecs.allOf(MonMoveComp))
|
||||||
}else{
|
}else{
|
||||||
enemys=ecs.query(ecs.allOf(HeroViewComp))
|
enemys=ecs.query(ecs.allOf(HeroMoveComp))
|
||||||
}
|
}
|
||||||
let IRTargets: HeroViewComp[] = []
|
let IRTargets: HeroViewComp[] = []
|
||||||
// 收集范围内所有敌方目标
|
// 收集范围内所有敌方目标
|
||||||
@@ -174,17 +178,15 @@ export class SkillView extends CCComp {
|
|||||||
apply_damage(target:HeroViewComp,is_range:boolean=false){
|
apply_damage(target:HeroViewComp,is_range:boolean=false){
|
||||||
if(target == null) return;
|
if(target == null) return;
|
||||||
if (!this.SConf) return;
|
if (!this.SConf) return;
|
||||||
let sData=this.ent.get(SDataCom)
|
|
||||||
//伤害处理
|
//伤害处理
|
||||||
target.ent.add(DmgDataCom)
|
target.ent.addComponents<DmgDataCom>(DmgDataCom)
|
||||||
let dmgData=target.ent.get(DmgDataCom)
|
let dmgData=target.ent.get(DmgDataCom)
|
||||||
dmgData.Attrs=sData.Attrs
|
dmgData.Attrs= this.sData.Attrs
|
||||||
dmgData.caster=sData.caster
|
dmgData.caster= this.sData.caster
|
||||||
dmgData.s_uuid=sData.s_uuid
|
dmgData.s_uuid= this.sData.s_uuid
|
||||||
console.log("[SkillCom]:apply_damage",target,sData,dmgData)
|
// console.log(`[SkillCom]: ${this.sData.caster.ent.get(HeroAttrsComp).hero_name}[${this.sData.caster.ent.get(HeroAttrsComp).fac}:${ this.sData.fac}:${target.ent.get(HeroAttrsComp).fac}] 对 ${target.ent.get(HeroAttrsComp).hero_name} 释放技能 ${this.SConf.name}`)
|
||||||
sData.hit_count++
|
this.sData.hit_count++
|
||||||
// console.log("[SkillCom]:碰撞次数:技能次数:穿刺次数",this.hit_count,this.Config.hit,this.puncture)
|
if( this.sData.hit_count>=(this.SConf.hit+ this.sData.Attrs[Attrs.PUNCTURE])&&(this.SConf.DTType!=DTType.range)&&(this.endType!=EType.animationEnd)&&(this.endType!=EType.timeEnd)) this.ent.destroy// 技能命中次数
|
||||||
if(sData.hit_count>=(this.SConf.hit+sData.Attrs[Attrs.PUNCTURE])&&(this.SConf.DTType!=DTType.range)&&(this.SConf.EType!=EType.animationEnd)&&(this.SConf.EType!=EType.timeEnd)) this.ent.destroy// 技能命中次数
|
|
||||||
}
|
}
|
||||||
/** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */
|
/** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */
|
||||||
reset() {
|
reset() {
|
||||||
|
|||||||
Reference in New Issue
Block a user