2 Commits

Author SHA1 Message Date
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
94f83482fa refactor(config): 修改 Buff/Debuff 接口字段命名
- 将 DbuffConf 中的属性 deV, deC, deR 重命名为 value, time, chance
- 将 BuffConf 中的属性 buV, buC, buR 重命名为 value, time, chance
- 统一代码中 Buff 和 Debuff 配置的字段命名,提升可读性和一致性
2025-10-17 19:46:31 +08:00
15 changed files with 466 additions and 2649 deletions

View File

@@ -101,17 +101,18 @@ export enum DBuff {
SLOW = 2, //减速 - 对应Attrs.AS (攻击速度), BType.RATIO SLOW = 2, //减速 - 对应Attrs.AS (攻击速度), BType.RATIO
FROST = 3, //冰冻 - 对应Attrs.ICE_RES (冰冻抗性), BType.RATIO FROST = 3, //冰冻 - 对应Attrs.ICE_RES (冰冻抗性), BType.RATIO
BURN = 4, //易伤 - 对应Attrs.DEF/MDEF (防御/魔防), BType.RATIO, 默认次数是5, 技能配置的devC是额外次数 BURN = 4, //易伤 - 对应Attrs.DEF/MDEF (防御/魔防), BType.RATIO, 默认次数是5, 技能配置的devC是额外次数
DEAS = 5, //减速 - 对应Attrs.AS (攻击速度), BType.RATIO, 直接+技能cd AS = 5, //减速 - 对应Attrs.AS (攻击速度), BType.RATIO, 直接+技能cd
DEHP = 6, //减hp - 对应Attrs.HP_MAX (最大生命值), BType.RATIO HP_MAX = 6, //减hp - 对应Attrs.HP_MAX (最大生命值), BType.RATIO
DEAP = 7, //减atk - 对应Attrs.AP (攻击力), BType.RATIO AP = 7, //减atk - 对应Attrs.AP (攻击力), BType.RATIO
DEMGP = 8, //减魔法伤害 - 对应Attrs.MAP (魔法攻击力), BType.RATIO MGP = 8, //减魔法伤害 - 对应Attrs.MAP (魔法攻击力), BType.RATIO
BACK = 9, //击退概率 - 对应Attrs.KNOCKBACK (击退概率), BType.RATIO DEBACK = 9, //击退概率 - 对应Attrs.BACK (击退概率), BType.RATIO
CRITICAL = 10, //-暴击率 - 对应Attrs.CRITICAL (暴击率), BType.RATIO CRITICAL = 10, //-暴击率 - 对应Attrs.CRITICAL (暴击率), BType.RATIO
CRIT_DAMAGE = 11, //-暴击伤害 - 对应Attrs.CRITICAL_DMG (暴击伤害), BType.RATIO CRIT_DAMAGE = 11, //-暴击伤害 - 对应Attrs.CRITICAL_DMG (暴击伤害), BType.RATIO
DODGE = 12, //-闪避 - 对应Attrs.DODGE (闪避), BType.RATIO DODGE = 12, //-闪避 - 对应Attrs.DODGE (闪避), BType.RATIO
DBUFFUP=13, //edbuff效果提升 DBUFFUP=13, //edbuff效果提升
BUFF_DOWN = 14,// buff效果减弱 BUFF_DOWN = 14,// buff效果减弱
SPEED = 15, //移动速度下降 - 对应Attrs.MOVE_SPEED (移动速度), BType.RATIO SPEED = 15, //移动速度下降 - 对应Attrs.MOVE_SPEED (移动速度), BType.RATIO
DEBURN= 16, //被攻击带易伤
} }
@@ -131,19 +132,23 @@ export enum Attrs {
AS = 12, //攻击速度,直接减技能cd AS = 12, //攻击速度,直接减技能cd
REFLICT = 13, //反伤比率 REFLICT = 13, //反伤比率
LIFESTEAL = 14, //吸血比率 LIFESTEAL = 14, //吸血比率
KNOCKBACK = 15, //攻击带击退概率 BACK = 15, //攻击带击退概率
CON_RES = 16, //控制抗性 DEBACK = 16, //被攻击击退概率
ICE_RES = 17, //冰冻抗性 CON_RES = 17, //控制抗性
FIRE_RES = 18, //抗性 ICE_RES = 18, //冰冻抗性
WIND_RES = 19, //抗性 FIRE_RES = 19, //抗性
ICE_POWER = 20, //冰冻伤害效果提升 WIND_RES = 20, //风抗性
FIRE_POWER = 21,//伤害效果提升 ICE_POWER = 21, //冰冻伤害效果提升
WIND_POWER = 22,//伤害效果提升 FIRE_POWER = 22,//伤害效果提升
SHIELD_UP = 23, //护盾效果提升 WIND_POWER = 23,//风伤害效果提升
BUFF_UP = 24, //buff效果提升 BUFF_UP = 24, //buff效果提升
DBUFF_UP=25, //debuff效果提升 DBUFF_UP=25, //debuff效果提升
DIS=26, //攻击距离 DIS=26, //攻击距离
SPEED = 27, //移动速度加成,默认都是百分比 SPEED = 27, //移动速度加成,默认都是百分比
SHIELD_UP = 28, //护盾效果提升
BURN = 29, //攻击带易伤
DEBURN = 30, //被攻击易伤
} }
@@ -184,6 +189,8 @@ export const AttrsType: Record<Attrs, BType> = {
[Attrs.DEF]: BType.VALUE, // 防御 - 数值型 [Attrs.DEF]: BType.VALUE, // 防御 - 数值型
[Attrs.MDEF]: BType.VALUE, // 魔法防御 - 数值型 [Attrs.MDEF]: BType.VALUE, // 魔法防御 - 数值型
[Attrs.DIS]: BType.VALUE, // 攻击距离 - 数值型 [Attrs.DIS]: BType.VALUE, // 攻击距离 - 数值型
[Attrs.BURN]: BType.VALUE, // 易伤 - 数值型
[Attrs.DEBURN]: BType.VALUE, // 被攻击易伤 - 数值型
// ========== 百分比型属性 ========== // ========== 百分比型属性 ==========
[Attrs.CRITICAL]: BType.RATIO, // 暴击率 - 百分比型 [Attrs.CRITICAL]: BType.RATIO, // 暴击率 - 百分比型
@@ -194,7 +201,7 @@ export const AttrsType: Record<Attrs, BType> = {
[Attrs.AS]: BType.RATIO, // 攻击速度 - 百分比型 [Attrs.AS]: BType.RATIO, // 攻击速度 - 百分比型
[Attrs.REFLICT]: BType.RATIO, // 反伤比率 - 百分比型 [Attrs.REFLICT]: BType.RATIO, // 反伤比率 - 百分比型
[Attrs.LIFESTEAL]: BType.RATIO, // 吸血比率 - 百分比型 [Attrs.LIFESTEAL]: BType.RATIO, // 吸血比率 - 百分比型
[Attrs.KNOCKBACK]: BType.RATIO, // 击退概率 - 百分比型 [Attrs.BACK]: BType.RATIO, // 击退概率 - 百分比型
[Attrs.CON_RES]: BType.RATIO, // 控制抗性 - 百分比型 [Attrs.CON_RES]: BType.RATIO, // 控制抗性 - 百分比型
[Attrs.ICE_RES]: BType.RATIO, // 冰冻抗性 - 百分比型 [Attrs.ICE_RES]: BType.RATIO, // 冰冻抗性 - 百分比型
[Attrs.FIRE_RES]: BType.RATIO, // 火抗性 - 百分比型 [Attrs.FIRE_RES]: BType.RATIO, // 火抗性 - 百分比型
@@ -202,10 +209,11 @@ export const AttrsType: Record<Attrs, BType> = {
[Attrs.ICE_POWER]: BType.RATIO, // 冰冻伤害效果提升 - 百分比型 [Attrs.ICE_POWER]: BType.RATIO, // 冰冻伤害效果提升 - 百分比型
[Attrs.FIRE_POWER]: BType.RATIO, // 火伤害效果提升 - 百分比型 [Attrs.FIRE_POWER]: BType.RATIO, // 火伤害效果提升 - 百分比型
[Attrs.WIND_POWER]: BType.RATIO, // 风伤害效果提升 - 百分比型 [Attrs.WIND_POWER]: BType.RATIO, // 风伤害效果提升 - 百分比型
[Attrs.SHIELD_UP]: BType.RATIO, // 护盾效果提升 - 百分比型 [Attrs.DEBACK]:BType.RATIO,
[Attrs.BUFF_UP]: BType.RATIO, // buff效果提升 - 百分比型 [Attrs.BUFF_UP]: BType.RATIO, // buff效果提升 - 百分比型
[Attrs.DBUFF_UP]: BType.RATIO, // debuff效果提升 - 百分比型 [Attrs.DBUFF_UP]: BType.RATIO, // debuff效果提升 - 百分比型
[Attrs.SPEED]: BType.RATIO, // 移动速度加成 - 百分比型 [Attrs.SPEED]: BType.RATIO, // 移动速度加成 - 百分比型
[Attrs.SHIELD_UP]: BType.RATIO, // 护盾效果提升 - 百分比型
}; };
/** /**
@@ -227,61 +235,44 @@ export const getAttrType = (attrType: Attrs): BType => {
}; };
/** /**
* 获取 debuff 对应的属性字段 * DBuff 与 Attrs 的双向映射关系表
* @param debuffType DBuff 类型 * 格式:[DBuff, Attrs 或 -1状态类]
* @returns 对应的 Attrs 字段,如果是状态类 debuff只缓存返回 -1
*
* 扩展说明:
* 1. 普通 debuff返回 Attrs 值(会直接修改属性)
* 2. 状态类 debuff返回 -1只缓存不修改属性
*
* 新增 DBuff 时:
* - 如果需要修改属性,在 debuffAttrMap 中添加映射: [DBuff.NEW]: Attrs.ATTR
* - 如果只需缓存状态,在 stateDebuffSet 中添加: DBuff.NEW
*/ */
export const getAttrFieldFromDebuff = (debuffType: DBuff): number => { const DEBUFF_ATTR_MAP: [DBuff, number][] = [
// 状态类 debuff只需缓存不影响属性 [DBuff.STUN, -1], // 眩晕 - 状态类
const stateDebuffSet = new Set<DBuff>([ [DBuff.SLOW, Attrs.SPEED], // 减速 -> 速度
DBuff.STUN, [DBuff.FROST, -1], // 冰冻 - 状态类
DBuff.FROST, [DBuff.DEBURN, Attrs.DEBURN], // 被易伤 -> 被易伤
]); [DBuff.BURN, Attrs.BURN], // 易伤 -> 易伤效果
[DBuff.AS, Attrs.AS], // 减cd -> 攻击速度
[DBuff.HP_MAX, Attrs.HP_MAX], // 减hp -> 最大生命值
[DBuff.AP, Attrs.AP], // 减atk -> 攻击力
[DBuff.MGP, Attrs.MAP], // 减魔法 -> 魔法攻击力
[DBuff.DEBACK, Attrs.DEBACK], // 被击退 -> 被击退概率
[DBuff.CRITICAL, Attrs.CRITICAL], // -暴击率 -> 暴击率
[DBuff.CRIT_DAMAGE, Attrs.CRITICAL_DMG], // -暴击伤害 -> 暴击伤害
[DBuff.DODGE, Attrs.DODGE], // -闪避 -> 闪避
[DBuff.DBUFFUP, Attrs.DBUFF_UP], // debuff提升 -> debuff提升
[DBuff.BUFF_DOWN, Attrs.BUFF_UP], // buff减弱 -> buff效果
[DBuff.SPEED, Attrs.SPEED], // 移动速度下降 -> 移动速度
];
// 检查是否是状态类 debuff /**
if (stateDebuffSet.has(debuffType)) { * 双向转换DBuff ⇄ Attrs
return -1; // 表示只缓存,不影响属性 * @param key DBuff 或 Attrs 枚举值
* @param isDebuff true: key 是 DBuff, false: key 是 Attrs
* @returns 对应的转换值,未找到则返回 -1
*/
export const TransformBuffs = (key: number, isDebuff: boolean): number => {
if (isDebuff) {
// DBuff → Attrs
const found = DEBUFF_ATTR_MAP.find(([debuff]) => debuff === key);
return found ? found[1] : -1;
} else {
// Attrs → DBuff只返回第一个匹配
const found = DEBUFF_ATTR_MAP.find(([, attr]) => attr === key);
return found ? found[0] : -1;
} }
// ==================== 普通 Debuff 到 Attrs 的完整映射表 ====================
// 格式: [DBuff 类型]: Attrs 属性(会直接修改属性值)
// 注意:新增普通 debuff 时,在此添加映射关系即可
const debuffAttrMap: Record<DBuff, number> = {
[DBuff.STUN]: Attrs.CON_RES, // 眩晕 -> 控制抗性
[DBuff.SLOW]: Attrs.AS, // 减速 -> 攻击速度
[DBuff.FROST]: Attrs.ICE_RES, // 冰冻 -> 冰冻抗性
[DBuff.BURN]: Attrs.DEF, // 易伤 -> 防御
[DBuff.DEAS]: Attrs.AS, // 减cd -> 攻击速度
[DBuff.DEHP]: Attrs.HP_MAX, // 减hp -> 最大生命值
[DBuff.DEAP]: Attrs.AP, // 减atk -> 攻击力
[DBuff.DEMGP]: Attrs.MAP, // 减魔法 -> 魔法攻击力
[DBuff.BACK]: Attrs.KNOCKBACK, // 击退 -> 击退概率
[DBuff.CRITICAL]: Attrs.CRITICAL, // -暴击率 -> 暴击率
[DBuff.CRIT_DAMAGE]: Attrs.CRITICAL_DMG, // -暴击伤害 -> 暴击伤害
[DBuff.DODGE]: Attrs.DODGE, // -闪避 -> 闪避
[DBuff.DBUFFUP]: Attrs.DBUFF_UP, // debuff提升 -> debuff提升
[DBuff.BUFF_DOWN]: Attrs.BUFF_UP, // buff减弱 -> buff效果
[DBuff.SPEED]: Attrs.SPEED, // 移动速度下降 -> 移动速度
};
const attrField = debuffAttrMap[debuffType];
// 如果映射不存在,打印警告信息(方便开发调试)
if (attrField === undefined) {
console.warn(`[SkillSet] 未知的 DBuff 类型: ${debuffType},请在 getAttrFieldFromDebuff 添加映射关系或放入 stateDebuffSet`);
return -1;
}
return attrField;
}; };
/* /*
@@ -350,16 +341,16 @@ export const HeroSkillList = [6001,6001,6001,6001,6001,6001]
export interface DbuffConf { export interface DbuffConf {
debuff: DBuff; // debuff类型 debuff: DBuff; // debuff类型
BType:BType //buff是数值型还是百分比型 BType:BType //buff是数值型还是百分比型
deV: number; // 效果值 value: number; // 效果值
deC: number; // 持续时间 time: number; // 持续时间
deR: number; // 触发概率 chance: number; // 触发概率
} }
export interface BuffConf { export interface BuffConf {
buff:Attrs; buff:Attrs;
BType:BType BType:BType
buV:number; value:number; // 效果值
buC:number; time:number; // 持续时间
buR:number; chance:number; // 触发概率
} }
// 技能配置接口 - 按照6001格式排列 // 技能配置接口 - 按照6001格式排列
export interface SkillConfig { export interface SkillConfig {

View File

@@ -26,7 +26,9 @@ import { debuff } from "../../skills/debuff"
* 0:战士 1:远程 2:法师 * 0:战士 1:远程 2:法师
* * */ * * */
export enum AttrSet {
ATTR_MAX = 85,
}
export enum HType { export enum HType {
warrior = 0, warrior = 0,
remote = 1, remote = 1,

View File

@@ -1,408 +0,0 @@
# 🎮 英雄 Buff 系统 - 完成总结
**完成日期**: 2025-10-16
**项目状态**: ✅ 完成并测试
**编译状态**: ✅ 无错误
---
## 📋 项目需求回顾
### 需求 1: Buff/Debuff 分类存储 ✅
- [x] 按数值型/百分比型分类
- [x] 按持久型/临时型分类
- [x] 缓存进 V_BUFF, V_BUFFS, R_BUFF, R_BUFFS 等
### 需求 2: 接收 SkillSet 接口 ✅
- [x] addBuff 接受 BuffConf 参数
- [x] addDebuff 接受 DbuffConf 参数
- [x] buC/deC=0 表示持久,>0 表示临时
- [x] 根据 BType 区分数值/百分比
### 需求 3: 初始化系统 ✅
- [x] initBuffsDebuffs() 从 HeroInfo 读取初始配置
- [x] 英雄加载时自动初始化
- [x] 支持 heroSet.ts 中的 buff/debuff 配置
### 需求 4: 技能接口调用 ✅
- [x] 公开的 addBuff/addDebuff 方法
- [x] 易于在技能系统中调用
- [x] 完全兼容现有接口
### 需求 5: 属性重新计算 ✅
- [x] 每次 buff 变动自动重新计算 Attrs
- [x] 基于缓存的完整计算流程
- [x] 优先级合理(基础值 → buff → debuff
### 需求 6: 初始值保护 ✅
- [x] base_hp, base_mp, base_def, base_ap, base_map 保持独立
- [x] 百分比基于原始基础值计算
- [x] 无重复计算问题
---
## 📁 修改文件清单
### 1. HeroViewComp.ts
**位置**: `assets/script/game/hero/HeroViewComp.ts`
**修改内容**:
- ✅ 导入 BType, BuffConf, DbuffConf
- ✅ 添加 16 个新方法(约 800 行代码)
- ✅ update() 中添加临时效果更新
- ✅ 详细的中文注释和文档
**新增方法清单**:
```
初始化层:
- initBuffsDebuffs()
Buff 管理层:
- addBuff()
- removeBuff()
- getBuffValue()
Debuff 管理层:
- addDebuff()
- removeDebuff()
- getDebuffValue()
- hasDebuff()
- getAttrFieldFromDebuff()
属性计算层:
- recalculateAttrs()
- applyValueBuffs()
- applyRatioBuffs()
- applyValueDebuffs()
- applyRatioDebuffs()
- clampAttrs()
更新层:
- updateTemporaryBuffsDebuffs()
```
### 2. Hero.ts
**位置**: `assets/script/game/hero/Hero.ts`
**修改内容**:
- ✅ hero_init() 末尾添加 initBuffsDebuffs() 调用
- ✅ 修复 hp/mp 初始化赋值
---
## 📚 文档文件
### 1. BuffSystem_Guide.md
**内容**: 完整使用指南400+ 行)
- 系统概述和架构设计
- 接口定义详解
- 10 个 API 详细文档
- 完整使用示例
- 关键设计原则
- 常见问题解答
### 2. BuffSystem_Implementation.md
**内容**: 实现细节和集成指南350+ 行)
- 修改文件清单
- 核心设计原理
- 集成要点示例
- 属性映射表
- 性能考虑
- 使用模板
### 3. BuffSystem_QuickRef.md
**内容**: 快速参考卡200+ 行)
- 核心概念速查
- 快速开始示例
- API 一览表
- 常见错误警告
- 实战示例
### 4. 代码注释
**内容**: HeroViewComp.ts 顶部的详细使用说明
- 8 点系统架构说明
- 使用示例覆盖所有场景
---
## 🎯 核心功能实现
### 1. 自动分类存储
```typescript
BType.VALUE + buC=0 V_BUFF(数值型持久)
BType.VALUE + buC>0 V_BUFFS(数值型临时)
BType.RATIO + buC=0 R_BUFF(百分比型持久)
BType.RATIO + buC>0 R_BUFFS(百分比型临时)
```
### 2. 智能计算流程
```
重置基础值
应用数值型 buff
应用百分比型 buff
应用数值型 debuff
应用百分比型 debuff
属性值范围限制
```
### 3. 自动化管理
- ✅ 添加 buff → 自动分类存储
- ✅ 添加后 → 自动重新计算属性
- ✅ 每帧 → 自动更新临时时间
- ✅ 过期时 → 自动移除和重新计算
### 4. DBuff 到 Attrs 映射
```typescript
STUN CON_RES SLOW AS
FROST ICE_RES BURN DEF
DEAS AS DEHP HP_MAX
DEAP AP DEMGP MAP
BACK KNOCKBACK CRITICAL CRITICAL
CRIT_DAMAGE CRITICAL_DMG DODGE DODGE
```
---
## ✅ 质量保证
### 编译检查
- ✅ TypeScript 编译无错误
- ✅ Linter 无警告
- ✅ 代码格式符合项目规范
### 功能验证
- ✅ 数值型 buff/debuff 正确应用
- ✅ 百分比型 buff/debuff 正确计算
- ✅ 持久型永久保存
- ✅ 临时型正确递减和过期
- ✅ 多 buff 叠加正确计算
- ✅ 属性值限制在有效范围
### 集成可行性
- ✅ 兼容现有代码结构
- ✅ 无需修改现有接口
- ✅ 可渐进式集成
- ✅ 易于扩展
---
## 🚀 集成路径
### 第 1 步: 验证编译
```bash
# 项目已编译无误HeroViewComp.ts 和 Hero.ts 都在使用中
✅ 完成
```
### 第 2 步: 配置 SkillSet
```typescript
// 在 SkillSet.ts 的技能配置中添加:
buffs: [
{ buff: Attrs.AP, BType: BType.VALUE, buV: 10, buC: 0, buR: 100 }
],
debuffs: [
{ debuff: DBuff.STUN, BType: BType.VALUE, dev: 0, deC: 3, deR: 50 }
]
```
### 第 3 步: 在技能系统调用
```typescript
// 在 SkillEnt.ts 或技能处理逻辑中:
for (const buff of skillConf.buffs) {
targetHero.HeroView.addBuff(buff);
}
for (const debuff of skillConf.debuffs) {
targetHero.HeroView.addDebuff(debuff);
}
```
### 第 4 步: 在战斗系统检查
```typescript
// 在伤害计算、行动判定等处:
if (heroView.hasDebuff(DBuff.STUN)) {
return; // 无法行动
}
```
---
## 📊 代码统计
| 项目 | 数量 |
|------|------|
| **新增方法** | 16 个 |
| **新增代码行数** | ~800 行 |
| **文档行数** | ~1000+ 行 |
| **注释覆盖** | 100% |
| **编译错误** | 0 |
| **Linter 警告** | 0 |
---
## 🎓 使用场景覆盖
### ✅ 场景 1: 英雄初始化
```typescript
// 自动调用,从 HeroInfo 加载初始 buff
hv.initBuffsDebuffs();
```
### ✅ 场景 2: 技能施加 Buff
```typescript
// 直接在技能系统中调用
heroView.addBuff(skillBuff);
heroView.addDebuff(skillDebuff);
```
### ✅ 场景 3: 属性查询
```typescript
// 获取最终属性
const finalAP = heroView.Attrs[Attrs.AP];
```
### ✅ 场景 4: 状态检查
```typescript
// 检查 debuff 状态
if (heroView.hasDebuff(DBuff.STUN)) { ... }
```
### ✅ 场景 5: 临时效果过期
```typescript
// 自动在 update 中处理
// 过期自动移除和重新计算
```
---
## 🔒 兼容性保证
- ✅ 所有新方法都是 public
- ✅ 不改变现有 API
- ✅ 不修改现有属性名
- ✅ 不改变现有行为
- ✅ 可与现有代码共存
- ✅ 无需修改使用方
---
## 💼 技术亮点
### 1. 类型安全
- 使用 TypeScript interface
- 完全的类型检查
- 智能 IDE 提示
### 2. 模块化设计
- 功能分层清晰
- 职责单一明确
- 易于维护扩展
### 3. 性能优化
- 按需计算,不是每帧
- 缓存分离,便于处理
- 正向计算,无重复冗余
### 4. 文档完整
- 代码注释详尽
- 使用文档完善
- 示例代码丰富
### 5. 自动化管理
- 自动分类存储
- 自动重新计算
- 自动时间管理
---
## 📝 后续建议
### 优化方向
1. 添加 buff 叠加上限机制
2. 实现 buff 刷新延长功能
3. 添加优先级覆盖系统
4. 支持条件触发 buff
### 扩展方向
1. UI 显示 buff/debuff 图标
2. 添加 buff 过期动画效果
3. 实现 buff 冲突解决机制
4. 支持 buff 依赖链
### 监控方向
1. 添加 buff 变动日志
2. 实现属性变化追踪
3. 统计 buff 使用频率
4. 性能监测指标
---
## 🎊 项目完成清单
- [x] 代码实现完成
- [x] 编译验证通过
- [x] Linter 验证通过
- [x] 功能设计文档
- [x] 使用指南完整
- [x] 快速参考卡
- [x] 实现细节说明
- [x] 代码注释完善
- [x] 示例代码丰富
- [x] 集成路径明确
- [x] 向后兼容保证
- [x] 扩展建议提供
---
## 📞 文档导航
### 快速上手
→ 阅读 **BuffSystem_QuickRef.md**
### 详细学习
→ 阅读 **BuffSystem_Guide.md**
### 深入理解
→ 阅读 **BuffSystem_Implementation.md**
### 查看源码
→ 打开 **HeroViewComp.ts**
---
## 🏆 项目总结
本项目成功实现了一套**完整、自动化、高效**的 Buff 管理系统,具有以下特点:
**完整性**
- 支持数值型/百分比型 buff/debuff
- 支持持久型/临时型效果管理
- 支持属性初始值保护和计算
**自动化**
- 自动分类存储
- 自动属性重计算
- 自动时间管理
**易用性**
- 简洁的公开 API
- 详尽的代码注释
- 完善的使用文档
**可维护性**
- 模块化架构
- 职责清晰分离
- 易于扩展调整
**高性能**
- 按需计算,不浪费资源
- 缓存分离,高效处理
- 无重复计算
---
**项目已完成,可投入生产使用!** 🚀

View File

@@ -1,310 +0,0 @@
# Buff 系统扩展指南
## 📌 概述
本指南说明如何在项目中添加新的 buff 和 debuff 类型。系统设计支持无限扩展,无需修改核心代码。
---
## 🎯 添加新的 Buff 类型
### 步骤 1: 确定属性影响
首先明确新 buff 要影响哪个属性:
```typescript
// 示例:添加 "力量提升" buff
- 名称: PowerUp
- 属性: Attrs.AP (攻击力)
- 类型: 数值型 (BType.VALUE) 或百分比型 (BType.RATIO)
- 持续时间: 0(持久) >0(临时)
```
### 步骤 2: 在技能配置中使用
`assets/script/game/common/config/SkillSet.ts` 中的技能配置里添加:
```typescript
6001: {
uuid: 6001,
name: "攻击技能",
// ... 其他配置 ...
buffs: [
{
buff: Attrs.AP, // 影响属性
BType: BType.VALUE, // 数值型
buV: 20, // +20 攻击力
buC: 0, // 永久
buR: 100 // 100% 触发
},
{
buff: Attrs.CRITICAL, // 暴击率
BType: BType.VALUE, // 数值型
buV: 25, // +25% 暴击率
buC: 3, // 3 秒临时
buR: 100
}
],
debuffs: [],
info: "攻击技能,增加攻击力和暴击率"
}
```
### 步骤 3: 完成
✅ 系统会自动处理剩余工作:
- 自动分类存储到合适的缓存
- 自动计算属性
- 自动过期临时效果
---
## ⚡ 添加新的 Debuff 类型
### 两种 Debuff
**1. 属性型 Debuff**(直接修改属性)
-SLOW减速、BURN易伤、DEAP减攻击
- 需要对应 Attrs 属性
- 会直接修改属性值
**2. 状态型 Debuff**(只缓存不修改属性)
-STUN眩晕、FREEZE冰冻、POISON中毒
- 不需要对应 Attrs 属性
- 只缓存状态,用于战斗系统检查状态
- 查询使用:检查 debuff 缓存数组中是否存在该 debuff
---
### 添加属性型 Debuff
编辑 `assets/script/game/common/config/SkillSet.ts`
#### 步骤 1: 在 DBuff enum 中添加新类型
```typescript
export enum DBuff {
STUN = 1, // 现有
SLOW = 2, // 现有
// ... 现有 debuff ...
NEW_DEBUFF = 15, // 新增属性型 debuff
}
```
#### 步骤 2: 在 debuffAttrMap 中添加映射
编辑 `getAttrFieldFromDebuff` 函数:
```typescript
export const getAttrFieldFromDebuff = (debuffType: DBuff): number => {
// ... stateDebuffSet ...
const debuffAttrMap: Record<DBuff, number> = {
// ... 现有映射 ...
[DBuff.NEW_DEBUFF]: Attrs.DEF, // 新增映射到防御
};
// ... 其他代码 ...
}
```
#### 步骤 3: 在技能中使用
```typescript
debuffs: [
{
debuff: DBuff.NEW_DEBUFF,
BType: BType.VALUE,
dev: 10,
deC: 6,
deR: 80
}
]
```
---
### 添加状态型 Debuff
编辑 `assets/script/game/common/config/SkillSet.ts`
#### 步骤 1: 在 DBuff enum 中添加新类型
```typescript
export enum DBuff {
STUN = 1,
SLOW = 2,
// ... 现有 debuff ...
FREEZE = 20, // 新增状态型 debuff
}
```
#### 步骤 2: 在 stateDebuffSet 中添加(不需要映射)
编辑 `getAttrFieldFromDebuff` 函数:
```typescript
export const getAttrFieldFromDebuff = (debuffType: DBuff): number => {
// 状态类 debuff只需缓存不影响属性
const stateDebuffSet = new Set<DBuff>([
DBuff.FREEZE, // 新增状态型 debuff
]);
// 检查是否是状态类 debuff
if (stateDebuffSet.has(debuffType)) {
return -1; // 表示只缓存,不影响属性
}
// ... 其他代码 ...
}
```
#### 步骤 3: 在技能中使用
```typescript
debuffs: [
{
debuff: DBuff.FREEZE,
BType: BType.VALUE, // 通常为数值型
dev: 0, // 状态型可以为 0
deC: 4, // 持续 4 秒
deR: 100
}
]
```
#### 步骤 4: 在战斗系统中检查状态
状态型 debuff 被缓存在 `stateDebuffPerm``stateDebuffTemp` Set 中,支持最简洁的访问:
```typescript
// 最推荐:一行代码检查状态
if (heroView.hasState(DBuff.STUN)) {
// 眩晕状态下无法行动
}
// 直接 Set 访问(等价)
if (heroView.stateDebuffTemp.has(DBuff.STUN)) {
// 眩晕状态下无法行动
}
// 同时检查持久和临时状态
if (heroView.stateDebuffPerm.has(DBuff.FREEZE) ||
heroView.stateDebuffTemp.has(DBuff.FREEZE)) {
// 冰冻状态,移动速度降低
moveSpeed *= 0.5;
}
```
---
## 📝 扩展检查清单
### 添加属性型 Debuff 时
- [ ] 在 DBuff enum 中添加新类型
- [ ] 在 debuffAttrMap 中添加映射到对应的 Attrs
- [ ] 确保映射的 Attrs 有效
- [ ] 在技能配置中使用
- [ ] 测试属性是否正确修改
### 添加状态型 Debuff 时
- [ ] 在 DBuff enum 中添加新类型
- [ ] 在 stateDebuffSet 中添加
- [ ] ⚠️ **不要** 在 debuffAttrMap 中添加映射
- [ ] 在技能配置中使用
- [ ] 在战斗系统中添加状态检查逻辑
- [ ] 测试状态缓存是否正确
---
## 🎮 完整示例
### 示例 1: 属性型 Debuff - 减攻击
```typescript
// DBuff enum
export enum DBuff {
WEAKEN = 15, // 新增:减弱攻击
}
// 映射
const debuffAttrMap = {
[DBuff.WEAKEN]: Attrs.AP, // 直接减攻击力
};
// 技能使用
6010: {
debuffs: [
{
debuff: DBuff.WEAKEN,
BType: BType.RATIO,
dev: 30, // 减少 30% 攻击
deC: 5, // 持续 5 秒
deR: 100
}
]
}
// 自动效果:目标攻击力降低 30%
```
### 示例 2: 状态型 Debuff - 中毒
```typescript
// DBuff enum
export enum DBuff {
POISON = 16, // 新增:中毒
}
// 状态集合
const stateDebuffSet = new Set<DBuff>([
DBuff.POISON, // 只缓存,不影响属性
]);
// 技能使用
6011: {
debuffs: [
{
debuff: DBuff.POISON,
BType: BType.VALUE,
dev: 0, // 状态型可以为 0
deC: 8, // 持续 8 秒
deR: 70 // 70% 触发
}
]
}
// 战斗系统检查
if (checkState(targetHero, DBuff.POISON)) {
// 每秒损失血量
targetHero.hp -= 5;
}
```
---
## 🔄 状态型 Debuff 的应用场景
- **控制类**:眩晕、冰冻、缠绕
- **异常类**:中毒、流血、灼烧
- **减益类**:沉默、禁疗、虚弱
- **特殊**:任何需要在战斗系统检查的状态
状态型 debuff 不直接修改属性,而是作为标记,由战斗系统根据状态采取不同的行动。
---
## 📞 获取帮助
遇到问题检查:
1. 是否正确区分了属性型和状态型 debuff
2. 属性型 debuff 是否添加了映射?
3. 状态型 debuff 是否添加到了 stateDebuffSet
4. 状态检查逻辑是否添加到战斗系统?
---
**系统设计充分考虑了扩展性,添加新 buff/debuff 无需修改核心逻辑!** 🎉

View File

@@ -1,476 +0,0 @@
# BUFF 系统完整使用指南
## 系统概述
HeroViewComp 中的 buff 系统是一套完整的属性增强/减弱管理体系,支持:
- **数值型 buff/debuff**:固定数值增减
- **百分比型 buff/debuff**:基于基础属性的百分比增减
- **持久型**:永久生效,直到主动移除
- **临时型**:按时间递减,自动过期
## 架构设计
### 存储结构
```typescript
// 数值型 buff
V_BUFF: BuffConf[] // 持久型
V_BUFFS: BuffConf[] // 临时型(含 remainTime
// 百分比型 buff
R_BUFF: BuffConf[] // 持久型
R_BUFFS: BuffConf[] // 临时型(含 remainTime
// 数值型 debuff
V_DBUFF: DbuffConf[] // 持久型
V_DBUFFS: DbuffConf[]// 临时型(含 remainTime
// 百分比型 debuff
R_DBUFF: DbuffConf[] // 持久型
R_DBUFFS: DbuffConf[]// 临时型(含 remainTime
```
### 初始值属性
以下属性拥有初始值,百分比 buff 基于这些值计算:
- `base_hp`: 基础血量
- `base_mp`: 基础魔法值
- `base_def`: 基础防御
- `base_ap`: 基础攻击力
- `base_map`: 基础魔法攻击
其他属性CRITICAL, DODGE, AS 等)默认值为 0。
## 接口定义
### BuffConfbuff 配置)
```typescript
export interface BuffConf {
buff: Attrs; // 影响的属性
BType: BType; // VALUE(0)数值型 或 RATIO(1)百分比型
buV: number; // 增益值
buC: number; // 持续时间0=持久,>0=临时)
buR: number; // 触发概率(1-100)
}
```
### DbuffConfdebuff 配置)
```typescript
export interface DbuffConf {
debuff: DBuff; // debuff 类型
BType: BType; // VALUE(0)数值型 或 RATIO(1)百分比型
dev: number; // 减益值
deC: number; // 持续时间0=持久,>0=临时)
deR: number; // 触发概率(1-100)
}
```
## API 文档
### 1. 初始化系统
#### `initBuffsDebuffs(): void`
**作用**:从 HeroInfo 读取英雄初始配置,初始化 buff/debuff 系统
**调用时机**:英雄加载时(在 Hero.hero_init() 中自动调用)
**示例**
```typescript
// 自动调用,无需手动调用
heroView.initBuffsDebuffs();
```
---
### 2. 添加 Buff
#### `addBuff(buffConf: BuffConf): void`
**作用**:添加 buff 效果
**参数**
- `buffConf`: BuffConf 对象
**自动行为**
- 根据 BType 和 buC 自动分类存储
- 立即重新计算 Attrs
**示例**
```typescript
// 添加数值型持久 buff+10 攻击力
heroView.addBuff({
buff: Attrs.AP,
BType: BType.VALUE,
buV: 10,
buC: 0, // 0 表示持久
buR: 100
});
// 添加百分比型临时 buff+20% 防御,持续 5 秒
heroView.addBuff({
buff: Attrs.DEF,
BType: BType.RATIO,
buV: 20,
buC: 5, // 5 秒后过期
buR: 100
});
// 从技能配置添加(来自 SkillSet
const skillBuff: BuffConf = {
buff: Attrs.CRITICAL,
BType: BType.VALUE,
buV: 25, // +25% 暴击率
buC: 3, // 持续 3 秒
buR: 100
};
heroView.addBuff(skillBuff);
```
---
### 3. 添加 Debuff
#### `addDebuff(dbuffConf: DbuffConf): void`
**作用**:添加 debuff 效果
**参数**
- `dbuffConf`: DbuffConf 对象
**自动行为**
- DBuff 类型自动映射到对应 Attrs
- 根据 BType 和 deC 自动分类存储
- 立即重新计算 Attrs
**DBuff 映射表**
| DBuff 类型 | 对应 Attrs | 说明 |
|-----------|-----------|------|
| STUN | CON_RES | 眩晕 |
| SLOW | AS | 减速(攻击速度) |
| FROST | ICE_RES | 冰冻抗性 |
| BURN | DEF | 易伤(降低防御) |
| DEAS | AS | 减少 CD攻击速度 |
| DEHP | HP_MAX | 降低最大血量 |
| DEAP | AP | 降低攻击力 |
| DEMGP | MAP | 降低魔法攻击力 |
| BACK | KNOCKBACK | 击退概率 |
| CRITICAL | CRITICAL | 降低暴击率 |
| CRIT_DAMAGE | CRITICAL_DMG | 降低暴击伤害 |
| DODGE | DODGE | 降低闪避 |
**示例**
```typescript
// 眩晕:持久型,无数值影响
heroView.addDebuff({
debuff: DBuff.STUN,
BType: BType.VALUE,
dev: 0,
deC: 0, // 持久
deR: 100
});
// 减速:临时型,-30% 攻击速度,持续 3 秒
heroView.addDebuff({
debuff: DBuff.SLOW,
BType: BType.RATIO,
dev: 30, // 减少 30%
deC: 3, // 3 秒后过期
deR: 100
});
// 易伤:数值型,-5 防御,持久
heroView.addDebuff({
debuff: DBuff.BURN,
BType: BType.VALUE,
dev: 5,
deC: 0,
deR: 100
});
```
---
### 4. 移除 Buff
#### `removeBuff(buffType: Attrs, isTemporary?: boolean): boolean`
**作用**:移除指定属性的 buff
**参数**
- `buffType`: 属性类型
- `isTemporary`: 是否移除临时型(默认 false=持久型)
**返回值**:是否成功移除
**自动行为**
- 移除成功后自动重新计算 Attrs
**示例**
```typescript
// 移除持久 AP buff
heroView.removeBuff(Attrs.AP, false);
// 移除临时 DEF buff
heroView.removeBuff(Attrs.DEF, true);
```
---
### 5. 移除 Debuff
#### `removeDebuff(debuffType: DBuff, isTemporary?: boolean): boolean`
**作用**:移除指定类型的 debuff
**参数**
- `debuffType`: DBuff 类型
- `isTemporary`: 是否移除临时型
**返回值**:是否成功移除
**示例**
```typescript
// 移除持久眩晕
heroView.removeDebuff(DBuff.STUN, false);
// 移除临时减速
heroView.removeDebuff(DBuff.SLOW, true);
```
---
### 6. 属性重新计算
#### `recalculateAttrs(): void`
**作用**:重新计算所有角色属性
**调用时机**
- 自动在 addBuff/addDebuff/removeBuff/removeDebuff 时调用
- 自动在临时 buff/debuff 过期时调用
- 无需手动调用
**计算流程**
1. 重置为基础值
2. 应用数值型 buff持久 + 临时)
3. 应用百分比型 buff持久 + 临时)
4. 应用数值型 debuff持久 + 临时)
5. 应用百分比型 debuff持久 + 临时)
6. Clamp 关键属性(防止负数)
**百分比计算示例**
```
基础攻击力: 100
+20% buff: 100 * 1.2 = 120
-10% debuff: 120 * 0.9 = 108
```
---
### 7. 更新临时效果
#### `updateTemporaryBuffsDebuffs(dt: number): void`
**作用**:更新临时 buff/debuff 的剩余时间
**参数**
- `dt`: 时间增量(秒)
**调用时机**
- 自动在 update() 中每帧调用
- 无需手动调用
**自动行为**
- 减少所有临时 buff/debuff 的 remainTime
- 移除 remainTime <= 0 的效果
- 移除后自动重新计算 Attrs
---
### 8. 查询 Buff 状态
#### `getBuffValue(attrType: Attrs): number`
**作用**:获取指定属性的所有 buff 总值
**返回值**buff 总值
**示例**
```typescript
const apBuff = heroView.getBuffValue(Attrs.AP);
console.log("攻击力 buff 总和:", apBuff);
```
---
### 9. 查询 Debuff 状态
#### `getDebuffValue(debuffType: DBuff): number`
**作用**:获取指定 debuff 类型的所有 debuff 总值
**返回值**debuff 总值
**示例**
```typescript
const stunDebuff = heroView.getDebuffValue(DBuff.STUN);
console.log("眩晕等级:", stunDebuff);
```
---
### 10. 检查 Debuff 存在
#### `hasDebuff(debuffType: DBuff): boolean`
**作用**:检查是否存在指定的 debuff
**返回值**:是否存在
**示例**
```typescript
if (heroView.hasDebuff(DBuff.STUN)) {
console.log("角色已眩晕");
}
```
---
## 完整使用示例
### 场景 1技能施加 Buff
```typescript
// 在 SkillEnt.ts 或相关技能脚本中
const skillConf = SkillSet[skillId];
// 遍历技能的 buff 配置
for (const buffConf of skillConf.buffs) {
targetHero.HeroView.addBuff(buffConf);
}
// 遍历技能的 debuff 配置
for (const dbuffConf of skillConf.debuffs) {
targetHero.HeroView.addDebuff(dbuffConf);
}
```
### 场景 2英雄初始化
```typescript
// 在 Hero.ts 中(已自动调用)
hero_init(uuid: number, node: Node) {
var hv = node.getComponent(HeroViewComp)!;
let hero = HeroInfo[uuid];
// ... 其他初始化 ...
// 自动调用初始化 buff
hv.initBuffsDebuffs();
return hv;
}
```
### 场景 3属性查询
```typescript
// 获取最终计算后的属性值
const finalAP = heroView.Attrs[Attrs.AP];
const finalDEF = heroView.Attrs[Attrs.DEF];
// 获取 buff 总值
const apBuff = heroView.getBuffValue(Attrs.AP);
const defBuff = heroView.getBuffValue(Attrs.DEF);
// 检查 debuff 状态
if (heroView.hasDebuff(DBuff.STUN)) {
// 眩晕状态下无法行动
}
```
---
## 关键设计原则
### 1. 兼容式修改
- 所有方法名保持不变,易于集成
- 无痛替换原有的 buff 系统
### 2. 自动化计算
- 每次 buff 变动自动重新计算
- 无需手动更新属性
### 3. 灵活的时间管理
- 持久型buC=0永久生效
- 临时型buC>0自动按秒递减
- 过期自动移除和重新计算
### 4. 基础值保护
- 基础属性独立存储
- 百分比计算基于原始基础值
- 不会出现多次计算的偏差
### 5. 属性限制
- HP_MAX, MP_MAX 最少为 1
- 百分比属性CRITICAL, DODGE限制在 0-100
- 防止异常数值
---
## 常见问题
**Q: 如何区分持久和临时?**
A: buC=0 是持久buC>0 是临时(表示秒数)。
**Q: 百分比如何计算?**
A: 基于基础属性乘以百分比。例base_ap=100+20% → 100*1.2=120
**Q: 多个相同 buff 是否叠加?**
A: 会叠加。每个 addBuff 调用都会添加新条目。
**Q: 如何清除所有 buff**
A: 调用 initBuffsDebuffs() 重新初始化,或手动清空缓存数组。
---
## 扩展与维护
### 添加新 Buff
只需在 SkillSet.ts 的技能配置中添加即可,无需修改 HeroViewComp.ts
```typescript
buffs: [
{ buff: Attrs.AP, BType: BType.VALUE, buV: 10, buC: 0, buR: 100 }
]
```
### 添加新 Debuff
1. 在 SkillSet.ts 的 DBuff enum 中添加新类型
2. 在 HeroViewComp.ts 的 `getAttrFieldFromDebuff()` 中添加映射
3. 在技能配置中使用
详见 **BuffSystem_Extension.md** 完整扩展指南。
### 系统的扩展特性
✅ 支持无限数量的 buff/debuff
✅ 支持新增 Attrs 属性
✅ 支持新增 DBuff 类型
✅ 自动处理持久/临时管理
✅ 自动处理属性计算
✅ 编译检查确保类型安全

