Files
heros/assets/script/game/hero/HeroViewComp.ts
2025-08-19 19:40:34 +08:00

644 lines
22 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, geDebuffNum, getBuffNum, 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 { RandomManager } from "db://oops-framework/core/common/random/RandomManager";
import { EnhancementType } from "../common/config/LevelUp";
import { MonsterDropManager } from "../common/config/Items";
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";
lv:number =1;
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_count_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;
speed: number = 100; /** 角色移动速度 */
speed_base: number = 100; /** 角色初始速度 */
power:number=0;
power_max:number=100;
hp: number = 100; /** 血量 */
hp_max: number = 100; /** 最大血量 */
hp_base:number=0;
shield:number=0; //当前护甲值
shield_max:number=0; //最大护甲值
ap: number = 10; /**攻击力 */
ap_base:number=0;
// atk_speed: number = 1;
cd: number = 1.3; /**攻击速度 攻击间隔 */
def: number = 0; //防御
dmg_red:number=0//免伤
dis: number = 80;
skills:any[]=[]
puncture:number=0; //穿刺敌人伤害后方敌人个数
puncture_damage:number=0; //后伤害加成
burn: number = 0; //易伤 伤害加成
stun_time:number=0; //眩晕加成
stun_ratio:number=0; //攻击眩晕概率加成
stun_no:boolean=false; //眩晕免疫
dod: number = 0; //闪避率
dod_no:boolean=false;
crit:number=0; //暴击率
crit_no:boolean=false; //暴击免疫
crit_d:number=0; //暴击伤害
wfuny:number=0; //风怒概率
frost_ratio:number=0; //冰冻概率
frost_time:number=0; //冰冻时间
frost_no:boolean=false; //冰冻免疫
knockback:number=0; //击退概率
knockback_no:boolean=false; //击退免疫
reflect:number=0; //反射伤害比率
lifesteal:number=0; //吸血比率
skill_dmg:number=0
debuff_down:number=0
Attrs:any=getBuffNum()
debuff_status:any=geDebuffNum()
atk_count: number = 0;
atked_count: number = 0;
stop_cd: number = 0; /*停止倒计时*/
speek_time:number = 0;
BUFFS:Array<{value: number, duration: number,type:number}> = [] //buff
DEBUFF_BURNS: Array<{value: number, duration: number}> = [] //易伤
DEBUFF_DEATKS: Array<{value: number, duration: number}> = [] //减攻击
DEBUFF_DECDS: Array<{value: number, duration: 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,
anm:string,
}> = [];
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.EXPUP,this.exp_up,this)
this.on(GameEvent.HeroLvUp,this.to_update_lv,this)
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);
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.BUFFCOMP.show_shield(this.shield,this.shield_max)
}
update(dt: number){
if(!smc.mission.play||smc.mission.pause) return
// if(this.is_dead) {
// this.ent.destroy();
// return
// }
if(this.DEBUFF_FROST > 0){
this.DEBUFF_FROST -=dt;
}
if(this.DEBUFF_STUN > 0){
this.DEBUFF_STUN -=dt;
}
// 更新所有按时间减少的buff和debuff
this.updateBuffsAndDebuffs(dt);
this.in_stop(dt);
// 处理伤害队列
this.processDamageQueue();
}
do_fight_end(){
this.as.do_buff()
}
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 = this.shield_max +=shield
if(this.shield>0) this.BUFFCOMP.show_shield(this.shield,this.shield_max)
}
add_hp(hp: number = 0,is_num:boolean=true) {
this.BUFFCOMP.heathed();
let real_hp=0
let hp_max=this.Attrs[BuffAttr.HP_MAX]
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));
}
this.BUFFCOMP.hp_show(this.hp,this.Attrs[BuffAttr.HP_MAX])
// this.update_vm
}
/** 静止时间 */
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.fac==FacSet.MON) return
this.atk_count+=1
}
do_dead(){
this.do_dead_trigger()
//console.log("[HeroViewComp]:角色死亡",this.hero_uuid)
if(this.is_count_dead) return
this.is_count_dead=true
if(this.fac==FacSet.MON){
this.scheduleOnce(()=>{
let drop_item=this.do_drop()
if(drop_item.length>0){
oops.message.dispatchEvent(GameEvent.MonDead,{mon_uuid:this.hero_uuid,drops:drop_item})
}
},0.1)
}
if(this.fac==FacSet.HERO){
this.scheduleOnce(()=>{
oops.message.dispatchEvent(GameEvent.HeroDead,{hero_uuid:this.hero_uuid})
},0.1)
}
if(this.fac==FacSet.HERO){
//console.log("[HeroViewComp]:英雄死亡")
// oops.message.dispatchEvent(GameEvent.FightEnd,{victory:false})
}
}
do_drop(){
let drop_item=MonsterDropManager.calculateMonsterDrops(this.hero_uuid,smc.data.mission,1)
console.log("[HeroViewComp]:do_drop",this.hero_uuid,drop_item)
return drop_item
}
add_debuff(type:number,deV:number,deC:number,deR:number){
let n_deR=deR-this.Attrs[BuffAttr.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,duration:deC+FightSet.BURN_COUNT})
break
case DebuffAttr.DECD:
this.DEBUFF_DECDS.push({value:deV,duration: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.skills[0].cd=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.Attrs[BuffAttr.HP_MAX]-=deV/100*this.Attrs[BuffAttr.HP_MAX]
if(this.hp-this.Attrs[BuffAttr.HP_MAX]>0) this.hp=this.Attrs[BuffAttr.HP_MAX]
break
case DebuffAttr.DEATK: //99为具体数字 并且局内永久生效,其他为百分比
if(deC == 99){
this.ap-=deV
}else{
this.DEBUFF_DEATKS.push({value:deV,duration: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)
}
// 更新所有按时间减少的buff和debuff
updateBuffsAndDebuffs(dt: number) {
// 更新BUFFS
for(let i = this.BUFFS.length - 1; i >= 0; i--) {
this.BUFFS[i].duration -= dt;
if(this.BUFFS[i].duration <= 0) {
this.apply_buff(this.BUFFS[i].type,-this.BUFFS[i].value)
this.BUFFS.splice(i, 1);
}
}
// 更新DEBUFF_BURNS
for(let i = this.DEBUFF_BURNS.length - 1; i >= 0; i--) {
this.DEBUFF_BURNS[i].duration -= dt;
if(this.DEBUFF_BURNS[i].duration <= 0) {
this.DEBUFF_BURNS.splice(i, 1);
}
}
// 更新DEBUFF_DEATKS
for(let i = this.DEBUFF_DEATKS.length - 1; i >= 0; i--) {
this.DEBUFF_DEATKS[i].duration -= dt;
if(this.DEBUFF_DEATKS[i].duration <= 0) {
this.DEBUFF_DEATKS.splice(i, 1);
}
}
// 更新DEBUFF_DECDS
for(let i = this.DEBUFF_DECDS.length - 1; i >= 0; i--) {
this.DEBUFF_DECDS[i].duration -= dt;
if(this.DEBUFF_DECDS[i].duration <= 0) {
this.DEBUFF_DECDS.splice(i, 1);
}
}
}
add_buff(buff:number,duration:number,type:number){
if(this.BUFFS.find(b=>b.type==type)) {
if(this.BUFFS.find(b=>b.type==type).value<buff) {
let dis_buff_value=buff-this.BUFFS.find(b=>b.type==type).value
this.BUFFS.find(b=>b.type==type).value=buff
this.BUFFS.find(b=>b.type==type).duration=duration
this.apply_buff(type,dis_buff_value)
}
}else{
this.BUFFS.push({value:buff,duration:duration,type:type})
this.apply_buff(type,buff)
}
}
// 应用buff,有基础值的需要特殊处理,其他的直接加减
apply_buff(buff_type:number,buff_value:number){
switch(buff_type){
case BuffAttr.ATK: //攻击百分比
this.Attrs[BuffAttr.AP]+=Math.floor(buff_value/100*this.ap)
break
case BuffAttr.ATK_CD: //攻击速度百分比
this.Attrs[BuffAttr.ATK_CD]+=buff_value/100*this.cd
break
case BuffAttr.HP: //血量百分比
this.Attrs[BuffAttr.HP_MAX]+=Math.floor(buff_value/100*this.hp_max)
break
default:
this.Attrs[buff_type]+=buff_value
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_ratio:number=0,
frost_time:number=0,frost_ratio:number=0,
atked_anm:string="atked"
){
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_ratio)
}
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))
}
console.log(this.hero_name+"[HeroViewComp]:heroview :damage|hp|hp_max",damage,this.hp,this.Attrs[BuffAttr.HP_MAX])
damage=this.check_shield(damage)
if(damage <= 0) return
this.hp -= damage;
if(this.hp <= 0) {
if(this == null) return;
this.is_dead=true
if(this.BUFFCOMP){
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();
}
}
// this.update_vm
this.back()
this.showDamage(damage, is_crit,atked_anm);
}
//后退
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()
}
}
//伤害计算 debuff 易伤
count_damage(remainingDamage:number){
let min =remainingDamage*0.2
let damage=(remainingDamage-this.dmg_red)*(100-this.def+this.burn)/100
////console.log("[HeroViewComp]:最终伤害,敌人伤害值,免伤,防御,易伤",damage,remainingDamage,buff_def,def,Burn)
return Math.floor(Math.max(damage,min))
}
check_shield(damage:number){
if(this.shield <= 0 ) return damage
if(this.shield >= damage){
this.shield -= damage
this.BUFFCOMP.tooltip(TooltipTypes.uskill,"*吸收*");
if(this.shield <= 0){
this.shield=this.shield_max=0
}
damage = 0
}
if(this.shield < damage){
damage=damage-this.shield
this.shield=0
this.shield_max=0
}
this.BUFFCOMP.show_shield(this.shield,this.shield_max)
return damage
}
check_dodge(){
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) 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_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){
}
to_update_lv(event:string,data:any){
if(this.fac==FacSet.MON) return
console.log("[HeroViewComp]:升级",this.BUFFCOMP)
if(this.hero_uuid!=data.uuid) return
this.apply_buff(BuffAttr.HP_MAX,data.hp)
this.apply_buff(BuffAttr.AP,data.ap)
this.BUFFCOMP.lv_up()
// this.BUFFCOMP.tooltip(TooltipTypes.lvup)
}
/** 显示伤害数字 */
showDamage(damage: number, isCrit: boolean,anm:string="atked") {
this.damageQueue.push({
damage,
isCrit,
delay: this.damageInterval,
anm
});
}
ex_show(text:string){
switch(text){
case "blue":
this.BUFFCOMP.max_show("mr_blue")
break
case "red":
this.BUFFCOMP.max_show("mr_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,damageInfo.anm);
// 设置延时处理下一个伤害
this.scheduleOnce(() => {
this.isProcessingDamage = false;
}, this.damageInterval);
}
/** 立即显示伤害效果 */
private showDamageImmediate(damage: number, isCrit: boolean,anm:string="atked") {
// this.as.atked()
this.BUFFCOMP.hp_show(this.hp,this.Attrs[BuffAttr.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);
}
}
}