import { Vec3, _decorator , v3,Collider2D,Contact2DType,Label ,Node,Prefab,instantiate,ProgressBar, Component, Material, Sprite, math, clamp, Game, tween, Color, BoxCollider2D} from "cc"; import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp"; import { HeroSpine } from "./HeroSpine"; import { BoxSet, FacSet } from "../common/config/BoxSet"; import { smc } from "../common/SingletonModuleComp"; import { Timer } from "../../../../extensions/oops-plugin-framework/assets/core/common/timer/Timer"; import { SkillSet,BuffConf,} from "../common/config/SkillSet"; import { BuffComp } from "./BuffComp"; import { oops } from "db://oops-framework/core/Oops"; import { GameEvent } from "../common/config/GameEvent"; import { FightSet, TooltipTypes } from "../common/config/Mission"; import { RandomManager } from "db://oops-framework/core/common/random/RandomManager"; import { AttrSet, HeroInfo, HeroUpSet } from "../common/config/heroSet"; import { Attrs, AttrsType, BType, NeAttrs } from "../common/config/HeroAttrs"; import { TalComp } from "./TalComp"; import { HeroModelComp, HeroBattleSystem } from "./HeroModelComp"; const { ccclass, property } = _decorator; /** 角色显示组件 */ export interface BuffInfo { attr: Attrs; value: number; remainTime?: number; } @ccclass('HeroViewComp') // 定义Cocos Creator 组件 @ecs.register('HeroView', false) // 定义ECS 组件 export class HeroViewComp extends CCComp { // ==================== View 层属性(表现相关)==================== BUFFCOMP:BuffComp=null! TALCOMP:any=null! as: HeroSpine = null! status:String = "idle" scale: number = 1; // 显示方向 box_group:number = BoxSet.HERO; // 碰撞组 is_stop:boolean = false; is_atking:boolean = false; // ==================== 直接访问 HeroModelComp ==================== private get model() { return this.ent.get(HeroModelComp); } private damageQueue: Array<{ damage: number, isCrit: boolean, delay: number, anm:string, }> = []; private isProcessingDamage: boolean = false; private damageInterval: number = 0.01; // 伤害数字显示间隔 onLoad() { this.as = this.getComponent(HeroSpine); //console.log("[HeroViewComp]:hero view comp ",this.FIGHTCON) this.on(GameEvent.FightEnd,this.do_fight_end,this) const collider = this.node.getComponent(BoxCollider2D); this.scheduleOnce(()=>{ if (collider) collider.enabled = true; // 先禁 },1) // let anm = this.node.getChildByName("anm") // anm.setScale(anm.scale.x*0.8,anm.scale.y*0.8); } /** 视图层逻辑代码分离演示 */ start () { this.as.idle() this.BUFFCOMP=this.node.getComponent(BuffComp); this.TALCOMP=this.ent.get(TalComp); // console.log("[HeroViewComp]:heroview"+this.hero_name,this.Attrs) /** 方向 */ this.node.setScale(this.scale,1); this.node.getChildByName("top").setScale(this.scale,1); if(this.is_boss){ this.node.getChildByName("top").position=v3(this.node.position.x,this.node.position.y+100,0) } /* 显示角色血*/ this.node.getChildByName("top").getChildByName("hp").active = true; this.node.getChildByName("top").getChildByName("pow").active = true; } // ==================== BUFF 系统方法直接调用 ==================== /** * 初始化角色的 buff debuff(直接调用 Model) */ initAttrs() { if (this.model) { this.model.initAttrs(); } } /** * 添加 buff 效果(直接调用 Model) */ addBuff(buffConf: BuffConf) { if (this.model) { this.model.addBuff(buffConf); } } // 属性计算方法已迁移到 Model,这里不再需要 /** * 更新临时 buff/debuff(直接调用 Model) */ updateTemporaryBuffsDebuffs(dt: number) { if (this.model) { this.model.updateTemporaryBuffsDebuffs(dt); } } /** * 清空buff(直接调用 Model) */ clearBuffs(attrIndex?: number, isBuff: boolean = true): void { if (this.model) { this.model.clearBuffs(attrIndex, isBuff); } } /** * 清理单个NeAttr(直接调用 Model) */ clearNeAttr(neAttrIndex: number): void { if (this.model) { this.model.clearNeAttr(neAttrIndex); } } /** * 清理所有NeAttrs(直接调用 Model) */ clearAllNeAttrs(): void { if (this.model) { this.model.clearAllNeAttrs(); } } /** * 检查是否眩晕(直接调用 Model) */ public isStun(): boolean { return this.model?.isStun() ?? false; } /** * 检查是否冰冻(直接调用 Model) */ public isFrost(): boolean { return this.model?.isFrost() ?? false; } /** * View 层每帧更新 * 注意:数据更新逻辑已移到 HeroAttrSystem,这里只负责显示 */ update(dt: number){ if(!smc.mission.play||smc.mission.pause) return // ✅ View 层职责:处理表现相关的逻辑 this.in_stop(dt); // 动画状态 this.processDamageQueue(); // 伤害数字显示队列 // ✅ 更新显示(数据由 HeroAttrSystem 更新) this.BUFFCOMP.hp_show(this.hp, this.Attrs[Attrs.HP_MAX]); this.BUFFCOMP.mp_show(this.mp, this.Attrs[Attrs.MP_MAX]); this.BUFFCOMP.show_shield(this.shield, this.Attrs[Attrs.SHIELD_MAX]); } // 注意:BaseUp 逻辑已移到 HeroAttrSystem.update() // 注意:updateTemporaryBuffsDebuffs 逻辑已移到 HeroAttrSystem.update() do_fight_end(){ this.as.do_buff() } get isActive() { return this.ent.has(HeroViewComp) && this.node?.isValid; } //状态切 status_change(type:string){ this.status=type if(type == "idle"){ this.as.idle() // this.as.change_default("idle") } if(type == "move"){ this.as.move() // this.as.change_default("move") } } add_shield(shield:number){ // 护盾数据更新由 Model 层处理,这里只负责视图表现 if(this.shield>0) this.BUFFCOMP.show_shield(this.shield,this.Attrs[Attrs.SHIELD_MAX]) } health(hp: number = 0,is_num:boolean=true) { // 生命值更新由 Model 层处理,这里只负责视图表现 this.BUFFCOMP.heathed(); this.BUFFCOMP.show_heal(hp); } /** 静止时间 */ in_stop (dt: number) { } count_atk_count(){ //主将攻击 if(this.fac==FacSet.MON) return this.atk_count+=1 } do_dead(){ // 死亡逻辑主要由 HeroBattleSystem 处理 // 这里只保留视图层的表现逻辑 if(this.is_count_dead) return this.is_count_dead=true if(this.fac==FacSet.MON){ this.scheduleOnce(()=>{ this.do_drop() },0.1) } if(this.fac==FacSet.HERO){ this.scheduleOnce(()=>{ oops.message.dispatchEvent(GameEvent.HeroDead,{hero_uuid:this.hero_uuid}) },0.1) } } do_drop(){ } do_atked(remainingDamage:number,CAttrs:any,s_uuid:number){ // 使用战斗系统处理攻击逻辑 const battleSystem = this.ent.ecs.getSystem(HeroBattleSystem); if (!battleSystem) { console.error("[HeroViewComp] HeroBattleSystem 未找到"); return; } const damage = battleSystem.doAttack(this.ent, remainingDamage, CAttrs, s_uuid); if (damage <= 0) return; // 视图层表现 let SConf=SkillSet[s_uuid] this.back() this.showDamage(damage, false, SConf.AtkedName); // 暴击状态由战斗系统内部处理 } //后退 back(){ if(this.fac==FacSet.MON) { let tx=this.node.position.x+5 if(tx > 320) tx=320 tween(this.node).to(0.1, { position:v3(tx,this.node.position.y,0)}).start() } if(this.fac==FacSet.HERO) { let tx=this.node.position.x-5 if(tx < -320) tx=-320 tween(this.node).to(0.1, { position:v3(tx,this.node.position.y,0)}).start() } } // 伤害计算和战斗逻辑已迁移到 HeroBattleSystem do_dead_trigger(){ //死亡特殊处理 if(this.is_dead||this.fac==FacSet.MON) return } do_atked_trigger(){ //受伤特殊处理 if(this.is_dead||this.fac==FacSet.MON) return } to_grave(){ tween(this.node).to(0.5, { position:v3(-900,this.node.position.y+300,0)},{ onComplete: (target?: object) => { this.node.setPosition(-900,this.node.position.y-300,0) } }).start() } // to_alive(){ // this.is_dead=false // this.currentHp=this.currentHpMax*(100+this.hp_buff)/100 // this.BUFFCOMP.vmdata_update(true) // this.node.setPosition(HeroPos[this.fight_pos].pos) // this.BUFFCOMP.heathed() // } to_console(value:any,value2:any=null,value3:any=null){ //console.log("["+this.scale+this.hero_name+']'+value,value2,value3) } reset() { this.is_dead = false; const collider = this.getComponent(Collider2D); if (collider) { collider.off(Contact2DType.BEGIN_CONTACT); } this.scheduleOnce(() => { this.node.destroy(); }, 0.1); } playSkillEffect(skill_id:number) { let skill = SkillSet[skill_id] switch(skill.act){ case "max": this.as.max() this.BUFFCOMP.tooltip(TooltipTypes.skill,skill.name,skill_id) break case "atk": this.as.atk() break } } /** 显示伤害数字 */ showDamage(damage: number, isCrit: boolean,anm:string="atked") { this.damageQueue.push({ damage, isCrit, delay: this.damageInterval, anm }); } /** 处理伤害队列 */ private processDamageQueue() { if (this.isProcessingDamage || this.damageQueue.length === 0) return; this.isProcessingDamage = true; const damageInfo = this.damageQueue.shift()!; this.showDamageImmediate(damageInfo.damage, damageInfo.isCrit,damageInfo.anm); // 设置延时处理下一个伤 this.scheduleOnce(() => { this.isProcessingDamage = false; }, this.damageInterval); } /** 立即显示伤害效果 */ private showDamageImmediate(damage: number, isCrit: boolean,anm:string="atked") { this.BUFFCOMP.hp_show(this.hp,this.Attrs[Attrs.HP_MAX]) this.BUFFCOMP.in_atked(anm,this.fac==FacSet.HERO?1:-1) this.atked_count++; if (isCrit) { this.BUFFCOMP.hp_tip(TooltipTypes.crit, damage.toFixed(0), damage); // //console.log("暴击伤害 + damage); } else { this.BUFFCOMP.hp_tip(TooltipTypes.life, damage.toFixed(0), damage); // //console.log("普通伤害:" + damage); } } }