Files
PHY/GAS_AttributeSystem_Notes.md
2026-03-03 01:23:02 +08:00

255 lines
8.1 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.
# GAS 属性系统实现记录PHY
> 说明:本文记录在本项目中,为古风游戏(四维:臂力/根骨/内息/身法)搭建 GAS 属性体系、派生属性、职业初始化、以及服务器端定时回复(回血/回内)等功能的实现过程。
>
> 本项目模块不对外暴露,因此代码全部放在 `Source/PHY/Private` 内AttributeSet/GE/MMC/GameplayTags 等)。
---
## 0. 总体目标
- 基础属性Primary
- **Strength臂力**
- **Constitution根骨**
- **InnerBreath内息**
- **Agility身法**
- 其他属性由四维派生MMC 计算)或由装备/功法 GE 附加。
- 不对外提供公共模块 API代码全部在 `Private`
---
## 1. GAS 组件挂载位置与初始化
### 1.1 AbilitySystemComponent 放在 PlayerState
-`APHYPlayerState` 的构造函数中创建:
- `UAbilitySystemComponent* AbilitySystemComponent`
- `UPHYAttributeSet* AttributeSet`
- 设置复制:
- `AbilitySystemComponent->SetIsReplicated(true)`
- `AbilitySystemComponent->SetReplicationMode(EGameplayEffectReplicationMode::Minimal)`(适合 PlayerState
相关文件:
- `Source/PHY/Private/Gameplay/Player/PHYPlayerState.cpp`
### 1.2 Character 初始化 GASOwner=PlayerStateAvatar=Character
`APHYPlayerCharacter`
- `PossessedBy()`(服务器)调用 `InitializeGAS()`
- `OnRep_PlayerState()`(客户端)也调用 `InitializeGAS()`
初始化逻辑(核心):
- `ASC->InitAbilityActorInfo(PlayerState, this)`
- 服务器:
- Apply `UPHYGE_InitPrimary`(设置四维初值)
- Apply `UPHYGE_DerivedAttributes`无限期派生属性Override + MMC
- 设置资源/当前值:
- `Health = MaxHealth`
- `InnerPower = MaxInnerPower`
相关文件:
- `Source/PHY/Private/Character/PHYPlayerCharacter.h/.cpp`
---
## 2. AttributeSet全部在 Private
### 2.1 AttributeSet 位置
- `Source/PHY/Private/AbilitySystem/Attributes/PHYAttributeSet.h`
- `Source/PHY/Private/AbilitySystem/Attributes/PHYAttributeSet.cpp`
### 2.2 属性分组
#### Primary基础四维
- `Strength`
- `Constitution`
- `InnerBreath`
- `Agility`
#### Vitals生命
- `Health`
- `MaxHealth`
#### Resource资源
- `InnerPower`
- `MaxInnerPower`
#### Derived示例派生
- `MoveSpeed`
- `PhysicalAttack`
- `PhysicalDefense`
#### Secondary二级属性
- `Tenacity`(韧性)
- `CritChance`(暴击率 0~1
- `CritDamage`(暴击伤害倍率 >=1
- `DodgeChance`(闪避 0~1
- `HitChance`(命中 0~1
- `ParryChance`(招架 0~1
- `CounterChance`(反击 0~1业务逻辑要求闪避/招架成功后再判定)
- `ArmorPenetration`(穿甲 0~1目前字段存在数值来源更多偏装备/功法)
- `DamageReduction`(免伤 0~1
- `LifeSteal`(吸血 0~1目前字段存在数值来源更多偏装备/功法)
- `HealthRegenRate`(生命回复/秒)
- `InnerPowerRegenRate`(内力回复/秒)
### 2.3 Clamp 与复制
在 AttributeSet 内实现:
- `PreAttributeChange`
- `Health` / `InnerPower` clamp 到 `[0, Max]`
- 概率类 clamp 到 `[0, 1]`
- `CritDamage` clamp `>= 1`
- `PostGameplayEffectExecute`
- 对关键属性再兜底 clamp
- 完整实现:
- `OnRep_XXX`
- `GetLifetimeReplicatedProps` + `DOREPLIFETIME_CONDITION_NOTIFY`
---
## 3. 派生属性计算MMC
### 3.1 MMC 放置位置
`Source/PHY/Private/AbilitySystem/MMC/`
### 3.2 已实现的 MMC示例
#### 基础派生
- `UPHY_MMC_MaxHealth``MaxHealth = 100 + Constitution * 25`
- `UPHY_MMC_MoveSpeed``MoveSpeed = 600 + Agility * 2`
- `UPHY_MMC_PhysicalAttack``PhysicalAttack = 10 + Strength * 2`
- `UPHY_MMC_PhysicalDefense``PhysicalDefense = 5 + Constitution * 1.5`
#### 二级属性派生(示例系数,后续建议数据化)
- `UPHY_MMC_MaxInnerPower``MaxInnerPower = 100 + InnerBreath * 20`
- `UPHY_MMC_Tenacity``Tenacity = InnerBreath * 1`
- `UPHY_MMC_CritChance``CritChance = 0.05 + Agility * 0.002 (clamp 0..1)`
- `UPHY_MMC_CritDamage``CritDamage = 1.5 + Strength * 0.005 (>=1)`
- `UPHY_MMC_DodgeChance``DodgeChance = 0.02 + Agility * 0.002`
- `UPHY_MMC_HitChance``HitChance = 0.9 + Agility * 0.001`
- `UPHY_MMC_ParryChance``ParryChance = 0.03 + Strength * 0.001`
- `UPHY_MMC_CounterChance``CounterChance = 0.1 + Agility * 0.001`
- `UPHY_MMC_DamageReduction``DamageReduction = Constitution * 0.001`
- `UPHY_MMC_HealthRegenRate``HealthRegenRate = Constitution * 0.1`
- `UPHY_MMC_InnerPowerRegenRate``InnerPowerRegenRate = InnerBreath * 0.15`
> 注:部分属性如穿甲/吸血更适合由装备/功法 GE 直接加成,而非完全从四维硬算。
---
## 4. GameplayEffect初始化 + 派生)
### 4.1 初始化四维:`UPHYGE_InitPrimary`
- 文件:`Source/PHY/Private/AbilitySystem/Effects/PHYGE_InitPrimary.h/.cpp`
- 类型Instant
-`SetByCaller` 写入四维(复用同一个 GE 支持所有职业)
SetByCaller TagNativeGameplayTags 管理):
- `Data.Init.Primary.Strength`
- `Data.Init.Primary.Constitution`
- `Data.Init.Primary.InnerBreath`
- `Data.Init.Primary.Agility`
### 4.2 派生属性:`UPHYGE_DerivedAttributes`
- 文件:`Source/PHY/Private/AbilitySystem/Effects/PHYGE_DerivedAttributes.h/.cpp`
- 类型Infinite
- Modifiers全部使用 `Override + MMC`
- 包含 `MaxHealth/MoveSpeed/PhysicalAttack/PhysicalDefense`
- 包含新增二级属性/资源上限(如 `MaxInnerPower`、暴击等)
---
## 5. GameplayTags 组织(集中管理,避免硬编码 FName
### 5.1 Init 属性 Tag
- `Source/PHY/Private/GameplayTags/InitAttributeTags.h/.cpp`
### 5.2 Regen Tag
- `Source/PHY/Private/GameplayTags/RegenTags.h/.cpp`
### 5.3 ini 配置
- 新增/维护:`Config/DefaultGameplayTags.ini`
- 包含 `Data.Init.Primary.*`
- 包含 `Data.Regen.*`
---
## 6. 职业/门派初始属性(全局配置)
### 6.1 职业枚举
- `Source/PHY/Private/AbilitySystem/PHYCharacterClass.h`
### 6.2 DataAsset全局职业默认值表
- `Source/PHY/Private/AbilitySystem/PHYClassDefaults.h`
- `UPHYClassDefaults`
- `FallbackPrimary`
- `Classes[]`:每个职业对应一套 `FPHYPrimaryAttributes`
### 6.3 配置位置GameInstance
考虑到 `ClassDefaults` 是全局数据,不应放在每个 Character 上:
- `UPHYGameInstance` 增加 `ClassDefaults` 引用
- `GetClassDefaults()`
文件:
- `Source/PHY/Private/Gameplay/PHYGameInstance.h/.cpp`
使用方式:
- 在编辑器中的项目 GameInstance 蓝图(`DefaultEngine.ini` 指定的 `GameInstance_Default`)里配置 `ClassDefaults` 资产。
---
## 7. 服务器端定时回复(方案 B代码驱动
> 选择方案 B不使用 Period GE而使用 **服务器 Timer + Instant GE**。
### 7.1 Regen 每跳 GE`UPHYGE_RegenTick`
- 文件:`Source/PHY/Private/AbilitySystem/Effects/PHYGE_RegenTick.h/.cpp`
- 类型Instant
- 使用 SetByCaller
- `Data.Regen.Health`(加到 Health
- `Data.Regen.InnerPower`(加到 InnerPower
### 7.2 Character 计时器逻辑
`APHYPlayerCharacter`
- 属性:`RegenInterval`(默认 1 秒)
-`InitializeGAS()` 服务器端启动 Timer
- `SetTimer(RegenTimerHandle, RegenTick, RegenInterval, true)`
- `RegenTick()`
- `HealthDelta = HealthRegenRate * RegenInterval`
- `InnerPowerDelta = InnerPowerRegenRate * RegenInterval`
- Apply `UPHYGE_RegenTick`SetByCaller 写入本次增量)
> 后续可拓展:脱战回复/坐下打坐/战斗中禁回等,均通过 GameplayTag 或状态判断来控制 `RegenTick()` 是否执行。
---
## 8. 代码风格/工程注意事项
### 8.1 UTF-8 BOM 引发的编译/IDE 问题
过程中多次遇到文件头 BOM 导致的解析错误(如 `无法解析符号 ''`)。
已对相关文件移除 BOM例如 PlayerState / PlayerCharacter / GameInstance 等)。
---
## 9. 下一步建议(可选)
- 将二级属性派生系数数据化DataAsset/CurveTable减少硬编码常量。
- 装备/功法:用 GE 直接对二级属性加成(穿甲/吸血等更适合走装备词条)。
- 战斗结算库:统一命中/闪避/招架/反击触发顺序与公式。
- Regen 增加“脱战 N 秒后生效”等状态控制GameplayTag 驱动)。