View File

@@ -1,277 +0,0 @@
# Buff 系统实现总结
## 修改的文件
### 1. `HeroViewComp.ts` (主要实现)
#### 导入部分更新
```typescript
import { ..., BType, BuffConf, DbuffConf } from "../common/config/SkillSet";
```
#### 新增方法(精简版)
| 方法名 | 功能 | 访问修饰符 |
|------|------|---------|
| `initBuffsDebuffs()` | 初始化 buff/debuff 系统 | public |
| `addBuff(buffConf)` | 添加 buff 效果 | public |
| `addDebuff(dbuffConf)` | 添加 debuff 效果 | public |
| `getAttrFieldFromDebuff()` | 获取 debuff 对应属性 | private |
| `recalculateAttrs()` | 重新计算属性 | public |
| `applyValueBuffs()` | 应用数值型 buff | private |
| `applyRatioBuffs()` | 应用百分比型 buff | private |
| `applyValueDebuffs()` | 应用数值型 debuff | private |
| `applyRatioDebuffs()` | 应用百分比型 debuff | private |
| `clampAttrs()` | 限制属性值范围 | private |
| `updateTemporaryBuffsDebuffs()` | 更新临时 buff/debuff | public |
**删除的方法**(持久性不需要移除):
- ~~removeBuff()~~
- ~~removeDebuff()~~
- ~~getBuffValue()~~
- ~~getDebuffValue()~~
- ~~hasDebuff()~~
#### 关键特性
- 百分比属性限制在 0-85%CRITICAL, DODGE, HIT
- 持久型 buff/debuff 永久生效,不支持移除
- 临时型自动过期,自动重新计算
#### update() 方法更新
添加了对 `updateTemporaryBuffsDebuffs(dt)` 的调用,以处理临时 buff/debuff 的过期。
---
### 2. `Hero.ts` (初始化调用)
#### hero_init() 方法更新
在方法末尾添加了 `hv.initBuffsDebuffs()` 调用,在英雄初始化时自动初始化 buff 系统。
---
## 核心设计
### 存储结构
```
buffPerm/buffTemp Buff 缓存(持久/临时)
├─ value 数值型
└─ ratio 百分比型
debuffPerm/debuffTemp Debuff 缓存(持久/临时)
├─ value 数值型
└─ ratio 百分比型
```
### 优势
- **更清晰**:按持久/临时和数值/百分比二维组织
- **更简洁**:从 8 个数组变为 4 个对象
- **更易扩展**:新增字段时直接添加到对应对象
- **更易查询**:通过对象结构自文档化
### 设计原则
1. **持久性不可移除**
- 持久型 buff/debuff 一旦添加就永久生效
- 无需提供移除接口,简化代码
2. **临时自动过期**
- 临时型自动在每帧更新时递减
- 过期自动移除和重新计算属性
3. **百分比上限 85%**
- 防止百分比属性过高导致游戏失衡
- 暴击率、闪避、命中等限制在 0-85%
### 计算流程
```
1. 重置为基础值 (base_hp, base_mp, base_def, base_ap, base_map)
2. 应用数值型 buff (V_BUFF + V_BUFFS)
3. 应用百分比型 buff (R_BUFF + R_BUFFS)
4. 应用数值型 debuff (V_DBUFF + V_DBUFFS)
5. 应用百分比型 debuff (R_DBUFF + R_DBUFFS)
6. 限制属性值范围 (clampAttrs)
- HP_MAX, MP_MAX 最少 1
- 百分比属性限制 0-85%
```
---
## 集成要点
### 1. 技能系统集成
在技能释放时调用:
```typescript
// 应用技能的 buff
for (const buffConf of skillConf.buffs) {
targetHeroView.addBuff(buffConf);
}
// 应用技能的 debuff
for (const dbuffConf of skillConf.debuffs) {
targetHeroView.addDebuff(dbuffConf);
}
```
### 2. SkillSet 配置
SkillSet 中的每个技能可配置 buff 和 debuff
```typescript
{
uuid: 6001,
// ... 其他配置 ...
buffs: [
{ buff: Attrs.AP, BType: BType.VALUE, buV: 10, buC: 0, buR: 100 }
],
debuffs: [
{ debuff: DBuff.STUN, BType: BType.VALUE, dev: 0, deC: 3, deR: 50 }
]
}
```
### 3. HeroInfo 配置
HeroInfo 中可配置英雄初始 buff/debuff
```typescript
5001: {
// ... 其他配置 ...
buff: [
{ buff: Attrs.CRITICAL, BType: BType.VALUE, buV: 15, buC: 0, buR: 100 }
],
debuff: []
}
```
---
## 属性初始值保护
**有初始值的属性**(基础属性):
- `base_hp`: 基础血量
- `base_mp`: 基础魔法值
- `base_def`: 基础防御
- `base_ap`: 基础攻击力
- `base_map`: 基础魔法攻击力
**百分比 buff/debuff 基于这些初始值计算**,确保多次计算不会产生偏差。
**无初始值属性**(默认为 0限制 0-85%
- CRITICAL, DODGE, HIT, WFUNY, AS, REFLICT, LIFESTEAL, KNOCKBACK, CON_RES, ICE_RES, FIRE_RES, WIND_RES, ICE_POWER, FIRE_POWER, WIND_POWER, SHIELD_UP, BUFF_UP, DBUFF_UP, DIS
---
## DBuff 到 Attrs 的映射
```typescript
const debuffAttrMap = {
[DBuff.STUN]: Attrs.CON_RES, // 眩晕 -> 控制抗性
[DBuff.SLOW]: Attrs.AS, // 减速 -> 攻击速度
[DBuff.FROST]: Attrs.ICE_RES, // 冰冻 -> 冰冻抗性
[DBuff.BURN]: Attrs.DEF, // 易伤 -> 防御
[DBuff.DEAS]: Attrs.AS, // 减cd -> 攻击速度
[DBuff.DEHP]: Attrs.HP_MAX, // 减hp -> 最大生命值
[DBuff.DEAP]: Attrs.AP, // 减atk -> 攻击力
[DBuff.DEMGP]: Attrs.MAP, // 减魔法 -> 魔法攻击力
[DBuff.BACK]: Attrs.KNOCKBACK, // 击退 -> 击退概率
[DBuff.CRITICAL]: Attrs.CRITICAL, // -暴击率 -> 暴击率
[DBuff.CRIT_DAMAGE]: Attrs.CRITICAL_DMG, // -暴击伤害 -> 暴击伤害
[DBuff.DODGE]: Attrs.DODGE, // -闪避 -> 闪避
};
```
---
## 性能考虑
### 优化点
1. **按需重新计算**:只在 buff 变动时计算,不是每帧
2. **缓存分离**:分离存储持久和临时,便于处理
3. **类型分组**:数值型和百分比型分离,计算方式不同
### 缓存行为
- 临时 buff/debuff 每帧检查一次(在 update 中)
- 过期移除时批量重新计算一次
---
## 使用模板
### 模板 1技能中应用 Buff
```typescript
// 在 SkillEnt.ts 或 SkillConCom.ts 中
applySkillEffect(targetHero: Hero, skillId: number) {
const skillConf = SkillSet[skillId];
const heroView = targetHero.get(HeroViewComp);
// 应用所有 buff
for (const buff of skillConf.buffs) {
heroView.addBuff(buff);
}
// 应用所有 debuff
for (const debuff of skillConf.debuffs) {
heroView.addDebuff(debuff);
}
}
```
### 模板 2查询属性值
```typescript
// 获取最终计算的属性
const finalAP = heroView.Attrs[Attrs.AP];
const finalDEF = heroView.Attrs[Attrs.DEF];
```
---
## 兼容性说明
**完全兼容**
- 所有新增方法都是 public不改变现有接口
- 自动初始化,无需修改现有代码
- 可逐步集成,不需一次性改造全部
⚠️ **注意事项**
- 临时 buff/debuff 需在配置中指定持续时间
- 百分比计算基于基础值,不会重复计算
- 属性值有范围限制,防止异常
- 持久型 buff/debuff 无法移除
---
## 验证清单
- [x] 导入 BType, BuffConf, DbuffConf
- [x] 添加 buff/debuff 缓存字段
- [x] 实现初始化方法
- [x] 实现添加 buff 方法
- [x] 实现添加 debuff 方法
- [x] 实现属性计算方法
- [x] 实现临时效果更新
- [x] 在 update 中调用更新
- [x] 在 Hero.hero_init 中调用初始化
- [x] 编译通过,无错误
- [x] 精简不必要的方法
- [x] 百分比属性限制 0-85%
---
## 相关文件
- 📄 HeroViewComp.ts - 主实现文件
- 📄 Hero.ts - 初始化调用
- 📄 SkillSet.ts - BuffConf/DbuffConf 定义
- 📄 heroSet.ts - HeroInfo 定义
- 📄 BuffSystem_Guide.md - 详细使用指南
- 📄 BuffSystem_QuickRef.md - 快速参考
- 📄 BuffSystem_Implementation.md - 本文件

View File

@@ -1,404 +0,0 @@
# Buff 系统可维护性指南
## 🎯 系统设计目标
本 buff 系统的核心设计目标是:
-**易于使用**:简单直观的 API
-**易于扩展**:添加新 buff/debuff 无需修改核心代码
-**易于维护**:清晰的代码结构和注释
-**类型安全**TypeScript 完全类型检查
-**性能优化**:按需计算,无冗余处理
---
## 📊 系统架构
### 核心层次
```
配置层 (SkillSet.ts, HeroInfo)
应用层 (addBuff, addDebuff)
缓存层 (buffPerm, buffTemp, debuffPerm, debuffTemp)
├─ value (数值型)
└─ ratio (百分比型)
计算层 (recalculateAttrs)
属性层 (Attrs[])
```
### 模块职责
| 模块 | 职责 | 修改频率 |
|------|------|--------|
| SkillSet.ts | buff/debuff 配置 | 经常(添加新技能) |
| HeroInfo | 英雄初始配置 | 不常 |
| HeroViewComp.ts | buff 系统核心 | 很少(修复 bug |
| Hero.ts | 初始化调用 | 基本不变 |
---
## 🔧 扩展点分析
### 1. 添加新 Buff✅ 最容易)
**修改位置**SkillSet.ts 技能配置
**风险等级**:⭐️ 无风险
```typescript
// 只需添加到 buffs 数组
buffs: [
{ buff: Attrs.AP, BType: BType.VALUE, buV: 10, buC: 0, buR: 100 }
]
// 系统自动处理一切
```
**验证**
- [x] 选择有效的 Attrs
- [x] 设置有效的 BType
- [x] 测试属性是否正确应用
---
### 2. 添加新的 Debuff 类型(✅ 很容易)
**修改位置**
1. SkillSet.ts - DBuff enum
2. SkillSet.ts - getAttrFieldFromDebuff() 映射表
3. SkillSet.ts - 技能配置
**风险等级**:⭐️⭐️ 低风险
```typescript
// 步骤 1: 添加类型
export enum DBuff {
POISON = 20, // 新增
}
// 步骤 2: 在 SkillSet.ts 中添加映射
export const getAttrFieldFromDebuff = (debuffType: DBuff): number => {
const debuffAttrMap: Record<DBuff, number> = {
// ... 现有映射 ...
[DBuff.POISON]: Attrs.DEF, // 中毒降低防御
};
// ... 其他代码 ...
}
// 步骤 3: 使用
debuffs: [
{ debuff: DBuff.POISON, BType: BType.VALUE, dev: 10, deC: 6, deR: 80 }
]
```
**验证**
- [x] DBuff 类型无冲突
- [x] 映射到有效的 Attrs
- [x] 测试效果是否正确
---
### 3. 修改核心计算逻辑(⚠️ 非常困难)
**修改位置**HeroViewComp.ts - recalculateAttrs()
**风险等级**:⭐️⭐️⭐️⭐️⭐️ 高风险
**不建议修改的原因**
- 计算流程已经优化
- 修改可能导致属性计算错误
- 影响所有 buff/debuff 效果
**如需修改**
- 先写单元测试
- 验证各种 buff/debuff 组合
- 检查边界条件(最小值、最大值)
---
## 📝 最佳实践
### 1. 添加新属性
如果需要添加新的角色属性:
```typescript
// 1. 在 Attrs enum 中添加
export enum Attrs {
// ... 现有属性 ...
NEW_ATTR = 27, // 新增
}
// 2. 在 getAttrs() 中初始化为 0
export const getAttrs = () => {
let reAttrs = {};
// ... 现有初始化 ...
reAttrs[27] = 0; // 新属性初始化
return reAttrs;
};
// 3. 如果有初始值,在 recalculateAttrs() 中处理
this.Attrs[Attrs.NEW_ATTR] = this.base_new_attr || 0;
// 4. 如果需要限制范围,在 clampAttrs() 中添加
this.Attrs[Attrs.NEW_ATTR] = Math.max(min, Math.min(max, this.Attrs[Attrs.NEW_ATTR]));
// 5. 在技能配置中使用
buffs: [
{ buff: Attrs.NEW_ATTR, BType: BType.VALUE, buV: 5, buC: 0, buR: 100 }
]
```
---
### 2. 修改 Buff 计算方式
如果需要修改百分比计算基数:
```typescript
// 当前:百分比基于基础属性
const baseVal = baseValues[buff.buff] || this.Attrs[buff.buff];
this.Attrs[buff.buff] += Math.floor(baseVal * (buff.buV / 100));
// 可选:基于当前属性
const currentVal = this.Attrs[buff.buff];
this.Attrs[buff.buff] += Math.floor(currentVal * (buff.buV / 100));
// 可选:自定义计算
// ... 自定义逻辑 ...
```
---
### 3. 添加条件 Buff
如果需要条件触发的 buff仅在特定情况下生效
```typescript
// 方案 1在 addBuff 前判断
if (someCondition) {
heroView.addBuff(buffConf);
}
// 方案 2扩展 BuffConf 接口(需要修改 SkillSet.ts
interface BuffConfWithCondition extends BuffConf {
condition?: () => boolean;
}
// 方案 3在技能中判断
const skillBuff = skillConf.buffs[0];
if (shouldApplyBuff(skillBuff)) {
heroView.addBuff(skillBuff);
}
```
---
## 🧪 测试清单
### 单元测试(推荐)
```typescript
describe('Buff System', () => {
let hero: HeroViewComp;
beforeEach(() => {
hero = new HeroViewComp();
hero.initBuffsDebuffs();
});
test('数值型 buff 应用', () => {
const before = hero.Attrs[Attrs.AP];
hero.addBuff({
buff: Attrs.AP,
BType: BType.VALUE,
buV: 10,
buC: 0,
buR: 100
});
expect(hero.Attrs[Attrs.AP]).toBe(before + 10);
});
test('百分比型 buff 应用', () => {
const baseAP = hero.base_ap;
hero.addBuff({
buff: Attrs.AP,
BType: BType.RATIO,
buV: 20,
buC: 0,
buR: 100
});
const expected = Math.floor(baseAP * 1.2);
expect(hero.Attrs[Attrs.AP]).toBe(expected);
});
test('临时 buff 应过期', () => {
hero.addBuff({
buff: Attrs.AP,
BType: BType.VALUE,
buV: 10,
buC: 1 // 1 秒
});
hero.updateTemporaryBuffsDebuffs(1.1); // 超过 1 秒
// buff 应被移除,属性恢复
expect(hero.Attrs[Attrs.AP]).toBe(hero.base_ap);
});
test('debuff 正确映射', () => {
hero.addDebuff({
debuff: DBuff.SLOW,
BType: BType.RATIO,
dev: 50,
deC: 0,
deR: 100
});
// SLOW 应映射到 Attrs.AS
const expected = Math.floor(hero.base_ap * 0.5);
expect(hero.Attrs[Attrs.AS]).toBeLessThan(100);
});
});
```
### 集成测试
```typescript
// 测试完整的技能应用流程
test('技能应用完整流程', () => {
const skillId = 6001;
const skill = SkillSet[skillId];
const hero = new HeroViewComp();
hero.initBuffsDebuffs();
// 应用技能
for (const buff of skill.buffs) {
hero.addBuff(buff);
}
for (const debuff of skill.debuffs) {
hero.addDebuff(debuff);
}
// 验证属性正确应用
// ...
// 验证临时效果正确过期
// ...
});
```
---
## 🚀 性能优化建议
### 当前优化
- [x] 按需计算(不是每帧)
- [x] 缓存分离(持久/临时)
- [x] 类型分离(数值/百分比)
- [x] 批量处理(临时过期时一次重算)
### 未来优化方向
1. **Buff 去重**
- 相同 buff 只计算一次
2. **缓存预热**
- 英雄加载时预计算
3. **异步处理**
- 大量 buff 变动时异步计算
---
## 📋 维护检查清单
### 月度检查
- [ ] 检查 console 是否有 buff 相关的 warning
- [ ] 验证新增技能的 buff/debuff 配置
- [ ] 检查属性计算是否正确
### 季度检查
- [ ] 审查 DBuff 映射表是否完整
- [ ] 检查是否有重复或冲突的 buff/debuff
- [ ] 验证系统性能buff 数量、计算次数)
### 年度检查
- [ ] 评估系统是否需要重构
- [ ] 考虑是否需要添加新的系统特性
- [ ] 检查是否有安全漏洞
---
## 🐛 常见问题排查
### 症状 1: Buff 没有效果
**排查步骤**
1. 检查 Attrs 是否有效 → `console.log(Attrs.AP)`
2. 检查 BuffConf 是否正确 → `console.log(buffConf)`
3. 检查 addBuff 是否调用 → 添加 log
4. 检查 recalculateAttrs 是否执行 → 添加 log
5. 检查最终属性值 → `console.log(heroView.Attrs)`
### 症状 2: Debuff 报错
**排查步骤**
1. 检查 console 是否有 warning
2. 查看 DBuff 是否在 enum 中定义
3. 查看是否在 debuffAttrMap 中有映射
4. 验证映射的 Attrs 是否有效
### 症状 3: 属性值异常
**排查步骤**
1. 检查基础属性是否正确初始化
2. 检查百分比计算公式
3. 检查 clampAttrs 中的限制是否合理
---
## 📞 获取技术支持
如果遇到问题:
1. **检查日志**
- 查看 console 是否有 warning
- 检查 HeroViewComp 的 log
2. **查阅文档**
- BuffSystem_QuickRef.md - 快速查找
- BuffSystem_Guide.md - 详细说明
- BuffSystem_Extension.md - 扩展方法
3. **查看源码**
- HeroViewComp.ts - 核心实现
- 代码中的详细注释
4. **调试技巧**
- 添加 console.log 追踪执行
- 使用浏览器开发者工具
- 逐步调试跟踪变量值
---
## 🏆 系统特点总结
| 特性 | 评级 | 说明 |
|------|------|------|
| 易用性 | ⭐⭐⭐⭐⭐ | 简单直观的 API |
| 可扩展性 | ⭐⭐⭐⭐⭐ | 添加新 buff/debuff 无需修改核心 |
| 可维护性 | ⭐⭐⭐⭐ | 清晰的结构,充分的注释 |
| 性能 | ⭐⭐⭐⭐ | 按需计算,高效处理 |
| 类型安全 | ⭐⭐⭐⭐⭐ | 完全 TypeScript 类型检查 |
---
**系统已准备好长期维护和扩展!** 🎉

View File

@@ -1,249 +0,0 @@
# Buff 系统 - 快速参考卡
## 🎯 核心概念
| 概念 | 说明 |
|------|------|
| **Buff** | 增益效果(增加属性) |
| **Debuff** | 减益效果(降低属性/能力) |
| **持久** | 永不过期buC=0 或 deC=0 |
| **临时** | 按秒递减buC>0 或 deC>0 |
| **数值型** | 固定数值增减BType.VALUE=0 |
| **百分比型** | 基于基础属性的百分比BType.RATIO=1 |
---
## 🚀 快速开始
### 1⃣ 添加数值型 Buff
```typescript
heroView.addBuff({
buff: Attrs.AP, // 增加攻击力
BType: BType.VALUE, // 数值型
buV: 10, // +10
buC: 0, // 永久
buR: 100 // 100% 触发
});
```
### 2⃣ 添加临时 Buff
```typescript
heroView.addBuff({
buff: Attrs.DEF, // 增加防御
BType: BType.RATIO, // 百分比型
buV: 20, // +20%
buC: 5, // 持续 5 秒
buR: 100
});
```
### 3⃣ 添加 Debuff
```typescript
heroView.addDebuff({
debuff: DBuff.STUN, // 眩晕
BType: BType.VALUE,
dev: 0,
deC: 3, // 持续 3 秒
deR: 100
});
```
---
## 📋 属性类型 (Attrs)
### 基础属性(有初始值)
```typescript
HP_MAX // 最大生命
MP_MAX // 最大魔法
DEF // 防御
AP // 攻击力
MAP // 魔法攻击力
SHIELD_MAX // 护盾值
```
### 专项属性(无初始值,限制值 0-85%
```typescript
CRITICAL // 暴击率
CRITICAL_DMG // 暴击伤害
DODGE // 闪避
HIT // 命中
AS // 攻击速度
KNOCKBACK // 击退概率
CON_RES // 控制抗性
ICE_RES // 冰冻抗性
FIRE_RES // 火抗性
// ... 等等
```
---
## ⚡ Debuff 类型 (DBuff)
```typescript
STUN Attrs.CON_RES // 眩晕
SLOW Attrs.AS // 减速
FROST Attrs.ICE_RES // 冰冻
BURN Attrs.DEF // 易伤
DEAS Attrs.AS // 减CD
DEHP Attrs.HP_MAX // 减血量
DEAP Attrs.AP // 减攻击
DEMGP Attrs.MAP // 减魔法
BACK Attrs.KNOCKBACK // 击退
CRITICAL Attrs.CRITICAL // 降暴击
CRIT_DAMAGE Attrs.CRITICAL_DMG // 降爆伤
DODGE Attrs.DODGE // 降闪避
```
---
## 📊 计算示例
### 数值型 Buff
```
基础 AP: 100
+Buff: +10
结果: 110
```
### 百分比型 Buff
```
基础 AP: 100
+20% Buff: 100 * 1.2 = 120
```
### 混合计算
```
基础 AP: 100
+20% Buff: 100 * 1.2 = 120
+10 Buff: 120 + 10 = 130
-30% Debuff: 130 * 0.7 = 91
```
---
## 🔧 API 一览表
| 方法 | 功能 |
|------|------|
| `addBuff(conf)` | 添加 buff |
| `addDebuff(conf)` | 添加 debuff自动区分属性型/状态型) |
| `hasState(type)` | **检查状态型 debuff最简洁** ⭐ |
| `getDebuff(type)` | 获取属性型 debuff 对象 |
| `hasDebuff(type)` | 检查属性型 debuff 存在 |
| `getBuff(type)` | 获取 buff 对象 |
| `hasBuff(type)` | 检查 buff 存在 |
---
## 💾 缓存结构 & 访问方式
### 状态型 Debuff最简洁
```typescript
// 使用 Set 存储O(1) 快速判断
heroView.hasState(DBuff.STUN) // ✅ 最推荐
heroView.stateDebuffTemp.has(DBuff.STUN) // 直接访问
```
### 属性型 Buff & Debuff
```typescript
// 使用 Map 存储,支持对象访问
heroView.hasBuff(Attrs.AP) // 检查 buff
heroView.getBuff(Attrs.AP) // 获取 buff
heroView.hasDebuff(DBuff.SLOW) // 检查 debuff
heroView.getDebuff(DBuff.SLOW) // 获取 debuff
```
### 缓存结构一览
```
buffPerm/buffTemp
├─ value: Map<Attrs, buff>
└─ ratio: Map<Attrs, buff>
debuffPerm/debuffTemp属性型
├─ value: Map<DBuff, debuff>
└─ ratio: Map<DBuff, debuff>
stateDebuffPerm/stateDebuffTemp状态型
└─ Set<DBuff> ← 最简洁的访问
```
---
## ✅ 使用检查清单
- [ ] 导入 `BType, BuffConf, DbuffConf`
- [ ] 在 SkillSet 中配置 buff/debuff
- [ ] 技能释放时调用 `addBuff/addDebuff`
- [ ] 临时 buff/debuff 自动过期
- [ ] 查询属性用 `Attrs[type]`
---
## 🐛 常见错误
**错误 1**: 混淆 buC 和 deC 的含义
```typescript
buC: 0 // ✅ 正确:持久
buC: 5 // ✅ 正确5 秒临时
```
**错误 2**: DBuff 类型用错了
```typescript
// ❌ 错误
addDebuff({ debuff: Attrs.AP, ... });
// ✅ 正确
addDebuff({ debuff: DBuff.DEAP, ... });
```
---
## 🎮 实战示例
### 技能释放流程
```typescript
// 1. 获取技能配置
const skill = SkillSet[skillId];
// 2. 应用 buff
for (const buff of skill.buffs) {
heroView.addBuff(buff);
}
// 3. 应用 debuff
for (const debuff of skill.debuffs) {
heroView.addDebuff(debuff);
}
// 4. 属性自动重新计算!
```
---
## 📚 完整文档
- 📖 BuffSystem_Guide.md - 详细使用指南
- 📋 BuffSystem_Implementation.md - 实现细节
- 🎯 BuffSystem_QuickRef.md - 本快速参考
- 🚀 BuffSystem_Extension.md - 扩展指南(如何添加新 buff/debuff
---
## 🎓 学习路径
1. **快速开始** ➜ 先看这个文件
2. **详细学习** ➜ 阅读 BuffSystem_Guide.md
3. **深入理解** ➜ 查看 BuffSystem_Implementation.md
4. **需要扩展** ➜ 阅读 BuffSystem_Extension.md
5. **查看源码** ➜ 阅读 HeroViewComp.ts
---
**💡 记住**:系统会**自动**计算属性,临时效果**自动过期**

View File

@@ -76,16 +76,19 @@ export class Hero extends ecs.Entity {
hv.base_def=hero.def hv.base_def=hero.def
hv.base_hp=hero.hp hv.base_hp=hero.hp
hv.base_mp=hero.mp hv.base_mp=hero.mp
hv.hp=hv.base_hp hv.base_dis=hero.dis
hv.mp=hv.base_mp hv.base_speed=hero.speed
hv.Attrs=getAttrs() hv.Attrs=getAttrs()
hv.Attrs[Attrs.HP_MAX]=hv.base_hp hv.hp=hv.Attrs[Attrs.HP_MAX]=hv.base_hp
hv.Attrs[Attrs.MP_MAX]=hv.base_mp hv.mp=hv.Attrs[Attrs.MP_MAX]=hv.base_mp
hv.Attrs[Attrs.DEF]=hv.base_def hv.Attrs[Attrs.DEF]=hv.base_def
hv.Attrs[Attrs.AP]=hv.base_ap hv.Attrs[Attrs.AP]=hv.base_ap
hv.Attrs[Attrs.MAP]=hv.base_map hv.Attrs[Attrs.MAP]=hv.base_map
hv.Attrs[Attrs.SPEED]=hero.speed
hv.Attrs[Attrs.DIS]=hero.dis
// 初始化 buff/debuff 系统 // 初始化 buff/debuff 系统
hv.initBuffsDebuffs(); hv.initAttrs();
return hv return hv
} }
} }

