Files
heros/assets/script/game/hero/HeroViewComp.ts
walkpan 2cdb25ac58 refactor(skillSet): 基本功完成 新buff系统 优化DBuff与Attrs映射及转换逻辑
- 规范化DBuff的枚举命名,修正属性对应关系
- 统一DBuff与Attrs的双向映射,通过TransformBuffs函数处理转换
- 移除旧的getAttrFieldFromDebuff方法,改用更灵活的映射数组
- 更新Attrs枚举,增加被易伤、防护盾等新属性
- 重新调整AttrsType映射,保证属性类型一致性

refactor(hero): 重构Hero和Monster初始化属性及buff系统

- Hero初始化时完善基础属性赋值,新增基础移动速度与攻击距离
- Hero使用initAttrs替代initBuffsDebuffs,重构buff/debuff初始化流程
- Monster初始化简化,统一按Hero写法初始化基础属性和Attrs
- 实现buff/debuff属性智能覆盖与叠加时长的改进逻辑
- 属性计算改用统一逻辑,支持数值型和百分比型准确计算
- 增加属性值范围限制,确保部分属性在合理区间内

refactor(heroViewComp): 优化buff/debuff管理及状态判断

- 统一buff和debuff的持久与临时管理字典及更新方法
- 优化临时buff/debuff的更新时间处理,自动触发属性重新计算
- 提供isStun和isFrost接口简化眩晕、冰冻状态判断
- 规范注释及代码格式,提升可读性和维护性

refactor(skillConComp): 优化眩晕与冰冻状态判断逻辑

- 移除遍历判断,改用HeroViewComp的isStun和isFrost方法
- 简化技能冷却更新逻辑,提升性能

chore(heroSet): 添加AttrSet枚举定义属性最大值限制

docs(rogueConfig): 更新说明文档中的属性枚举定义说明

- 将属性增强枚举由BuffAttr修改为Attrs,以保持一致性
2025-10-17 22:02:23 +08:00

