Files
heros/assets/script/game/hero/HeroViewComp.ts
2025-06-17 17:21:54 +08:00

445 lines
14 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} 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, TargetGroup, TargetType } from "../common/config/SkillSet";
import { BuffComp } from "./BuffComp";
import { oops } from "db://oops-framework/core/Oops";
import { GameEvent } from "../common/config/GameEvent";
import { FightConComp } from "../map/FightConComp";
import { EquipSpecialAttr } from "../common/config/Equips";
import { FightSet } from "../common/config/Mission";
import { HeroPos } from "../common/config/heroSet";
import { FriendModelComp } from "./FriendModel";
import { MasterModelComp } from "./MasterModel";
const { ccclass, property } = _decorator;
/** 角色显示组件 */
@ccclass('HeroViewComp') // 定义为 Cocos Creator 组件
@ecs.register('HeroView', false) // 定义为 ECS 组件
export class HeroViewComp extends CCComp {
FIGHTCON:FightConComp=null!
BUFFCOMP:BuffComp=null!
as: HeroSpine = null!
status:String = "idle"
hero_uuid:number = 1001;
hero_name : string = "hero";
fight_pos:number=0;
lv:number =1;
slv:number =1;
scale: number = 1; /** 角色阵营 1hero -1 :mon */
type: number = 0; /**角色类型 0近战-需要贴身 1远程-保持距离 2辅助 */
fac:number=0; //阵营 0hero 1monster
atk_range:number = 150;
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;
ap_u:number=0;
ap_ur:number=0;
hp_up:number=0;
hp: number = 100; /** 血量 */
hp_max: number = 100; /** 最大血量 */
hp_speed: number = 0; //每秒回复量
pwt:Timer = new Timer(1); //计时器
ap: number = 10; /**攻击力 */
// atk_speed: number = 1;
cd: number = 1.3; /**攻击速度 攻击间隔 */
dis: number = 80;
at: number = 0; /** 冷却时间 */
atk_skill:number=0;
def: number = 0; //防御
vun: number = 0; //易伤
dodge: number = 10; //闪避率
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; /*停止倒计时*/
yun_cd: number = 0; //眩晕倒计时
ice_cd: number = 0; //冰冻倒计时
dir_y:number = 0;
speek_time:number = 0;
is_stop_temp:boolean = false;i
Friend_alive_cd:Timer=new Timer(10)
private damageQueue: Array<{
damage: number,
isCrit: boolean,
delay: number
}> = [];
private isProcessingDamage: boolean = false;
private damageInterval: number = 0.2; // 伤害数字显示间隔
private timer:Timer=new Timer(1);
onLoad() {
this.as = this.getComponent(HeroSpine);
this.FIGHTCON=this.node.parent.getComponent(FightConComp);
console.log("[HeroViewComp]:hero view comp ",this.FIGHTCON)
this.on(GameEvent.ChangeATK_EQUIP_SPECIAL_ATTR,this.change_atk,this)
// 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.setScale(this.node.scale.x*1.5,this.node.scale.y*1.5);
this.node.getChildByName("top").getChildByName("sboss").active = true;
}
/* 显示角色血量 */
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.is_dead) {
// console.log("[HeroViewComp]:alive friend cd",this.Friend_alive_cd ,this.Friend_alive_cd.elapsedTime)
if(this.Friend_alive_cd.update(dt)){
this.to_alive()
}
}
if(this.timer.update(dt)){
// this.add_ap(10)
};
if(this.ice_cd > 0){
this.ice_cd -=dt;
return
}
if(this.yun_cd > 0){
this.yun_cd -=dt;
return
}
this.in_stop(dt);
// 处理伤害队列
this.processDamageQueue();
}
change_atk(e:GameEvent,data:any){
if(data.ice){
this.atk_skill=6001
}else if(data.fire){
this.atk_skill=6002
}else if(data.wind){
this.atk_skill=6003
}else{
this.atk_skill=6001
}
}
get isActive() {
return this.ent.has(HeroViewComp) && this.node?.isValid;
}
hide_info(){
this.node.getChildByName("top").getChildByName("ihp").active = false;
this.node.getChildByName("top").getChildByName("iap").active = false;
}
//状态切换
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>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_ap(ap: number,is_num:boolean=true){
console.log("[HeroViewComp]:add_ap add:",ap,this.ap)
if(is_num){
this.ap += Math.floor(ap);
}else{
this.ap += Math.floor(ap/100*this.ap);
}
this.BUFFCOMP.update_info_ap()
}
de_ap(ap: number,is_num:boolean=true){
console.log("[HeroViewComp]:de_ap de:",ap,this.ap)
if(is_num){
this.ap -= Math.floor(ap);
}else{
this.ap -= Math.floor(ap/100*this.ap);
}
this.BUFFCOMP.update_info_ap()
}
add_hp_max(hp: number=0,is_num:boolean=true){
console.log("[HeroViewComp]:add_hp_max add:",hp,this.hp_max)
if(is_num){
this.hp_max += Math.floor(hp) ;
this.hp += Math.floor(hp) ;
}else{
this.hp_max += Math.floor(hp/100*this.hp_max);
this.hp += Math.floor(hp/100*this.hp_max);
}
this.BUFFCOMP.update_info_hp()
}
de_hp_max(hp: number=0,is_num:boolean=true){
console.log("[HeroViewComp]:de_hp_max de:",hp,this.hp_max)
if(is_num){
this.hp_max -= Math.floor(hp) ;
}else{
this.hp_max -= Math.floor(hp/100*this.hp_max);
}
this.BUFFCOMP.update_info_hp()
}
add_hp(hp: number = 0,is_num:boolean=true) {
this.BUFFCOMP.heathed();
if(is_num){
this.hp+=Math.floor(hp);
}else{
this.hp+=Math.floor(hp/100*this.hp_max);
}
if(this.hp > this.hp_max){
this.hp = this.hp_max;
}
this.BUFFCOMP.tooltip(2,hp.toFixed(0));
}
/** 静止时间 */
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;
}
}
}
master_count_atk_count(){ //主将攻击次数 主要有装备加成,需要单独处理
if(!this.is_master) return
this.atk_count+=1
if(this.atk_count< FightSet.ATK_ADD_FRIEND_COUNT) return
if(this.FIGHTCON.atk_add_glod >0) smc.vmdata.mission_data.gold+=this.FIGHTCON.atk_add_glod
this.do_friend_atk_add()
this.do_master_atk_add()
this.atk_count=0
}
friend_count_atk_count(){ //伙伴攻击次数 有装备加成,需要单独处理
if(this.is_master) return
if(this.atk_add_count==0) return
this.atk_count+=1
if(this.atk_count < this.atk_add_count) return
}
do_friend_atk_add(){
let friends=ecs.query(ecs.allOf(FriendModelComp))
friends.forEach(friend=>{
let friend_view=friend.get(HeroViewComp)
if(this.FIGHTCON.atk_add_friend_atk>0) {
friend_view.add_ap(this.FIGHTCON.atk_add_friend_atk)
}
if(this.FIGHTCON.atk_add_friend_hp>0) {
friend_view.add_hp_max(this.FIGHTCON.atk_add_friend_hp)
}
})
}
do_master_atk_add(){
let master=ecs.query(ecs.allOf(MasterModelComp))
master.forEach(master=>{
let master_view=master.get(HeroViewComp)
if(this.FIGHTCON.atk_add_master_atk>0) {
master_view.add_ap(this.FIGHTCON.atk_add_master_atk)
}
if(this.FIGHTCON.atk_add_master_hp>0) {
master_view.add_hp_max(this.FIGHTCON.atk_add_master_hp)
}
})
}
do_change(){
this.BUFFCOMP.update_info_ap()
this.BUFFCOMP.update_info_hp()
this.BUFFCOMP.update_info_lv()
}
do_update(){
this.BUFFCOMP.update_info_ap()
this.BUFFCOMP.update_info_hp()
this.BUFFCOMP.update_info_lv()
}
do_dead(){
this.Friend_alive_cd=new Timer(this.FIGHTCON.friend_alive_cd)
console.log("[HeroViewComp]:角色死亡",this.hero_uuid)
if(this.is_master){
console.log("[HeroViewComp]:英雄死亡")
oops.message.dispatchEvent(GameEvent.FightEnd,{victory:false})
}
}
do_atked(remainingDamage:number){
if (this.shield > 0) {
this.shield -= 1
this.BUFFCOMP.tooltip(5,"*吸收*");
remainingDamage = 0
if (this.shield <= 0) {
if(this == null) return;
this.BUFFCOMP.show_shield(false);
}
}else{
if(this == null) return;
this.hp -= remainingDamage;
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();
}
}
this.BUFFCOMP.update_info_hp()
this.showDamage(remainingDamage, true);
}
}
dead(){
this.BUFFCOMP.dead()
this.to_drop()
}
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
this.BUFFCOMP.update_info_hp()
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(3,skill.name,skill_id)
break
case "atk":
this.as.atk()
break
}
}
to_update(){
this.ap=this.ap*this.lv
}
/** 显示伤害数字 */
showDamage(damage: number, isCrit: boolean) {
this.damageQueue.push({
damage,
isCrit,
delay: this.damageInterval
});
}
/** 处理伤害队列 */
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.BUFFCOMP.in_atked();
this.atked_count++;
if (isCrit) {
this.BUFFCOMP.tooltip(4, damage.toFixed(0), damage);
// console.log("暴击伤害:" + damage);
} else {
this.BUFFCOMP.tooltip(1, damage.toFixed(0), damage);
// console.log("普通伤害:" + damage);
}
}
}