Files
heros/assets/script/game/hero/HeroViewComp.ts
2025-07-28 14:17:56 +08:00

700 lines
23 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 { BuffAttr, DebuffAttr, SkillSet, TGroup, TType } from "../common/config/SkillSet";
import { BuffComp } from "./BuffComp";
import { oops } from "db://oops-framework/core/Oops";
import { GameEvent } from "../common/config/GameEvent";
import { EquipSpecialAttr } from "../common/config/Equips";
import { FightSet, getExpDrops, getStoneDrops, TooltipTypes } from "../common/config/Mission";
import { getApIncrease, getHpIncrease, getUpExp, HeroInfo, HeroPos } from "../common/config/heroSet";
import { FriendModelComp } from "./FriendModel";
import { MasterModelComp } from "./MasterModel";
import { RandomManager } from "db://oops-framework/core/common/random/RandomManager";
import { EnhancementType } from "../common/config/LevelUp";
const { ccclass, property } = _decorator;
/** 角色显示组件 */
@ccclass('HeroViewComp') // 定义为 Cocos Creator 组件
@ecs.register('HeroView', false) // 定义为 ECS 组件
export class HeroViewComp extends CCComp {
BUFFCOMP:BuffComp=null!
as: HeroSpine = null!
status:String = "idle"
hero_uuid:number = 1001;
hero_name : string = "hero";
fight_pos:number=0;
lv:number =1;
exp:number = 0;
next_exp:number = 100;
scale: number = 1; /** 角色阵营 1hero -1 :mon */
type: number = 0; /**角色类型 0近战-需要贴身 1远程-保持距离 2辅助 */
fac:number=0; //阵营 0hero 1monster
box_group:number = BoxSet.HERO;
is_dead:boolean = false; //是否摧毁
is_stop:boolean = false;
is_atking:boolean = false;
is_boss:boolean = false;
is_big_boss:boolean = false;
is_master:boolean =false;
is_friend:boolean =false;
is_kalami:boolean =false;
hp: number = 100; /** 血量 */
hp_max: number = 100; /** 最大血量 */
buff_hp:number=0;
hp_base:number=0;
pwt:Timer = new Timer(1); //计时器
ap: number = 10; /**攻击力 */
buff_ap:number=0;
ap_base:number=0;
// atk_speed: number = 1;
cd: number = 1.3; /**攻击速度 攻击间隔 */
dis: number = 80;
at: number = 0; /** 冷却时间 */
atk_skill:number=0;
puncture:number=0; //穿刺敌人伤害后方敌人个数
puncture_damage:number=0; //后伤害加成
def: number = 0; //防御
vun: number = 0; //易伤
burn_count:number=0; //易伤次数
burn_value:number=0; //易伤值
stun_time:number=0; //眩晕加成
stun_ratto:number=0; //攻击眩晕概率加成
dod: number = 0; //闪避率
dod_no:boolean=false;
crit:number=0; //暴击率
crit_no:boolean=false; //暴击免疫
crit_d:number=0; //暴击伤害
wfuny:number=0; //风怒概率
frost_ratto:number=0; //冰冻概率
frost_time:number=0; //冰冻时间
shield:number = 0; //护盾,免伤1次减1
speed: number = 100; /** 角色移动速度 */
ospeed: number = 100; /** 角色初始速度 */
atk_count: number = 0;
atked_count: number = 0;
atk_add_count:number=0;
stop_cd: number = 0; /*停止倒计时*/
speek_time:number = 0;
is_stop_temp:boolean = false
double_atked:boolean=false
atk_add_master_atk:number=0
atk_add_master_hp:number=0
buff_debuff_down:number=0
skill_dmg:number=0
BUFF_DEFS: Array<{value: number, count: number}> = [] //防御提升
BUFF_ATKS: Array<{value: number, count: number}> = [] //攻击提升
BUFF_CDS: Array<{value: number, count: number}> = [] //攻击加速
BUFF_DEDOWN:Array<{value: number, count: number}> = [] //debuff 概率降低
DEBUFF_BURNS: Array<{value: number, count: number}> = [] //易伤
DEBUFF_DEATKS: Array<{value: number, count: number}> = [] //减攻击
DEBUFF_DECDS: Array<{value: number, count: number}> = [] //减攻击速度
DEBUFF_SLOW: number = 0; //减速
DEBUFF_FROST: number = 0; //冰冻
DEBUFF_STUN: number = 0; //眩晕
DEBUFF_VALUE:number=0; //debuff 增益值
DEBUFF_COUNT:number=0; //debuff 持续次数
DEBUFF_UP:number=0; //debuff 概率提升
private damageQueue: Array<{
damage: number,
isCrit: boolean,
delay: number
}> = [];
private isProcessingDamage: boolean = false;
private damageInterval: number = 0.01; // 伤害数字显示间隔
private timer:Timer=new Timer(1);
onLoad() {
this.as = this.getComponent(HeroSpine);
//console.log("[HeroViewComp]:hero view comp ",this.FIGHTCON)
this.on(GameEvent.ChangeATK_EQUIP_SPECIAL_ATTR,this.change_atk,this)
this.on(GameEvent.EXPUP,this.exp_up,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.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;
}
update(dt: number){
if(!smc.mission.play||smc.mission.pause) return
// if(this.is_dead) {
// this.ent.destroy();
// return
// }
if(this.timer.update(dt)){
// this.add_ap(10)
};
if(this.DEBUFF_FROST > 0){
this.DEBUFF_FROST -=dt;
}
if(this.DEBUFF_STUN > 0){
this.DEBUFF_STUN -=dt;
}
this.in_stop(dt);
// 处理伤害队列
this.processDamageQueue();
}
change_atk(e:GameEvent,data:any){
if(!this.is_master) return
}
get isActive() {
return this.ent.has(HeroViewComp) && this.node?.isValid;
}
hide_info(){
}
//状态切换
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){
this.shield =shield
if(this.shield>6) this.shield=6
if(this.shield>0) this.BUFFCOMP.show_shield(true)
}
// add_cd(cd: number){
// this.cd += this.cd*((100-cd)/100);
// this.BUFFCOMP.buff_get("cd")
// }
/**
* 增加英雄的攻击AP
* @param ap 要增加的攻击。
*/
add_def(def: number){
this.def+=def
if(this.is_master) this.BUFFCOMP.vmdata_update()
// this.BUFFCOMP.tooltip(TooltipTypes.defup,def.toFixed(0));
}
add_speed(cd: number){
this.cd -=this.cd*cd/100
if(this.is_master) this.BUFFCOMP.vmdata_update()
// this.BUFFCOMP.tooltip(TooltipTypes.speedup,speed.toFixed(0));
}
add_ap(ap: number,is_num:boolean=true){
// console.log("[HeroViewComp]:add_ap add:",ap,this.ap)
if(is_num){
this.ap_base += Math.floor(ap);
}else{
this.buff_ap += Math.floor(ap);
}
let diff=Math.floor(this.ap_base*(100+this.buff_ap)/100)-this.ap
this.ap = Math.floor(this.ap_base*(100+this.buff_ap)/100)
// this.BUFFCOMP.tooltip(TooltipTypes.apup,diff.toFixed(0));
if(this.is_master) {
this.BUFFCOMP.vmdata_update();
oops.message.dispatchEvent(GameEvent.APChange,{is_master:this.is_master,fac:this.fac})
}
}
de_ap(ap: number,is_num:boolean=true){
//console.log("[HeroViewComp]:de_ap de:",ap,this.ap)
if(is_num){
this.ap_base -= Math.floor(ap);
}else{
this.buff_ap -= Math.floor(ap/100*this.ap);
}
let diff=Math.floor(this.ap_base*(100+this.buff_ap)/100)-this.ap
this.ap = Math.floor(this.ap_base*(100+this.buff_ap)/100)
// this.BUFFCOMP.tooltip(TooltipTypes.apup,diff.toFixed(0));
if(this.is_master) this.BUFFCOMP.vmdata_update()
}
add_hp_max(hp: number=0,is_num:boolean=false){
// console.log("[HeroViewComp]:add_hp_max add:",hp,this.hp_max)
if(is_num){
this.hp_base += Math.floor(hp) ;
}else{
this.buff_hp+=hp
}
let diff=Math.floor(this.hp_base*(100+this.buff_hp)/100)-this.hp_max
this.hp_max =Math.floor(this.hp_base*(100+this.buff_hp)/100)
this.hp+=diff
if(this.is_master) this.BUFFCOMP.vmdata_update(true)
// this.BUFFCOMP.tooltip(TooltipTypes.hpup,diff.toFixed(0));
}
de_hp_max(hp: number=0,is_num:boolean=true){ //最大值 只存在数值添加, 比例通过buff_hp处理
//console.log("[HeroViewComp]:de_hp_max de:",hp,this.hp_max)
this.hp_base -= Math.floor(hp) ;
let diff=Math.floor(this.hp_base*(100+this.buff_hp)/100)-this.hp_max
this.hp_max =Math.floor(this.hp_base*(100+this.buff_hp)/100)
this.hp+=diff
if(this.is_master) this.BUFFCOMP.vmdata_update(true)
}
add_hp(hp: number = 0,is_num:boolean=true) {
this.BUFFCOMP.heathed();
let real_hp=0
let hp_max=Math.floor(this.hp_max*(100+this.buff_hp)/100)
let lost_hp=hp_max-this.hp
if(is_num){
if(lost_hp > hp){
real_hp=Math.floor(hp);
}else{
real_hp=lost_hp;
}
}else{
if(lost_hp > hp/100*hp_max){
real_hp=Math.floor(hp/100*hp_max);
}else{
real_hp=lost_hp;
}
}
if(real_hp > 0){
this.hp+=real_hp;
this.BUFFCOMP.tooltip(TooltipTypes.health,real_hp.toFixed(0));
}
if(this.is_master) this.BUFFCOMP.vmdata_update(true)
}
/** 静止时间 */
in_stop (dt: number) {
if(this.stop_cd > 0){
this.stop_cd -= dt;
if(this.stop_cd <= 0){
this.stop_cd = 0;
this.is_atking = false;
}
}
}
count_atk_count(){ //主将攻击次数 主要有装备加成,需要单独处理
if(!this.is_master) return
this.atk_count+=1
if(this.atk_count< FightSet.ATK_ADD_COUNT) return
let master=ecs.query(ecs.allOf(MasterModelComp))
master.forEach(master=>{
let master_view=master.get(HeroViewComp)
if(this.atk_add_master_atk>0) {
master_view.add_ap(this.atk_add_master_atk,true)
}
if(this.atk_add_master_hp>0) {
master_view.add_hp_max(this.atk_add_master_hp,true)
}
})
this.atk_count=0
}
do_dead(){
this.do_dead_trigger()
//console.log("[HeroViewComp]:角色死亡",this.hero_uuid)
if(this.fac==FacSet.MON){
oops.message.dispatchEvent(GameEvent.MonDead)
}
if(this.fac==FacSet.HERO){
//console.log("[HeroViewComp]:英雄死亡")
oops.message.dispatchEvent(GameEvent.FightEnd,{victory:false})
}
}
get_debuff(){
}
add_debuff(type:number,deV:number,deC:number,deR:number){
let DEBUFF_DOWN=0
for(let i=0;i<this.BUFF_DEDOWN.length;i++){
DEBUFF_DOWN+=this.BUFF_DEDOWN[i].value
this.BUFF_DEDOWN[i].count-=1
if(this.BUFF_DEDOWN[i].count<=0){
this.BUFF_DEDOWN.splice(i,1)
}
}
let n_deR=deR-DEBUFF_DOWN-this.buff_debuff_down // 触发概率
let r=RandomManager.instance.getRandomInt(0,100) // 随机数
//console.log("[HeroViewComp]:类型,值,次数,技能概率,实际概率,随机数",type,deV,deC,deR,n_deR,r)
if(r < n_deR) {
// this.BUFFCOMP.tooltip(TooltipTypes.uskill,"*抵抗*")
return
}
switch(type){
case DebuffAttr.BURN:
this.DEBUFF_BURNS.push({value:deV,count:deC+FightSet.BURN_COUNT})
break
case DebuffAttr.DECD:
this.DEBUFF_DECDS.push({value:deV,count:deC})
break
case DebuffAttr.SLOW:
this.DEBUFF_SLOW+=deV
break
case DebuffAttr.FROST:
this.BUFFCOMP.in_iced(deV)
this.DEBUFF_FROST+=deV
break
case DebuffAttr.STUN:
if(this.DEBUFF_STUN>0) return
this.at=0 // 眩晕 cd归零
this.BUFFCOMP.in_yun(deV+FightSet.STUN_TIME) // 眩晕时间
this.DEBUFF_STUN+=deV+FightSet.STUN_TIME // 眩晕时间
// this.is_stop=true
break
case DebuffAttr.DEHP:
this.hp_max-=deV/100*this.hp_max
if(this.hp-this.hp_max>0) this.hp=this.hp_max
break
case DebuffAttr.DEATK: //99为具体数字 并且局内永久生效,其他为百分比
if(deC == 99){
this.ap-=deV
}else{
this.DEBUFF_DEATKS.push({value:deV,count:deC})
}
break
case DebuffAttr.DECOUNT:
this.atk_count-=deV
if(this.atk_count<0) this.atk_count=1
break
case DebuffAttr.BACK:
if(this.fac==FacSet.MON) {
let tx=this.node.position.x+50
if(tx > 320) tx=320
tween(this.node).to(0.3, { position:v3(tx,this.node.position.y,0)}).start()
}
break
}
//console.log("[HeroViewComp]:debuffs",type,deV,deC,deR,this.DEBUFF_BURNS)
}
add_buff(buff:number,count:number,type:number){
switch(type){
case BuffAttr.DEF:
this.BUFF_DEFS.push({value:buff,count:count})
break
case BuffAttr.ATK:
this.BUFF_ATKS.push({value:buff,count:count})
break
case BuffAttr.ATK_CD:
this.BUFF_CDS.push({value:buff,count:count})
break
case BuffAttr.DEBUFF_DOWN:
this.BUFF_DEDOWN.push({value:buff,count:count})
break
}
}
do_atked(remainingDamage:number,
crit:number=0,crit_d:number=0,
burn_count:number=0,burn_value:number=0,
stun_time:number=0,stun_ratto:number=0,
frost_time:number=0,frost_ratto:number=0,
){
this.do_atked_trigger()
if(burn_count>0){
this.add_debuff(DebuffAttr.BURN,burn_value,burn_count,100)
}
if(stun_time>0){
this.add_debuff(DebuffAttr.STUN,stun_time,1,stun_ratto)
}
if(this.check_shield()) return
if(this.check_dodge()) return
let is_crit = this.check_crit(crit)
if(this == null) return;
let damage = this.count_damage(remainingDamage)
if(is_crit) {
damage = Math.floor(damage * (1 + (FightSet.CRIT_DAMAGE+crit_d)/100))
if(this.fac==FacSet.MON) smc.vmdata.hero.power+=smc.vmdata.hero.POWER_UP+FightSet.CRIT_TO_POWER //暴击涨能量 怪物被暴击,因为只有一个英雄 直接处理
}
this.hp -= damage;
if(this.fac==FacSet.HERO) smc.vmdata.hero.power+=smc.vmdata.hero.POWER_UP+FightSet.ATKED_TO_POWER //被攻击涨能量
if(this.fac==FacSet.MON) smc.vmdata.hero.power+=smc.vmdata.hero.POWER_UP+FightSet.ATK_TO_POWER //攻击命中涨能量 因为是只有1个英雄 直接处理
if(this.hp <= 0) {
if(this == null) return;
this.is_dead=true
this.BUFFCOMP.dead()
this.do_dead()
//console.log("[HeroViewComp]:dead,fac => "+(this.fac==FacSet.HERO?"hero":"monster"))
if(this.ent == null) return;
if(this.fac ==FacSet.HERO){
this.to_grave()
}else{
this.ent.destroy();
}
}
if(this.is_master) this.BUFFCOMP.vmdata_update(true)
this.showDamage(damage, is_crit);
}
//伤害计算 debuff 易伤
count_damage(remainingDamage:number){
let damage = 0;
let Burn = 0;
let def = 0;
for(let i=0;i<this.DEBUFF_BURNS.length;i++){
Burn+=this.DEBUFF_BURNS[i].value
this.DEBUFF_BURNS[i].count-=1
if(this.DEBUFF_BURNS[i].count<=0){
this.DEBUFF_BURNS.splice(i,1)
}
}
for(let i=0;i<this.BUFF_DEFS.length;i++){
def+=this.BUFF_DEFS[i].value
this.BUFF_DEFS[i].count-=1
if(this.BUFF_DEFS[i].count<=0){
this.BUFF_DEFS.splice(i,1)
}
}
// buff 防御 即免伤
damage=remainingDamage*(100-def-this.def+Burn)/100
////console.log("[HeroViewComp]:最终伤害,敌人伤害值,免伤,防御,易伤",damage,remainingDamage,buff_def,def,Burn)
return Math.floor(damage)
}
count_debuff(){
}
count_buff(){
}
check_shield(){
if(this.shield>0){
this.shield -= 1
this.BUFFCOMP.tooltip(TooltipTypes.uskill,"*吸收*");
if (this.shield <= 0) {
if(this == null) return;
this.BUFFCOMP.show_shield(false);
}
return true
}
return false
}
check_dodge(){
if(this.fac==FacSet.HERO) smc.vmdata.hero.power+=smc.vmdata.hero.POWER_UP+FightSet.DODGE_TO_POWER //闪避涨能量
if(this.dod > 0){
let random = Math.random()*100
if(random < this.dod) {
this.BUFFCOMP.tooltip(TooltipTypes.uskill,"*闪避*");
return true
}
}
return false
}
check_crit(crit:number=0){
if(this.crit_no) return false
if(crit > 0){
let random = Math.random()*100
if(random < crit) {
//console.log("[HeroViewComp]:crit",crit,random)
return true
}
}
//console.log("[HeroViewComp]:crit",crit)
return false
}
// dead(){
// this.BUFFCOMP.dead()
// this.to_drop()
// }
do_dead_trigger(){
if(this.is_dead||this.fac==FacSet.MON||this.is_master) return
let count = 1
for(let i=0;i<count;i++){
//console.log("[HeroViewComp]:dead"+i+"次")
}
}
do_atked_trigger(){
if(this.is_dead||this.fac==FacSet.MON) return
let count = 1
if(this.double_atked) {
//console.log("[HeroViewComp]:double_atked")
count =2
}
}
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.hp=this.hp_max*(100+this.buff_hp)/100
// this.BUFFCOMP.vmdata_update(true)
// this.node.setPosition(HeroPos[this.fight_pos].pos)
// this.BUFFCOMP.heathed()
// }
//掉落物品
to_drop(){
// let Drops = getMonsterDrops(1, MonsterType.Normal, 1.2);
// if(this.is_boss) Drops =getMonsterDrops(1, MonsterType.Elite, 1.2);
// if(this.is_big_boss) Drops =getMonsterDrops(1, MonsterType.Boss, 1.2);
}
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.max_show(skill.fname)
this.BUFFCOMP.tooltip(TooltipTypes.skill,skill.name,skill_id)
break
case "atk":
this.as.atk()
break
}
}
exp_up(e:any,data:any){
if(this.fac==FacSet.MON) return
// console.log("[HeroViewComp]:经验提高",data.exp)
smc.vmdata.hero.exp+=data.exp
// smc.vmdata.hero.next_exp=getUpExp(this.lv)
if(smc.vmdata.hero.exp >= smc.vmdata.hero.next_exp){
// console.log("[HeroViewComp]:升级")
this.to_update()
oops.message.dispatchEvent(GameEvent.CanUpdateLv)
}
}
to_update(){
// console.log("[HeroViewComp]:to_update",this.is_master)
if(!this.is_master) return
smc.vmdata.hero.exp = smc.vmdata.hero.exp-smc.vmdata.hero.next_exp
smc.vmdata.hero.lv = smc.vmdata.hero.lv+1
smc.vmdata.hero.next_exp=getUpExp(smc.vmdata.hero.lv)
oops.message.dispatchEvent(GameEvent.HeroLvUp,{lv:smc.vmdata.hero.lv})
this.BUFFCOMP.lv_up()
// this.BUFFCOMP.tooltip(TooltipTypes.lvup)
}
/** 显示伤害数字 */
showDamage(damage: number, isCrit: boolean) {
this.damageQueue.push({
damage,
isCrit,
delay: this.damageInterval
});
}
ex_show(text:string){
switch(text){
case "blue":
this.BUFFCOMP.max_show("max_blue")
break
case "red":
this.BUFFCOMP.max_show("max_red")
break
}
}
/** 处理伤害队列 */
private processDamageQueue() {
if (this.isProcessingDamage || this.damageQueue.length === 0) return;
this.isProcessingDamage = true;
const damageInfo = this.damageQueue.shift()!;
this.showDamageImmediate(damageInfo.damage, damageInfo.isCrit);
// 设置延时处理下一个伤害
this.scheduleOnce(() => {
this.isProcessingDamage = false;
}, this.damageInterval);
}
/** 立即显示伤害效果 */
private showDamageImmediate(damage: number, isCrit: boolean) {
this.as.atked()
// this.BUFFCOMP.in_atked()
this.atked_count++;
if (isCrit) {
this.BUFFCOMP.tooltip(TooltipTypes.crit, damage.toFixed(0), damage);
// //console.log("暴击伤害:" + damage);
} else {
this.BUFFCOMP.tooltip(TooltipTypes.life, damage.toFixed(0), damage);
// //console.log("普通伤害:" + damage);
}
}
}