799 lines
27 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 { Attrs, DBuff, SkillSet, BType, BuffConf, DbuffConf, TransformBuffs, AttrsType } 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";
const { ccclass, property } = _decorator;
/**
* ==================== BUFF 系统使用说明 ====================
*
* 1. 系统架构
* - BUFF_V/BUFFS_V: 数值型 buff持临时
* - BUFF_R/BUFFS_R: 百分比型 buff持临时
* - DBUFF_V/DBUFFS_V: 数值型 debuff持临时
* - DBUFF_R/DBUFFS_R: 百分比型 debuff持临时
*
* 2. 智能覆盖规则
* - 值更小:不添加(弱效果不覆盖强效果)
* - 值相同且临时:叠加时
* - 值更大:更新为新值(临时则更新值和时间
*
* 3. 性能优化
* - 增量计算:添删除时只重算受影响的属
* - 批量计算initBuffsDebuffs() 中使recalculateAttrs() 一次性计算所
*/
/** 角色显示组件 */
@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;
mp: number = 100;
hp: number = 100; /** 血*/
shield:number=0; //当前护甲
/** 基础属有初始值的基础属后续Attrs 属性计算时用到*/
base_ap: number = 0; //基础攻击
base_map: number = 0;
base_def: number = 5;
base_hp: number = 100;
base_mp: number = 100;
base_speed: number = 100; /** 角色移动速度 */
base_dis: number = 100;
Attrs:any=[]
// Buff/Debuff 字典结构,通过属性索引直接访
// 结构: { [attrIndex: number]: { value: number, remainTime?: number } }
DBUFF_V: Record<number, {value: number}> = {} // 持久型数debuff
DBUFF_R: Record<number, {value: number}> = {} // 持久型百分比 debuff
BUFF_V: Record<number, {value: number}> = {} // 持久型数buff
BUFF_R: Record<number, {value: number}> = {} // 持久型百分比 buff
DBUFFS_V: Record<number, {value: number, remainTime: number}> = {} // 临时型数debuff
DBUFFS_R: Record<number, {value: number, remainTime: number}> = {} // 临时型百分比 debuff
BUFFS_V: Record<number, {value: number, remainTime: number}> = {} // 临时型数buff
BUFFS_R: Record<number, {value: number, remainTime: number}> = {} // 临时型百分比 buff
atk_count: number = 0;
atked_count: number = 0;
speek_time:number = 0;
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);
// 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.Attrs[Attrs.SHIELD_MAX])
}
// ==================== BUFF系统初始====================
/**
* 初始化角色的 buff debuff
* HeroInfo 读取初始配置,建立属性系
*/
initAttrs() {
// 清空现有 buff/debuff
this.BUFF_V = {};
this.BUFFS_V = {};
this.BUFF_R = {};
this.BUFFS_R = {};
this.DBUFF_V = {};
this.DBUFFS_V = {};
this.DBUFF_R = {};
this.DBUFFS_R = {};
// 获取英雄配置
const heroInfo = HeroInfo[this.hero_uuid];
if (!heroInfo) return;
// 1. 重置为基础
this.Attrs[Attrs.HP_MAX] = this.base_hp;
this.Attrs[Attrs.MP_MAX] = this.base_mp;
this.Attrs[Attrs.DEF] = this.base_def;
this.Attrs[Attrs.AP] = this.base_ap;
this.Attrs[Attrs.MAP] = this.base_map;
this.Attrs[Attrs.SPEED] = this.base_speed;
this.Attrs[Attrs.DIS] = this.base_dis;
// 2. 初始化其他属性(无初始值的
for (const attrKey in this.Attrs) {
const attrIndex = parseInt(attrKey);
if(
attrIndex !== Attrs.HP_MAX &&
attrIndex !== Attrs.MP_MAX&&
attrIndex !== Attrs.DEF &&
attrIndex !== Attrs.AP &&
attrIndex !== Attrs.MAP &&
attrIndex !== Attrs.SPEED &&
attrIndex !== Attrs.DIS
) {
this.Attrs[attrIndex] = 0;
}
}
// 加载初始 buff
if (heroInfo.buff && heroInfo.buff.length > 0) {
for (const buffConf of heroInfo.buff) {
this.addBuff(buffConf);
}
}
// 加载初始 debuff
if (heroInfo.debuff && heroInfo.debuff.length > 0) {
for (const dbuffConf of heroInfo.debuff) {
this.addDebuff(dbuffConf);
}
}
}
// ==================== BUFF管理 ====================
/**
* 添加 buff 效果(智能覆盖)
* @param buffConf buff 配置 (来自 SkillSet.BuffConf heroSet.buff)
*
* 智能覆盖规则
* 1. 值更小:不添
* 2. 值相同且都是临时:叠加时
* 3. 值更大:更新为新值(临时则更新值和时间
*/
addBuff(buffConf: BuffConf) {
const isValue = buffConf.BType === BType.VALUE;
const isPermanent = buffConf.time === 0;
const attrIndex = buffConf.buff;
// 根据类型选择对应buff 字典
const permanentBuffs = isValue ? this.BUFF_V : this.BUFF_R;
const temporaryBuffs = isValue ? this.BUFFS_V : this.BUFFS_R;
if (isPermanent) {
// 添加持久buff
const existing = permanentBuffs[attrIndex];
if (existing) {
// 值更小,不添
if (buffConf.value <= existing.value) {
return;
}
// 值更大,更新
existing.value = buffConf.value;
} else {
// 没有同类型,直接添加
permanentBuffs[attrIndex] = { value: buffConf.value };
}
} else {
// 添加临时buff
const existing = temporaryBuffs[attrIndex];
if (existing) {
if (buffConf.value < existing.value) {
// 值更小,不添
return;
} else if (buffConf.value === existing.value) {
// 值相同,叠加时间
existing.remainTime += buffConf.time;
return; // 时间叠加不需要重算属
} else {
// 值更大,更新值和时间
existing.value = buffConf.value;
existing.remainTime = buffConf.time;
}
} else {
// 没有同类型,直接添加
temporaryBuffs[attrIndex] = {
value: buffConf.value,
remainTime: buffConf.time
};
}
}
this.recalculateSingleAttr(buffConf.buff);
}
// ==================== DEBUFF管理 ====================
/**
* 添加 debuff 效果(智能覆盖)
* @param dbuffConf debuff 配置 (来自 SkillSet.DbuffConf heroSet.debuff)
*
* 支持两种 debuff
* 1. 属性型 debuff直接修改属性值有对应的 Attrs
* 2. 状态型 debuff只缓存状态无对应的 Attrs用于状态检查
*
* 智能覆盖规则
* 1. 值更小:不添
* 2. 值相同且都是临时:叠加时
* 3. 值更大:更新为新值(临时则更新值和时间
*/
addDebuff(dbuffConf: DbuffConf) {
// 获取 debuff 对应的属性字
const isValue = dbuffConf.BType === BType.VALUE;
const isPermanent = dbuffConf.time === 0;
// 根据类型选择对应debuff 字典
const permanentDebuffs = isValue ? this.DBUFF_V : this.DBUFF_R;
const temporaryDebuffs = isValue ? this.DBUFFS_V : this.DBUFFS_R;
// 状态类 debuff 使用 debuff 类型作为 key属性类 debuff 使用 attrField 作为 key
const key = dbuffConf.debuff;
if (isPermanent) {
// 添加持久debuff
const existing = permanentDebuffs[key];
if (existing) {
// 值更小,不添
if (dbuffConf.value <= existing.value) {
return;
}
// 值更大,更新
existing.value = dbuffConf.value;
} else {
// 没有同类型,直接添加
permanentDebuffs[key] = { value: dbuffConf.value };
}
} else {
// 添加临时debuff
const existing = temporaryDebuffs[key];
if (existing) {
if (dbuffConf.value < existing.value) {
// 值更小,不添
return;
} else if (dbuffConf.value === existing.value) {
// 值相同,叠加时间
existing.remainTime += dbuffConf.time;
return; // 时间叠加不需要重算属
} else {
// 值更大,更新值和时间
existing.value = dbuffConf.value;
existing.remainTime = dbuffConf.time;
}
} else {
// 没有同类型,直接添加
temporaryDebuffs[key] = {
value: dbuffConf.value,
remainTime: dbuffConf.time
};
}
}
let attrField = TransformBuffs(dbuffConf.debuff,true);
// 只重新计算受影响的属性(状态类 debuff 不需要计算)
if (attrField > 0 ) {
this.recalculateSingleAttr(attrField);
}
}
// ==================== 属性计算系====================
/**
* 重新计算单个属性
* @param attrIndex 属性索引
*
* 计算公式:
* - 数值型属性:最终值 = (基础值 + 数值型buff - 数值型debuff) × (1 + 百分比buff/100 - 百分比debuff/100)
* - 百分比型属性:最终值 = 基础值 + 数值型buff - 数值型debuff + 百分比buff - 百分比debuff
*/
private recalculateSingleAttr(attrIndex: number) {
// 1. 获取基础值
const baseValues: Record<number, number> = {
[Attrs.HP_MAX]: this.base_hp,
[Attrs.MP_MAX]: this.base_mp,
[Attrs.DEF]: this.base_def,
[Attrs.AP]: this.base_ap,
[Attrs.MAP]: this.base_map,
[Attrs.SPEED]: this.base_speed,
[Attrs.SHIELD_MAX]: 0
};
const baseVal = baseValues[attrIndex] !== undefined ? baseValues[attrIndex] : 0;
// 2. 收集所有数值型 buff/debuff
let totalValue = baseVal;
// Buff直接使用 Attrs 索引
if (this.BUFF_V[attrIndex]) {
totalValue += this.BUFF_V[attrIndex].value;
}
if (this.BUFFS_V[attrIndex]) {
totalValue += this.BUFFS_V[attrIndex].value;
}
// Debuff需要通过 DBuff key 查找
const deKey = TransformBuffs(attrIndex, false);
if (deKey !== -1) {
if (this.DBUFF_V[deKey]) {
totalValue -= this.DBUFF_V[deKey].value;
}
if (this.DBUFFS_V[deKey]) {
totalValue -= this.DBUFFS_V[deKey].value;
}
}
// 3. 收集所有百分比型 buff/debuff
let totalRatio = 0; // 总百分比(可正可负)
// Buff直接使用 Attrs 索引
if (this.BUFF_R[attrIndex]) {
totalRatio += this.BUFF_R[attrIndex].value;
}
if (this.BUFFS_R[attrIndex]) {
totalRatio += this.BUFFS_R[attrIndex].value;
}
// Debuff需要通过 DBuff key 查找
if (deKey !== -1) {
if (this.DBUFF_R[deKey]) {
totalRatio -= this.DBUFF_R[deKey].value;
}
if (this.DBUFFS_R[deKey]) {
totalRatio -= this.DBUFFS_R[deKey].value;
}
}
// 4. 根据属性类型计算最终值
const attrType = AttrsType[attrIndex];
const isRatioAttr = attrType === BType.RATIO;
if (isRatioAttr) {
// 百分比型属性:直接加减
this.Attrs[attrIndex] = totalValue + totalRatio;
} else {
// 数值型属性:(基础值+数值) × (1 + 百分比/100)
this.Attrs[attrIndex] = Math.floor(totalValue * (1 + totalRatio / 100));
}
// 5. 确保属性值合理
this.clampSingleAttr(attrIndex);
}
/**
* 确保单个属性值合
*/
private clampSingleAttr(attrIndex: number) {
switch(attrIndex) {
case Attrs.HP_MAX:
case Attrs.MP_MAX:
this.Attrs[attrIndex] = Math.max(1, this.Attrs[attrIndex]);
break;
case Attrs.DEF:
case Attrs.AP:
case Attrs.MAP:
this.Attrs[attrIndex] = Math.max(1, this.Attrs[attrIndex]);
break;
case Attrs.CRITICAL:
case Attrs.DODGE:
case Attrs.HIT:
this.Attrs[attrIndex] = Math.max(0, Math.min(AttrSet.ATTR_MAX, this.Attrs[attrIndex])); //AttrSet.ATTR_MAX =85
break;
}
}
// ==================== 临时 BUFF/DEBUFF 更新 ====================
/**
* 更新临时 buff/debuff 的剩余时
* 应在 update 中定期调
* @param dt 时间
*/
updateTemporaryBuffsDebuffs(dt: number) {
const affectedAttrs = new Set<number>();
// 更新临时型数buff
for (const attrIndex in this.BUFFS_V) {
const buff = this.BUFFS_V[attrIndex];
buff.remainTime -= dt;
if (buff.remainTime <= 0) {
delete this.BUFFS_V[attrIndex];
affectedAttrs.add(parseInt(attrIndex));
}
}
// 更新临时型百分比 buff
for (const attrIndex in this.BUFFS_R) {
const buff = this.BUFFS_R[attrIndex];
buff.remainTime -= dt;
if (buff.remainTime <= 0) {
delete this.BUFFS_R[attrIndex];
affectedAttrs.add(parseInt(attrIndex));
}
}
// 更新临时型数debuff
for (const key in this.DBUFFS_V) {
const debuff = this.DBUFFS_V[key];
debuff.remainTime -= dt;
if (debuff.remainTime <= 0) {
delete this.DBUFFS_V[key];
const keyNum = parseInt(key);
const attrField = TransformBuffs(keyNum,true)
if(attrField > 0) affectedAttrs.add(attrField);
}
}
// 更新临时型百分比 debuff
for (const key in this.DBUFFS_R) {
const debuff = this.DBUFFS_R[key];
debuff.remainTime -= dt;
if (debuff.remainTime <= 0) {
delete this.DBUFFS_R[key];
const keyNum = parseInt(key);
const attrField = TransformBuffs(keyNum,true)
if(attrField > 0) affectedAttrs.add(attrField);
}
}
// 只重新计算受影响的属
affectedAttrs.forEach(attrIndex => {
this.recalculateSingleAttr(attrIndex);
});
}
public isStun() {
this.DBUFFS_V[DBuff.STUN] !== undefined
}
public isFrost() {
this.DBUFFS_V[DBuff.FROST] !== undefined
}
update(dt: number){
if(!smc.mission.play||smc.mission.pause) return
// if(this.is_dead) {
// this.ent.destroy();
// return
// }
this.BaseUp(dt)
// 更新所有按时间减少的buff和debuff
this.in_stop(dt);
// 处理伤害队列
this.processDamageQueue();
// 更新临时 buff/debuff 时间
this.updateTemporaryBuffsDebuffs(dt);
}
BaseUp(dt:number){
this.mp += HeroUpSet.MP*dt
this.hp += HeroUpSet.HP*dt
if(this.mp > this.Attrs[Attrs.MP_MAX]) this.mp = this.Attrs[Attrs.MP_MAX]
if(this.hp > this.Attrs[Attrs.HP_MAX]) this.hp = this.Attrs[Attrs.HP_MAX]
}
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){
this.shield = this.Attrs[Attrs.SHIELD_MAX] +=shield
if(this.shield>0) this.BUFFCOMP.show_shield(this.shield,this.Attrs[Attrs.SHIELD_MAX])
}
health(hp: number = 0,is_num:boolean=true) {
this.BUFFCOMP.heathed();
let real_hp=0
let hp_max=this.Attrs[Attrs.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[Attrs.HP_MAX])
// this.update_vm
}
/** 静止时间 */
in_stop (dt: number) {
}
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(()=>{
this.do_drop()
},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(){
}
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(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){
return remainingDamage
}
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.Attrs[Attrs.SHIELD_MAX]=0
}
damage = 0
}
if(this.shield < damage){
damage=damage-this.shield
this.shield=0
this.Attrs[Attrs.SHIELD_MAX]=0
}
this.BUFFCOMP.show_shield(this.shield,this.Attrs[Attrs.SHIELD_MAX])
return damage
}
check_dodge(){
if(this.Attrs[Attrs.DODGE] > 0){
let random = Math.random()*100
if(random < this.Attrs[Attrs.DODGE]) {
this.BUFFCOMP.tooltip(TooltipTypes.uskill,"*闪避*");
return true
}
}
return false
}
check_crit(crit:number=0){
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
}
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
});
}
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[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);
}
}
}