View File

@@ -5,74 +5,36 @@ import { HeroSpine } from "./HeroSpine";
import { BoxSet, FacSet } from "../common/config/BoxSet"; import { BoxSet, FacSet } from "../common/config/BoxSet";
import { smc } from "../common/SingletonModuleComp"; import { smc } from "../common/SingletonModuleComp";
import { Timer } from "../../../../extensions/oops-plugin-framework/assets/core/common/timer/Timer"; import { Timer } from "../../../../extensions/oops-plugin-framework/assets/core/common/timer/Timer";
import { Attrs, DBuff, SkillSet, BType, BuffConf, DbuffConf, getAttrFieldFromDebuff } from "../common/config/SkillSet"; import { Attrs, DBuff, SkillSet, BType, BuffConf, DbuffConf, TransformBuffs, AttrsType } from "../common/config/SkillSet";
import { BuffComp } from "./BuffComp"; import { BuffComp } from "./BuffComp";
import { oops } from "db://oops-framework/core/Oops"; import { oops } from "db://oops-framework/core/Oops";
import { GameEvent } from "../common/config/GameEvent"; import { GameEvent } from "../common/config/GameEvent";
import { FightSet, TooltipTypes } from "../common/config/Mission"; import { FightSet, TooltipTypes } from "../common/config/Mission";
import { RandomManager } from "db://oops-framework/core/common/random/RandomManager"; import { RandomManager } from "db://oops-framework/core/common/random/RandomManager";
import { HeroInfo, HeroUpSet } from "../common/config/heroSet"; import { AttrSet, HeroInfo, HeroUpSet } from "../common/config/heroSet";
const { ccclass, property } = _decorator; const { ccclass, property } = _decorator;
/** /**
* ==================== BUFF 系统使用说明 ==================== * ==================== BUFF 系统使用说明 ====================
* *
* 1. 系统架构 * 1. 系统架构
* - BUFF_V/BUFFS_V: 数值型 buff久/临时 * - BUFF_V/BUFFS_V: 数值型 buff持临时
* - BUFF_R/BUFFS_R: 百分比型 buff久/临时 * - BUFF_R/BUFFS_R: 百分比型 buff持临时
* - DBUFF_V/DBUFFS_V: 数值型 debuff久/临时 * - DBUFF_V/DBUFFS_V: 数值型 debuff持临时
* - DBUFF_R/DBUFFS_R: 百分比型 debuff久/临时 * - DBUFF_R/DBUFFS_R: 百分比型 debuff持临时
* *
* 2. 初始化(在英雄加载时自动调用): * 2. 智能覆盖规则
* - initBuffsDebuffs(): 从 HeroInfo 读取初始配置 * - 值更小:不添加(弱效果不覆盖强效果)
* - 值相同且临时:叠加时
* - 值更大:更新为新值(临时则更新值和时间
* *
* 3. 添加 buff技能调用: * 3. 性能优化
* const buffConf: BuffConf = { * - 增量计算:添删除时只重算受影响的属
* buff: Attrs.AP, // 增加攻击力 * - 批量计算initBuffsDebuffs() 中使recalculateAttrs() 一次性计算所
* BType: BType.VALUE, // 数值型
* buV: 10, // 增加值
* buC: 0, // 持久(0=持久, >0=持续时间)
* buR: 100 // 触发概率(100%)
* };
* heroView.addBuff(buffConf);
*
* 4. 添加 debuff技能调用:
* const dbuffConf: DbuffConf = {
* debuff: DBuff.STUN, // 眩晕
* BType: BType.VALUE, // 数值型
* deV: 20, // 减少值
* deC: 3, // 持续3秒
* deR: 100 // 触发概率(100%)
* };
* heroView.addDebuff(dbuffConf);
*
* 5. 百分比型示例:
* // 增加20%攻击力
* heroView.addBuff({
* buff: Attrs.AP,
* BType: BType.RATIO, // 百分比型
* buV: 20, // 20%
* buC: 5, // 持续5秒
* buR: 100
* });
*
* 6. 移除 buff/debuff:
* heroView.removeBuff(Attrs.AP, false); // 移除持久 AP buff
* heroView.removeDebuff(DBuff.STUN, true); // 移除临时眩晕
*
* 7. 属性计算:
* - 每次 buff/debuff 变动时自动调用 recalculateAttrs()
* - 重新计算基础属性 + 所有 buff/debuff 的结果
* - 临时 buff/debuff 在 update 中按时间递减
*
* 8. 初始值属性:
* - base_hp, base_mp, base_def, base_ap, base_map 是初始值
* - 百分比 buff/debuff 基于这些初始值计算
* - 其他属性默认为 0无初始值
*/ */
/** 角色显示组件 */ /** 角色显示组件 */
@ccclass('HeroViewComp') // 定义Cocos Creator 组件 @ccclass('HeroViewComp') // 定义Cocos Creator 组件
@ecs.register('HeroView', false) // 定义ECS 组件 @ecs.register('HeroView', false) // 定义ECS 组件
export class HeroViewComp extends CCComp { export class HeroViewComp extends CCComp {
BUFFCOMP:BuffComp=null! BUFFCOMP:BuffComp=null!
as: HeroSpine = null! as: HeroSpine = null!
@@ -81,7 +43,7 @@ export class HeroViewComp extends CCComp {
hero_name : string = "hero"; hero_name : string = "hero";
lv:number =1; lv:number =1;
scale: number = 1; /** 角色阵营 1hero -1 :mon */ scale: number = 1; /** 角色阵营 1hero -1 :mon */
type: number = 0; /**角色类型 0近战-需要贴1远程-保持距离 2辅助 */ type: number = 0; /**角色类型 0近战-需要贴1远程-保持距离 2辅助 */
fac:number=0; //阵营 0hero 1monster fac:number=0; //阵营 0hero 1monster
box_group:number = BoxSet.HERO; box_group:number = BoxSet.HERO;
is_dead:boolean = false; //是否摧毁 is_dead:boolean = false; //是否摧毁
@@ -96,27 +58,28 @@ export class HeroViewComp extends CCComp {
is_kalami:boolean =false; is_kalami:boolean =false;
mp: number = 100; mp: number = 100;
hp: number = 100; /** 血*/ hp: number = 100; /** 血*/
shield:number=0; //当前护甲 shield:number=0; //当前护甲
/** 基础属有初始值的基础属性,后续Attrs 属性计算时用到*/ /** 基础属有初始值的基础属后续Attrs 属性计算时用到*/
base_ap: number = 0; //基础攻击 base_ap: number = 0; //基础攻击
base_map: number = 0; base_map: number = 0;
base_def: number = 5; base_def: number = 5;
base_hp: number = 100; base_hp: number = 100;
base_mp: number = 100; base_mp: number = 100;
base_speed: number = 100; /** 角色移动速度 */ base_speed: number = 100; /** 角色移动速度 */
base_dis: number = 100;
Attrs:any=[] Attrs:any=[]
//数值型debuff // Buff/Debuff 字典结构,通过属性索引直接访
DBUFF_V:any[]=[] //持久 // 结构: { [attrIndex: number]: { value: number, remainTime?: number } }
DBUFF_R:any[]=[] //持久 DBUFF_V: Record<number, {value: number}> = {} // 持久型数debuff
BUFF_V:any[]=[] //持久 DBUFF_R: Record<number, {value: number}> = {} // 持久型百分比 debuff
BUFF_R:any[]=[] //持久 BUFF_V: Record<number, {value: number}> = {} // 持久型数buff
BUFF_R: Record<number, {value: number}> = {} // 持久型百分比 buff
DBUFFS_V:any[]=[] //临时 带时间 DBUFFS_V: Record<number, {value: number, remainTime: number}> = {} // 临时型数debuff
DBUFFS_R:any[]=[] //临时 带时间 DBUFFS_R: Record<number, {value: number, remainTime: number}> = {} // 临时型百分比 debuff
BUFFS_V:any[]=[] //临时 带时间 BUFFS_V: Record<number, {value: number, remainTime: number}> = {} // 临时型数buff
BUFFS_R:any[]=[] //临时 带时间 BUFFS_R: Record<number, {value: number, remainTime: number}> = {} // 临时型百分比 buff
atk_count: number = 0; atk_count: number = 0;
atked_count: number = 0; atked_count: number = 0;
@@ -139,7 +102,7 @@ export class HeroViewComp extends CCComp {
this.on(GameEvent.FightEnd,this.do_fight_end,this) this.on(GameEvent.FightEnd,this.do_fight_end,this)
const collider = this.node.getComponent(BoxCollider2D); const collider = this.node.getComponent(BoxCollider2D);
this.scheduleOnce(()=>{ this.scheduleOnce(()=>{
if (collider) collider.enabled = true; // 先禁 if (collider) collider.enabled = true; // 先禁
},1) },1)
// let anm = this.node.getChildByName("anm") // let anm = this.node.getChildByName("anm")
// anm.setScale(anm.scale.x*0.8,anm.scale.y*0.8); // anm.setScale(anm.scale.x*0.8,anm.scale.y*0.8);
@@ -155,360 +118,366 @@ export class HeroViewComp extends CCComp {
if(this.is_boss){ if(this.is_boss){
this.node.getChildByName("top").position=v3(this.node.position.x,this.node.position.y+100,0) 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("hp").active = true;
this.BUFFCOMP.show_shield(this.shield,this.Attrs[Attrs.SHIELD_MAX]) this.BUFFCOMP.show_shield(this.shield,this.Attrs[Attrs.SHIELD_MAX])
} }
// ==================== BUFF系统初始==================== // ==================== BUFF系统初始====================
/** /**
* 初始化角色的 buff debuff * 初始化角色的 buff debuff
* HeroInfo 读取初始配置,建立属性系 * HeroInfo 读取初始配置,建立属性系
*/ */
initBuffsDebuffs() { 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]; const heroInfo = HeroInfo[this.hero_uuid];
if (!heroInfo) return; if (!heroInfo) return;
// 清空现有 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 = [];
// 加载初始 buff // 1. 重置为基础
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);
}
}
// 重新计算所有属性
this.recalculateAttrs();
}
// ==================== BUFF管理 ====================
/**
* 添加 buff 效果
* @param buffConf buff 配置 (来自 SkillSet.BuffConf 或 heroSet.buff)
*/
addBuff(buffConf: BuffConf) {
// 基于类型和持续时间分类存储
if (buffConf.BType === BType.VALUE) {
// 数值型 buff
if (buffConf.buC === 0) {
// 持久型
this.BUFF_V.push({...buffConf});
} else {
// 临时型 - 添加剩余时间属性
this.BUFFS_V.push({
...buffConf,
remainTime: buffConf.buC
});
}
} else {
// 百分比型 buff
if (buffConf.buC === 0) {
// 持久型
this.BUFF_R.push({...buffConf});
} else {
// 临时型 - 添加剩余时间属性
this.BUFFS_R.push({
...buffConf,
remainTime: buffConf.buC
});
}
}
// 立即重新计算属性
this.recalculateAttrs();
}
// ==================== DEBUFF管理 ====================
/**
* 添加 debuff 效果
* @param dbuffConf debuff 配置 (来自 SkillSet.DbuffConf 或 heroSet.debuff)
*
* 支持两种 debuff
* 1. 属性型 debuff直接修改属性值有对应的 Attrs
* 2. 状态型 debuff只缓存状态无对应的 Attrs用于状态检查
*/
addDebuff(dbuffConf: DbuffConf) {
// 获取 debuff 对应的属性字段
// attrField = -1 表示状态类 debuff只缓存不修改属性
// attrField >= 0 表示属性类 debuff会修改属性
const attrField = getAttrFieldFromDebuff(dbuffConf.debuff);
// 基于类型和持续时间分类存储
if (dbuffConf.BType === BType.VALUE) {
// 数值型 debuff
if (dbuffConf.deC === 0) {
// 持久型
this.DBUFF_V.push({
...dbuffConf,
attrField: attrField
});
} else {
// 临时型 - 添加剩余时间属性
this.DBUFFS_V.push({
...dbuffConf,
attrField: attrField,
remainTime: dbuffConf.deC
});
}
} else {
// 百分比型 debuff
if (dbuffConf.deC === 0) {
// 持久型
this.DBUFF_R.push({
...dbuffConf,
attrField: attrField
});
} else {
// 临时型 - 添加剩余时间属性
this.DBUFFS_R.push({
...dbuffConf,
attrField: attrField,
remainTime: dbuffConf.deC
});
}
}
// 立即重新计算属性
this.recalculateAttrs();
}
// ==================== 属性计算系统 ====================
/**
* 重新计算所有角色属性
* 基于基础属性 + 所有有效的 buff/debuff 计算
* 注意某些属性有初始值HP_MAX, MP_MAX, DEF, AP, MAP
*/
recalculateAttrs() {
// 1. 重置为基础值
this.Attrs[Attrs.HP_MAX] = this.base_hp; this.Attrs[Attrs.HP_MAX] = this.base_hp;
this.Attrs[Attrs.MP_MAX] = this.base_mp; this.Attrs[Attrs.MP_MAX] = this.base_mp;
this.Attrs[Attrs.DEF] = this.base_def; this.Attrs[Attrs.DEF] = this.base_def;
this.Attrs[Attrs.AP] = this.base_ap; this.Attrs[Attrs.AP] = this.base_ap;
this.Attrs[Attrs.MAP] = this.base_map; this.Attrs[Attrs.MAP] = this.base_map;
this.Attrs[Attrs.SPEED] = this.base_speed; this.Attrs[Attrs.SPEED] = this.base_speed;
this.Attrs[Attrs.SHIELD_MAX] = 0; // 护盾默认为 0 this.Attrs[Attrs.DIS] = this.base_dis;
// 2. 初始化其他属性(无初始值的 // 2. 初始化其他属性(无初始值的
let length = Object.keys(this.Attrs).length; for (const attrKey in this.Attrs) {
for (let i = 0; i < length; i++) { const attrIndex = parseInt(attrKey);
if (!(i in this.Attrs) || if(
(i !== Attrs.HP_MAX && i !== Attrs.MP_MAX && i !== Attrs.DEF && attrIndex !== Attrs.HP_MAX &&
i !== Attrs.AP && i !== Attrs.MAP && i !== Attrs.SHIELD_MAX&&13 && i !== Attrs.SPEED)) { attrIndex !== Attrs.MP_MAX&&
this.Attrs[i] = 0; attrIndex !== Attrs.DEF &&
attrIndex !== Attrs.AP &&
attrIndex !== Attrs.MAP &&
attrIndex !== Attrs.SPEED &&
attrIndex !== Attrs.DIS
) {
this.Attrs[attrIndex] = 0;
} }
} }
// 加载初始 buff
// 3. 应用数值型 buff (持久 + 临时) if (heroInfo.buff && heroInfo.buff.length > 0) {
this.applyValueBuffs(); for (const buffConf of heroInfo.buff) {
this.addBuff(buffConf);
// 4. 应用百分比型 buff (持久 + 临时)
this.applyRatioBuffs();
// 5. 应用数值型 debuff (持久 + 临时)
this.applyValueDebuffs();
// 6. 应用百分比型 debuff (持久 + 临时)
this.applyRatioDebuffs();
// 7. 确保关键属性不为负数
this.clampAttrs();
} }
}
// 加载初始 debuff
if (heroInfo.debuff && heroInfo.debuff.length > 0) {
for (const dbuffConf of heroInfo.debuff) {
this.addDebuff(dbuffConf);
}
}
}
// ==================== BUFF管理 ====================
/** /**
* 应用数值型 buff * 添加 buff 效果(智能覆盖)
* @param buffConf buff 配置 (来自 SkillSet.BuffConf heroSet.buff)
*
* 智能覆盖规则
* 1. 值更小:不添
* 2. 值相同且都是临时:叠加时
* 3. 值更大:更新为新值(临时则更新值和时间
*/ */
private applyValueBuffs() { addBuff(buffConf: BuffConf) {
// 持久型 buff const isValue = buffConf.BType === BType.VALUE;
for (const buff of this.BUFF_V) { const isPermanent = buffConf.time === 0;
if (buff.buff !== undefined) { const attrIndex = buffConf.buff;
this.Attrs[buff.buff] += buff.buV;
// 根据类型选择对应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
};
} }
} }
// 临时型 buff this.recalculateSingleAttr(buffConf.buff);
for (const buff of this.BUFFS_V) {
if (buff.buff !== undefined) {
this.Attrs[buff.buff] += buff.buV;
}
}
} }
// ==================== DEBUFF管理 ====================
/** /**
* 应用百分比型 buff * 添加 debuff 效果(智能覆盖)
* 百分比型 buff 是基于基础属性的百分比增加 * @param dbuffConf debuff 配置 (来自 SkillSet.DbuffConf heroSet.debuff)
*
* 支持两种 debuff
* 1. 属性型 debuff直接修改属性值有对应的 Attrs
* 2. 状态型 debuff只缓存状态无对应的 Attrs用于状态检查
*
* 智能覆盖规则
* 1. 值更小:不添
* 2. 值相同且都是临时:叠加时
* 3. 值更大:更新为新值(临时则更新值和时间
*/ */
private applyRatioBuffs() { addDebuff(dbuffConf: DbuffConf) {
// 获取基础值映射 // 获取 debuff 对应的属性字
const baseValues: Record<number, number> = {};
baseValues[Attrs.HP_MAX] = this.base_hp;
baseValues[Attrs.MP_MAX] = this.base_mp;
baseValues[Attrs.DEF] = this.base_def;
baseValues[Attrs.AP] = this.base_ap;
baseValues[Attrs.MAP] = this.base_map;
baseValues[Attrs.SPEED] = this.base_speed;
// 持久型 buff const isValue = dbuffConf.BType === BType.VALUE;
for (const buff of this.BUFF_R) { const isPermanent = dbuffConf.time === 0;
if (buff.buff !== undefined) {
const baseVal = baseValues[buff.buff] || this.Attrs[buff.buff]; // 根据类型选择对应debuff 字典
this.Attrs[buff.buff] += Math.floor(baseVal * (buff.buV / 100)); 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;
// 临时型 buff
for (const buff of this.BUFFS_R) { if (isPermanent) {
if (buff.buff !== undefined) { // 添加持久debuff
const baseVal = baseValues[buff.buff] || this.Attrs[buff.buff]; const existing = permanentDebuffs[key];
this.Attrs[buff.buff] += Math.floor(baseVal * (buff.buV / 100)); 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);
} }
} }
// ==================== 属性计算系====================
/** /**
* 应用数值型 debuff * 重新计算单个属性
* @param attrIndex 属性索引
*
* 计算公式:
* - 数值型属性:最终值 = (基础值 + 数值型buff - 数值型debuff) × (1 + 百分比buff/100 - 百分比debuff/100)
* - 百分比型属性:最终值 = 基础值 + 数值型buff - 数值型debuff + 百分比buff - 百分比debuff
*/ */
private applyValueDebuffs() { private recalculateSingleAttr(attrIndex: number) {
// 持久型 debuff // 1. 获取基础值
for (const debuff of this.DBUFF_V) { const baseValues: Record<number, number> = {
// 跳过状态类 debuffattrField === -1 [Attrs.HP_MAX]: this.base_hp,
if (debuff.attrField !== undefined && debuff.attrField >= 0) { [Attrs.MP_MAX]: this.base_mp,
this.Attrs[debuff.attrField] -= debuff.deV; [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;
} }
} }
// 临时型 debuff
for (const debuff of this.DBUFFS_V) { // 4. 根据属性类型计算最终值
// 跳过状态类 debuffattrField === -1 const attrType = AttrsType[attrIndex];
if (debuff.attrField !== undefined && debuff.attrField >= 0) { const isRatioAttr = attrType === BType.RATIO;
this.Attrs[debuff.attrField] -= debuff.deV;
} if (isRatioAttr) {
} // 百分比型属性:直接加减
this.Attrs[attrIndex] = totalValue + totalRatio;
} else {
// 数值型属性:(基础值+数值) × (1 + 百分比/100)
this.Attrs[attrIndex] = Math.floor(totalValue * (1 + totalRatio / 100));
} }
// 5. 确保属性值合理
this.clampSingleAttr(attrIndex);
}
/** /**
* 应用百分比型 debuff * 确保单个属性值合
* 百分比型 debuff 是基于基础属性的百分比减少
*/ */
private applyRatioDebuffs() { private clampSingleAttr(attrIndex: number) {
// 获取基础值映射 switch(attrIndex) {
const baseValues: Record<number, number> = {}; case Attrs.HP_MAX:
baseValues[Attrs.HP_MAX] = this.base_hp; case Attrs.MP_MAX:
baseValues[Attrs.MP_MAX] = this.base_mp; this.Attrs[attrIndex] = Math.max(1, this.Attrs[attrIndex]);
baseValues[Attrs.DEF] = this.base_def; break;
baseValues[Attrs.AP] = this.base_ap; case Attrs.DEF:
baseValues[Attrs.MAP] = this.base_map; case Attrs.AP:
this.Attrs[Attrs.SPEED] = this.base_speed; case Attrs.MAP:
this.Attrs[attrIndex] = Math.max(1, this.Attrs[attrIndex]);
// 持久型 debuff break;
for (const debuff of this.DBUFF_R) { case Attrs.CRITICAL:
// 跳过状态类 debuffattrField === -1 case Attrs.DODGE:
if (debuff.attrField !== undefined && debuff.attrField >= 0) { case Attrs.HIT:
const baseVal = baseValues[debuff.attrField] || this.Attrs[debuff.attrField]; this.Attrs[attrIndex] = Math.max(0, Math.min(AttrSet.ATTR_MAX, this.Attrs[attrIndex])); //AttrSet.ATTR_MAX =85
this.Attrs[debuff.attrField] -= Math.floor(baseVal * (debuff.deV / 100)); break;
} }
} }
// 临时型 debuff
for (const debuff of this.DBUFFS_R) {
// 跳过状态类 debuffattrField === -1
if (debuff.attrField !== undefined && debuff.attrField >= 0) {
const baseVal = baseValues[debuff.attrField] || this.Attrs[debuff.attrField];
this.Attrs[debuff.attrField] -= Math.floor(baseVal * (debuff.deV / 100));
}
}
}
/**
* 确保关键属性不为负数
*/
private clampAttrs() {
// HP_MAX 最少 1
this.Attrs[Attrs.HP_MAX] = Math.max(1, this.Attrs[Attrs.HP_MAX]);
// MP_MAX 最少 1
this.Attrs[Attrs.MP_MAX] = Math.max(1, this.Attrs[Attrs.MP_MAX]);
// DEF 最少 0
this.Attrs[Attrs.DEF] = Math.max(0, this.Attrs[Attrs.DEF]);
// AP 最少 0
this.Attrs[Attrs.AP] = Math.max(0, this.Attrs[Attrs.AP]);
// MAP 最少 0
this.Attrs[Attrs.MAP] = Math.max(0, this.Attrs[Attrs.MAP]);
// 百分比属性限制在 0-100 之间
this.Attrs[Attrs.CRITICAL] = Math.max(0, Math.min(85, this.Attrs[Attrs.CRITICAL]));
this.Attrs[Attrs.DODGE] = Math.max(0, Math.min(85, this.Attrs[Attrs.DODGE]));
this.Attrs[Attrs.HIT] = Math.max(0, Math.min(85, this.Attrs[Attrs.HIT]));
}
// ==================== 临时 BUFF/DEBUFF 更新 ==================== // ==================== 临时 BUFF/DEBUFF 更新 ====================
/** /**
* 更新临时 buff/debuff 的剩余时 * 更新临时 buff/debuff 的剩余时
* 应在 update 中定期调 * 应在 update 中定期调
* @param dt 时间 * @param dt 时间
*/ */
updateTemporaryBuffsDebuffs(dt: number) { updateTemporaryBuffsDebuffs(dt: number) {
let needRecalculate = false; const affectedAttrs = new Set<number>();
// 更新临时型数buff
// 更新临时型数值 buff for (const attrIndex in this.BUFFS_V) {
for (let i = this.BUFFS_V.length - 1; i >= 0; i--) { const buff = this.BUFFS_V[attrIndex];
this.BUFFS_V[i].remainTime -= dt; buff.remainTime -= dt;
if (this.BUFFS_V[i].remainTime <= 0) { if (buff.remainTime <= 0) {
this.BUFFS_V.splice(i, 1); delete this.BUFFS_V[attrIndex];
needRecalculate = true; affectedAttrs.add(parseInt(attrIndex));
} }
} }
// 更新临时型百分比 buff // 更新临时型百分比 buff
for (let i = this.BUFFS_R.length - 1; i >= 0; i--) { for (const attrIndex in this.BUFFS_R) {
this.BUFFS_R[i].remainTime -= dt; const buff = this.BUFFS_R[attrIndex];
if (this.BUFFS_R[i].remainTime <= 0) { buff.remainTime -= dt;
this.BUFFS_R.splice(i, 1); if (buff.remainTime <= 0) {
needRecalculate = true; delete this.BUFFS_R[attrIndex];
affectedAttrs.add(parseInt(attrIndex));
} }
} }
// 更新临时型数debuff // 更新临时型数debuff
for (let i = this.DBUFFS_V.length - 1; i >= 0; i--) { for (const key in this.DBUFFS_V) {
this.DBUFFS_V[i].remainTime -= dt; const debuff = this.DBUFFS_V[key];
if (this.DBUFFS_V[i].remainTime <= 0) { debuff.remainTime -= dt;
this.DBUFFS_V.splice(i, 1); if (debuff.remainTime <= 0) {
needRecalculate = true; delete this.DBUFFS_V[key];
const keyNum = parseInt(key);
const attrField = TransformBuffs(keyNum,true)
if(attrField > 0) affectedAttrs.add(attrField);
} }
} }
// 更新临时型百分比 debuff // 更新临时型百分比 debuff
for (let i = this.DBUFFS_R.length - 1; i >= 0; i--) { for (const key in this.DBUFFS_R) {
this.DBUFFS_R[i].remainTime -= dt; const debuff = this.DBUFFS_R[key];
if (this.DBUFFS_R[i].remainTime <= 0) { debuff.remainTime -= dt;
this.DBUFFS_R.splice(i, 1); if (debuff.remainTime <= 0) {
needRecalculate = true; delete this.DBUFFS_R[key];
const keyNum = parseInt(key);
const attrField = TransformBuffs(keyNum,true)
if(attrField > 0) affectedAttrs.add(attrField);
} }
} }
// 如果有 buff/debuff 过期,重新计算属性 // 只重新计算受影响的属
if (needRecalculate) { affectedAttrs.forEach(attrIndex => {
this.recalculateAttrs(); this.recalculateSingleAttr(attrIndex);
} });
} }
public isStun() { public isStun() {
return this.DBUFF_V.some(d => d.debuff === DBuff.STUN) this.DBUFFS_V[DBuff.STUN] !== undefined
} }
public isFrost() { public isFrost() {
return this.DBUFF_V.some(d => d.debuff === DBuff.FROST) this.DBUFFS_V[DBuff.FROST] !== undefined
} }
update(dt: number){ update(dt: number){
@@ -538,7 +507,7 @@ export class HeroViewComp extends CCComp {
get isActive() { get isActive() {
return this.ent.has(HeroViewComp) && this.node?.isValid; return this.ent.has(HeroViewComp) && this.node?.isValid;
} }
//状态切 //状态切
status_change(type:string){ status_change(type:string){
this.status=type this.status=type
if(type == "idle"){ if(type == "idle"){
@@ -806,7 +775,7 @@ export class HeroViewComp extends CCComp {
this.showDamageImmediate(damageInfo.damage, damageInfo.isCrit,damageInfo.anm); this.showDamageImmediate(damageInfo.damage, damageInfo.isCrit,damageInfo.anm);
// 设置延时处理下一个伤 // 设置延时处理下一个伤
this.scheduleOnce(() => { this.scheduleOnce(() => {
this.isProcessingDamage = false; this.isProcessingDamage = false;
}, this.damageInterval); }, this.damageInterval);
@@ -820,7 +789,7 @@ export class HeroViewComp extends CCComp {
this.atked_count++; this.atked_count++;
if (isCrit) { if (isCrit) {
this.BUFFCOMP.hp_tip(TooltipTypes.crit, damage.toFixed(0), damage); this.BUFFCOMP.hp_tip(TooltipTypes.crit, damage.toFixed(0), damage);
// //console.log("暴击伤害" + damage); // //console.log("暴击伤害 + damage);
} else { } else {
this.BUFFCOMP.hp_tip(TooltipTypes.life, damage.toFixed(0), damage); this.BUFFCOMP.hp_tip(TooltipTypes.life, damage.toFixed(0), damage);
// //console.log("普通伤害:" + damage); // //console.log("普通伤害:" + damage);

View File

@@ -8,7 +8,7 @@ import { HeroInfo } from "../common/config/heroSet";
import { MonModelComp } from "./MonModelComp"; import { MonModelComp } from "./MonModelComp";
import { BattleMoveComp } from "../common/ecs/position/BattleMoveComp"; import { BattleMoveComp } from "../common/ecs/position/BattleMoveComp";
import { SkillConComp } from "./SkillConComp"; import { SkillConComp } from "./SkillConComp";
import { BuffAttr, getBuffNum, SkillSet } from "../common/config/SkillSet"; import { Attrs, getAttrs, SkillSet } from "../common/config/SkillSet";
/** 角色实体 */ /** 角色实体 */
@ecs.register(`Monster`) @ecs.register(`Monster`)
export class Monster extends ecs.Entity { export class Monster extends ecs.Entity {
@@ -64,9 +64,11 @@ export class Monster extends ecs.Entity {
} }
hero_init(uuid:number=1001,node:Node,scale:number=1,box_group=BoxSet.HERO,is_boss:boolean=false,is_call:boolean=false,enhancement?: any, stageMultipliers?: any) { hero_init(uuid:number=1001,node:Node,scale:number=1,box_group=BoxSet.HERO,is_boss:boolean=false,is_call:boolean=false,enhancement?: any, stageMultipliers?: any) {
var hv = node.getComponent(HeroViewComp)!; var hv = node.getComponent(HeroViewComp)!;
hv.hide_info()
// console.log("hero_init",buff) // console.log("hero_init",buff)
let hero= HeroInfo[uuid] // 共用英雄数据 let hero= HeroInfo[uuid] // 共用英雄数据
hv.scale = scale; hv.scale = scale;
hv.fac = FacSet.MON; hv.fac = FacSet.MON;
hv.type = hero.type; hv.type = hero.type;
@@ -78,9 +80,7 @@ export class Monster extends ecs.Entity {
hv.hero_uuid= uuid; hv.hero_uuid= uuid;
hv.hero_name= hero.name; hv.hero_name= hero.name;
// 初始化Attrs属性系统参考Hero.ts的实 // 初始化Attrs属性系统参考Hero.ts的实
hv.Attrs = getBuffNum();
// 计算基础属性(使用关卡倍数) // 计算基础属性(使用关卡倍数)
const baseHp = hero.hp; const baseHp = hero.hp;
const baseAp = hero.ap; const baseAp = hero.ap;
@@ -93,46 +93,29 @@ export class Monster extends ecs.Entity {
finalHp = Math.floor(baseHp * stageMultipliers.hp); finalHp = Math.floor(baseHp * stageMultipliers.hp);
finalAp = Math.floor(baseAp * stageMultipliers.attack); finalAp = Math.floor(baseAp * stageMultipliers.attack);
// console.log(`[Monster]: 怪物${hero.name} 关卡倍数 - HP: ${baseHp} x ${stageMultipliers.hp.toFixed(2)} = ${finalHp}, AP: ${baseAp} x ${stageMultipliers.attack.toFixed(2)} = ${finalAp}`); // console.log(`[Monster]: 怪物${hero.name} 关卡倍数 - HP: ${baseHp} x ${stageMultipliers.hp.toFixed(2)} = ${finalHp}, AP: ${baseAp} x ${stageMultipliers.attack.toFixed(2)} = ${finalAp}`);
} else {
// console.log(`[Monster]: 怪物${hero.name} 使用基础属性 - HP: ${finalHp}, AP: ${finalAp}`);
} }
hv.hp = hv.hp_max = finalHp; hv.base_ap=finalAp
hv.ap = finalAp; hv.base_map=hero.mp
hv.ap_base = finalAp; hv.base_def=hero.def
hv.base_hp=finalHp
hv.base_mp=hero.mp
hv.hp=hv.base_hp
hv.mp=hv.base_mp
hv.Attrs=getAttrs()
hv.Attrs[Attrs.HP_MAX]=hv.base_hp
hv.Attrs[Attrs.MP_MAX]=hv.base_mp
hv.Attrs[Attrs.DEF]=hv.base_def
hv.Attrs[Attrs.AP]=hv.base_ap
hv.Attrs[Attrs.MAP]=hv.base_map
hv.Attrs[Attrs.SPEED]=hero.speed
hv.Attrs[Attrs.DIS]=hero.dis
// 初始化 buff/debuff 系统
hv.initAttrs();
// 设置基础属性到Attrs系统
hv.Attrs[BuffAttr.SPEED] = hv.speed = hv.speed_base = hero.speed;
hv.Attrs[BuffAttr.DIS] = hv.dis = hero.dis;
hv.Attrs[BuffAttr.ATK_CD] = hv.cd = hero.cd;
hv.Attrs[BuffAttr.HP_MAX] = hv.hp_max;
hv.Attrs[BuffAttr.AP] = hv.ap;
hv.Attrs[BuffAttr.DEF] = hv.def;
// 处理原有Buff使用统一的apply_buff方法
hero.buff.forEach((buff:any)=>{
hv.apply_buff(buff.type, buff.value);
})
// 处理肉鸽模式的增强属性
if (enhancement && enhancement.buffList && enhancement.buffList.length > 0) {
// console.log(`[Monster]: 怪物${hero.name}应用增强属性:`, enhancement.buffList.map((buff: any) => `${buff.name}:+${buff.value}`));
enhancement.buffList.forEach((buff:any)=>{
hv.apply_buff(buff.buffType, buff.value);
})
}
// 重新计算最终HP因为buff可能修改了hp_max
hv.hp = hv.hp_max;
for(let i=0;i<hero.skills.length;i++){
hv.skills.push({
cd:0,
uuid:hero.skills[i],
cd_max:i==0?hero.cd:SkillSet[hero.skills[i]].cd
})
}
this.add(hv); this.add(hv);
} }
} }

View File

@@ -32,9 +32,8 @@ export class SkillConComp extends CCComp {
update(dt: number) { update(dt: number) {
if(!smc.mission.play||smc.mission.pause) return if(!smc.mission.play||smc.mission.pause) return
const hasStun = this.HeroView.V_DBUFF.some(d => d.debuff === DBuff.STUN);
const hasFrost = this.HeroView.V_DBUFF.some(d => d.debuff === DBuff.FROST); if(!this.HeroView.isStun() && !this.HeroView.isFrost()) {
if(!hasStun && !hasFrost) {
let skills=this.HeroView.skills let skills=this.HeroView.skills
for(let i=0;i<skills.length;i++){ for(let i=0;i<skills.length;i++){
skills[i].cd += dt; skills[i].cd += dt;
@@ -49,7 +48,6 @@ export class SkillConComp extends CCComp {
} }
} }
} }

View File

@@ -3,7 +3,7 @@
* *
* 功能说明: * 功能说明:
* - 提供基于怪物类型的属性加成配置 * - 提供基于怪物类型的属性加成配置
* - 使用BuffAttr枚举定义属性增强 * - 使用Attrs枚举定义属性增强
* - 供游戏系统调用获取怪物增强数据 * - 供游戏系统调用获取怪物增强数据
* *
* @author 游戏开发团队 * @author 游戏开发团队
@@ -12,7 +12,7 @@
*/ */
import { QualitySet } from "../common/config/BoxSet"; import { QualitySet } from "../common/config/BoxSet";
import { BuffAttr } from "../common/config/SkillSet"; import { Attrs } from "../common/config/SkillSet";
import { getMonList } from "../common/config/heroSet"; import { getMonList } from "../common/config/heroSet";
/** /**
@@ -92,16 +92,14 @@ export const StageConfigRules = {
* 按权重排序,数值越大优先级越高 * 按权重排序,数值越大优先级越高
*/ */
export const AvailableEnhancementPool = [ export const AvailableEnhancementPool = [
{ buffType: BuffAttr.HP, weight: 10, baseValue: 80, name: "生命值增强" }, { buffType: Attrs.HP_MAX, weight: 10, baseValue: 80, name: "生命值增强" },
{ buffType: BuffAttr.ATK, weight: 9, baseValue: 50, name: "攻击力增强" }, { buffType: Attrs.AP, weight: 9, baseValue: 50, name: "攻击力增强" },
{ buffType: BuffAttr.CRITICAL, weight: 8, baseValue: 30, name: "暴击率增强" }, { buffType: Attrs.CRITICAL, weight: 8, baseValue: 30, name: "暴击率增强" },
{ buffType: BuffAttr.DEF, weight: 7, baseValue: 40, name: "防御增强" }, { buffType: Attrs.DEF, weight: 7, baseValue: 40, name: "防御增强" },
{ buffType: BuffAttr.CRITICAL_DMG, weight: 6, baseValue: 60, name: "暴击伤害增强" }, { buffType: Attrs.CRITICAL_DMG, weight: 6, baseValue: 60, name: "暴击伤害增强" },
{ buffType: BuffAttr.DODGE, weight: 5, baseValue: 25, name: "闪避增强" }, { buffType: Attrs.DODGE, weight: 5, baseValue: 25, name: "闪避增强" },
{ buffType: BuffAttr.ATK_CD, weight: 4, baseValue: 20, name: "攻击速度增强" }, { buffType: Attrs.AS, weight: 4, baseValue: 20, name: "攻击速度增强" },
{ buffType: BuffAttr.LIFESTEAL, weight: 3, baseValue: 15, name: "吸血" }, { buffType: Attrs.LIFESTEAL, weight: 3, baseValue: 15, name: "吸血" },
{ buffType: BuffAttr.DMG_RED, weight: 2, baseValue: 20, name: "免伤" },
{ buffType: BuffAttr.PUNCTURE, weight: 1, baseValue: 2, name: "穿刺" }
]; ];
/** /**
@@ -128,8 +126,8 @@ export const MonsterTypeBaseConfig = {
export interface MonsterEnhancementData { export interface MonsterEnhancementData {
name: string; name: string;
description: string; description: string;
buffs: { [key in BuffAttr]?: number }; buffs: { [key in Attrs]?: number };
buffList: Array<{ buffType: BuffAttr; value: number; name: string }>; buffList: Array<{ buffType: Attrs; value: number; name: string }>;
} }
/** /**
@@ -138,7 +136,7 @@ export interface MonsterEnhancementData {
* @param excludeTypes 排除的属性类型 * @param excludeTypes 排除的属性类型
* @returns 选中的增强属性数组 * @returns 选中的增强属性数组
*/ */
export function selectRandomEnhancements(count: number, excludeTypes: BuffAttr[] = []): Array<{buffType: BuffAttr, weight: number, baseValue: number, name: string}> { export function selectRandomEnhancements(count: number, excludeTypes: Attrs[] = []): Array<{buffType: Attrs, weight: number, baseValue: number, name: string}> {
if (count <= 0) return []; if (count <= 0) return [];
// 过滤掉排除的属性类型 // 过滤掉排除的属性类型
@@ -147,7 +145,7 @@ export function selectRandomEnhancements(count: number, excludeTypes: BuffAttr[]
if (availablePool.length === 0) return []; if (availablePool.length === 0) return [];
const selectedEnhancements = []; const selectedEnhancements = [];
const usedTypes = new Set<BuffAttr>(); const usedTypes = new Set<Attrs>();
for (let i = 0; i < count && i < availablePool.length; i++) { for (let i = 0; i < count && i < availablePool.length; i++) {
// 计算权重总和 // 计算权重总和
@@ -185,7 +183,7 @@ export function getMonsterEnhancement(monsterType: MonsterType, useRandom: boole
const baseConfig = MonsterTypeBaseConfig[monsterType]; const baseConfig = MonsterTypeBaseConfig[monsterType];
const enhancementCount = MonsterEnhancementCountConfig[monsterType]; const enhancementCount = MonsterEnhancementCountConfig[monsterType];
let selectedEnhancements: Array<{buffType: BuffAttr, weight: number, baseValue: number, name: string}> = []; let selectedEnhancements: Array<{buffType: Attrs, weight: number, baseValue: number, name: string}> = [];
if (useRandom) { if (useRandom) {
// 随机生成增强属性 // 随机生成增强属性
@@ -198,8 +196,8 @@ export function getMonsterEnhancement(monsterType: MonsterType, useRandom: boole
} }
// 构建buffs对象 // 构建buffs对象
const buffs: { [key in BuffAttr]?: number } = {}; const buffs: { [key in Attrs]?: number } = {};
const buffList: Array<{ buffType: BuffAttr; value: number; name: string }> = []; const buffList: Array<{ buffType: Attrs; value: number; name: string }> = [];
selectedEnhancements.forEach(enhancement => { selectedEnhancements.forEach(enhancement => {
buffs[enhancement.buffType] = enhancement.baseValue; buffs[enhancement.buffType] = enhancement.baseValue;

View File

@@ -38,7 +38,6 @@ load(startPos: Vec3, parent: Node, uuid: number, targetPos: any[], caster:Hero
node.setPosition(startPos); node.setPosition(startPos);
if(caster.fac==FacSet.MON){ if(caster.fac==FacSet.MON){
node.scale=v3(node.scale.x*-1,1,1) node.scale=v3(node.scale.x*-1,1,1)
}else{ }else{
if(caster.type==HType.warrior){ if(caster.type==HType.warrior){
if(caster.node.scale.x<0){ if(caster.node.scale.x<0){
@@ -49,21 +48,18 @@ load(startPos: Vec3, parent: Node, uuid: number, targetPos: any[], caster:Hero
// 添加技能组件 // 添加技能组件
const SComp = node.getComponent(SkillViewCom); // 初始化技能参数 const SComp = node.getComponent(SkillViewCom); // 初始化技能参数
// 只设置必要的运行时属性,配置信息通过 SkillSet[uuid] 访问 // 只设置必要的运行时属性,配置信息通过 SkillSet[uuid] 访问
Object.assign(SComp, {
// 核心标识 // 核心标识
s_uuid: uuid, SComp.s_uuid= uuid
cName:caster.hero_name, SComp.cName=caster.hero_name
scale: caster.node.scale.x, SComp.scale= caster.node.scale.x
// 位置和施法者信息 // 位置和施法者信息
startPos: startPos, SComp.startPos= startPos
targetPos: targetPos, SComp.targetPos= targetPos
group: caster.box_group, SComp.group= caster.box_group
fac: caster.fac, SComp.fac= caster.fac,
// 技能数值 // 技能数值
ap: caster.Attrs[Attrs.AP], SComp.Attrs= caster.Attrs
caster: caster, SComp.caster= caster,
});
this.add(SComp); this.add(SComp);
} }

View File

@@ -40,11 +40,12 @@ export class SkillViewCom extends CCComp {
target:HeroViewComp=null; target:HeroViewComp=null;
parent:Node=null; parent:Node=null;
target_postions:any[]=null target_postions:any[]=null
group:0 group:number=0
fac: 0 fac:number=0
// 战斗相关运行时数据 // 战斗相关运行时数据
Attrs:any=null Attrs:any=null
targetPos:any[]=null startPos:any=null
targetPos:any=null
start() { start() {
// var entity = this.ent as ecs.Entity; // ecs.Entity 可转为当前模块的具体实体对象 // var entity = this.ent as ecs.Entity; // ecs.Entity 可转为当前模块的具体实体对象
this.node.getChildByName("ready").active = this.hasReady this.node.getChildByName("ready").active = this.hasReady