vault backup: 2026-05-31 12:41:10
This commit is contained in:
@@ -411,4 +411,98 @@ repos:
|
||||
同一页面上给检索工具一个优先级:
|
||||
```
|
||||
1. 当前模块 repo → 2. 领域 Group → 3. 全局 Group → 4. grep 兜底
|
||||
```
|
||||
```
|
||||
---
|
||||
|
||||
## 模块合并方案:188 模块 → 11 功能组
|
||||
|
||||
### 方案总览
|
||||
|
||||
| 组名 | 文件数 | 模块数 | 预计耗时 |
|
||||
|------|--------|--------|----------|
|
||||
| Core | 2,063 | 1 | 2-4h |
|
||||
| Engine | 3,934 | 1 | 4-10h |
|
||||
| Gameplay | 2,874 | 53 | 2-4h |
|
||||
| Rendering | 1,962 | 30 | 1-2h |
|
||||
| UI | 1,194 | 10 | 30-60min |
|
||||
| AudioSignal | 623 | 21 | 15-30min |
|
||||
| MediaMovieScene | 1,209 | 17 | 30-60min |
|
||||
| Networking | 1,214 | 13 | 30-60min |
|
||||
| PhysicsAnimation | 916 | 20 | 30-60min |
|
||||
| Platform | 493 | 17 | 10-20min |
|
||||
| Experimental | 1,397 | 1 | 1-2h |
|
||||
|
||||
### 各组包含模块
|
||||
|
||||
#### Core (2063 files)
|
||||
- Core
|
||||
|
||||
#### Engine (3934 files)
|
||||
- Engine
|
||||
|
||||
#### Gameplay (2874 files, 53 模块)
|
||||
- CoreUObject, ApplicationCore, AppFramework, Launch, Projects, Serialization
|
||||
- Json, JsonUtilities, XmlParser, Cbor, CoreOnline, CorePreciseFP
|
||||
- TypedElementFramework, TypedElementRuntime, FieldNotification, UniversalObjectLocator
|
||||
- TraceLog, DeveloperSettings, BuildSettings, EngineSettings
|
||||
- AIModule, NavigationSystem, GameplayTasks, GameplayTags, GameplayDebugger
|
||||
- Navmesh, MassEntity, StateStream, GameMenuBuilder
|
||||
- Analytics, AutomationMessages, AutomationTest, AutomationWorker
|
||||
- StorageServerClient, StorageServerClientDebug, RuntimeAssetCache, InstallBundleManager
|
||||
- PakFile, SessionServices, SessionMessages, Messaging, MessagingCommon, MessagingRpc
|
||||
- PreLoadScreen, FriendsAndChat, EngineMessages, CrashReportCore, Instrumentation
|
||||
- StudioTelemetry, PerfCounters, ClientPilot, ExternalRPCRegistry, Portal
|
||||
- OodleDataCompression, SandboxFile, StreamingFile, StreamingPauseRendering
|
||||
- CookOnTheFly, MoviePlayerProxy, NullInstallBundleManager, BlueprintRuntime
|
||||
- PlatformThirdPartyHelpers, CUDA, RSA, PropertyPath, AutoRTFM, AssetRegistry
|
||||
- UELibrary, UnrealGame, NNE, Toolbox, SymsLib, VerseCompiler, MathCore, Linux
|
||||
|
||||
#### Rendering (1962 files, 30 模块)
|
||||
- Renderer, RenderCore, RHI, RHICore, D3D12RHI, VulkanRHI, OpenGLDrv
|
||||
- NullDrv, ColorManagement, OpenColorIOWrapper
|
||||
- Datasmith, Interchange, MeshDescription, MeshConversion, MeshConversionEngineTypes
|
||||
- StaticMeshDescription, SkeletalMeshDescription, MeshUtilitiesCommon, RawMesh
|
||||
- ImageCore, ImageWrapper, ImageWriteQueue, TextureUtilitiesCommon
|
||||
- IESFile, MaterialShaderQualitySettings, SynthBenchmark
|
||||
|
||||
#### UI (1194 files, 10 模块)
|
||||
- Slate, SlateCore, UMG, SlateRHIRenderer, AdvancedWidgets
|
||||
- SlateNullRenderer, WidgetCarousel, InputCore, InputDevice
|
||||
|
||||
#### AudioSignal (623 files, 21 模块)
|
||||
- AudioMixer, AudioMixerCore, AudioExtensions, AudioAnalyzer, AudioLink
|
||||
- AudioCaptureCore, AudioCaptureImplementations, AudioDeviceEnumeration
|
||||
- AudioPlatformConfiguration, AudioPlatformSupport, RadAudioCodec
|
||||
- BinkAudioDecoder, SignalProcessing, SoundFieldRendering
|
||||
- NonRealtimeAudioRenderer, OpusAudioDecoder, VorbisAudioDecoder
|
||||
- AdpcmAudioDecoder, UEJpegComp, UEWavComp
|
||||
|
||||
#### MediaMovieScene (1209 files, 17 模块)
|
||||
- Media, MediaAssets, MediaUtils, MoviePlayer, MoviePlayerProxy
|
||||
- MovieScene, MovieSceneCapture, MovieSceneTracks, AVEncoder, AVIWriter
|
||||
- LevelSequence, TimeManagement, Overlay, GameplayMediaEncoder
|
||||
- CinematicCamera, LiveLinkInterface, LiveLinkAnimationCore
|
||||
- LiveLinkMessageBusFramework
|
||||
|
||||
#### Networking (1214 files, 13 模块)
|
||||
- Online, Net, Networking, NetworkReplayStreaming, NetworkFile
|
||||
- NetworkFileSystem, Sockets, WebBrowser, WebBrowserTexture
|
||||
- PacketHandlers, IPC, CEF3Utils, RewindDebuggerRuntimeInterface
|
||||
|
||||
#### PhysicsAnimation (916 files, 20 模块)
|
||||
- PhysicsCore, GeometryCore, GeometryFramework, AnimationCore
|
||||
- AnimGraphRuntime, Landscape, Foliage
|
||||
- ClothingSystemRuntimeInterface, ClothingSystemRuntimeCommon, ClothingSystemRuntimeNv
|
||||
- VectorVM, InteractiveToolsFramework, AugmentedReality
|
||||
|
||||
#### Platform (493 files, 17 模块)
|
||||
- Apple, Android, IOS, Linux, Windows, Unix, Solaris
|
||||
- EyeTracker, HeadMountedDisplay, VirtualProduction, HardwareSurvey
|
||||
- InputDevice, MRMesh, Advertising
|
||||
|
||||
#### Experimental (1397 files)
|
||||
- Experimental
|
||||
|
||||
### Group 配置
|
||||
|
||||
合并后统一放在 Group 下,跨组查询使用 。
|
||||
@@ -0,0 +1,565 @@
|
||||
# AIDM 项目技术分析报告
|
||||
|
||||
> 测试用提示词(标准化,两组完全一致)
|
||||
> 项目:AIDM — UE5.7 修仙 ARPG
|
||||
> 日期:2026-05-30
|
||||
|
||||
---
|
||||
|
||||
# 任务 1:NPC 系统完整架构
|
||||
|
||||
## 1.1 分级机制(A/B/C 三级)
|
||||
|
||||
NPC 分级体系定义在 `LWSNpcTypes.h:111-219` 和设计文档中:
|
||||
|
||||
| 级别 | 数量 | 跨存档保留 | 模拟深度 | 更新频率 |
|
||||
|------|------|-----------|---------|---------|
|
||||
| **A级** | 20~40 | 姓名/外貌/性格/资质永不改变(`IdentitySeedId` 种子驱动) | 完整(情绪/关系/目标/记忆/决策) | 每个时间单位 |
|
||||
| **B级** | 100~300 | 角色定位保留,人物更换 | 中度(目标/关系/基础决策) | 每2~5个时间单位 |
|
||||
| **C级** | 数百~上千 | 无 | 轻度(位置/状态/基础反应) | 按需/低频 |
|
||||
|
||||
关键字段:`FLWSNpcData` 中 `Tier`(`ELWSNpcTier`)、`IdentitySeedId`(A级跨存档种子ID)。C→B 涌现升级通过 `InteractionCount` 和 `SignificanceScore` 追踪。
|
||||
|
||||
## 1.2 决策模型(Utility AI)
|
||||
|
||||
核心文件:`LWSNpcDecisionSystem.h/.cpp`
|
||||
|
||||
**评分公式**(`LWSNpcDecisionSystem.h:19-31`):
|
||||
```
|
||||
BaseScore(a) = Σᵢ NeedRelevance[a][i] × Npc.Needs[i] (i ∈ 6维需求)
|
||||
PersonalityFactor = f(Temperament, Caution, Morality, a)
|
||||
GoalFactor = Π(Goal Type → bonus, a)
|
||||
ScoreWithNoise(a) = BaseScore × PersonalityFactor × GoalFactor + Uniform[0, 0.10]
|
||||
ChosenAction = argmaxₐ ScoreWithNoise(a)
|
||||
```
|
||||
|
||||
**6 维需求**:`Survival / Safety / Social / Power / Resource / Cultivation`,每日衰减(缺乏度↑),存储在 `FLWSNpcData::Needs`(`TArray<float>` 长度固定为6)。
|
||||
|
||||
**7 种高层 Action**:`Wander / GoHome / Cultivate / SeekResource / Socialize / Flee / Hunt`
|
||||
|
||||
**3 种 Behavior**(执行层翻译):
|
||||
- `Idle` → 原地不动
|
||||
- `Wander` → 6邻居随机跳转(20%概率原地不动)
|
||||
- `MoveTo` → 贪心1-hop向目标移动
|
||||
|
||||
**3D 性格**(`LWSNpcPersonalityTypes.h`):`Temperament`(冷→热)、`Caution`(慎→莽)、`Morality`(义→私),影响各 Action 的权重系数。
|
||||
|
||||
**行为持续性**(设计文档 §八,待实施):承诺期 `MinDuration`、完成判定 `IsFinished`、Need 分摊扣减、Stickiness 黏性、Hysteresis 迟滞、中断保护。
|
||||
|
||||
## 1.3 与时间系统的关系
|
||||
|
||||
时间系统定义在 `RPGCommon/Public/Time/RPGGameTimeTypes.h` 和 `RPGGameTimeSubsystem.h`:
|
||||
|
||||
- **日历常量**:12月/年,30天/月,360天/年(`FRPGGameRawTime`)
|
||||
- **驱动方式**:`URPGGameTimeSubsystem::OnGameTimeChanged` 广播,每次 `DeltaDays > 0` 触发
|
||||
- **NPC 模拟入口**:`ULWSNpcSimulationSubsystem::HandleGameTimeChanged` 订阅时间广播 → 按 `DeltaDays` 次调用 `SimulateOneDay()`
|
||||
- **数据流**:
|
||||
```
|
||||
GameTimeSubsystem.OnGameTimeChanged (DeltaDays>0)
|
||||
→ NpcSim.SimulateDays(N)
|
||||
→ 对每个存活 NPC:
|
||||
→ DecisionSystem.DecayNeeds (需求衰减)
|
||||
→ DecisionSystem.DecideAction (评分→选Action→翻译Behavior)
|
||||
→ TickNpcOneDay (Idle/Wander/MoveTo 物理推进)
|
||||
→ SpatialIndex.Move (更新空间索引)
|
||||
→ PushTrail (环形buffer记录轨迹)
|
||||
→ 同格NPC关系建立 / 关系衰减 / 信息传播
|
||||
```
|
||||
|
||||
## 1.4 存档方式
|
||||
|
||||
存档系统定义在 `RPGSaveSystem/Public/RPGSaveSubsystem.h`:
|
||||
|
||||
- **两级存档**:`URPGSaveSystemData`(系统级,槽位列表)+ `URPGSaveDataObject`(玩家级,`TMap<FName, FSaveDataContainer>`)
|
||||
- **接口机制**:各模块通过 `ISaveableInterface` 注册到 `URPGSaveSubsystem`,以 `FName SaveID` 标识
|
||||
- **NPC 数据持久化**:`ULWSNpcSimulationSubsystem` 提供 `GetActiveNpcsCopy()`(返回 `TArray<FLWSNpcData>` 副本)和 `RestoreNpcsFromSave()`(从存档还原),NPC 数据作为 `FLWSNpcData[]` 序列化存入 `FSaveDataContainer`
|
||||
- **玩家数据持久化**:通过 `URPGAttributeSet` + `FRPGCharacterAttributeData` 保存属性,`FRPGSkilllActionPoseTree` 保存技能映射,`FSkilllTreeDataPool` 保存技能树
|
||||
|
||||
---
|
||||
|
||||
# 任务 2:商队 NPC 跨系统依赖分析
|
||||
|
||||
新增「商队 NPC」类型需要修改以下模块:
|
||||
|
||||
## 必须修改的模块
|
||||
|
||||
### 1. LivingWorldSystem 模块
|
||||
|
||||
| 文件 | 修改内容 |
|
||||
|------|---------|
|
||||
| `LWSNpcTypes.h` | `ELWSNpcBehavior` 新增 `Trade`/`Caravan` 枚举值;`FLWSNpcData` 新增字段:`TradeRoute`(起点→终点)、`TradeGoods`(货物数组)、`CaravanOwnerFactionId` |
|
||||
| `LWSNpcPersonalityTypes.h` | `ELWSNpcAction` 新增 `TradeCaravan`;`ELWSNpcNeed` 可能需要新增 `Wealth` 维度;`ELWSNpcGoal` 新增 `TradeGoal` |
|
||||
| `LWSNpcDecisionSystem.h/.cpp` | `NeedRelevance` 矩阵新增 `TradeCaravan` 行;Personality/Goal 权重新增商队相关因子;`ApplyActionToBehavior` 新增 `TradeCaravan → MoveTo` 翻译逻辑 |
|
||||
| `LWSNpcSimulationSubsystem.h/.cpp` | `TickNpcOneDay` 新增 Trade 行为处理(沿路线移动、到达后触发交易结算) |
|
||||
| `LWSNpcGenerator.h/.cpp` | 新增商队生成逻辑(沿贸易路线撒点、分配货物) |
|
||||
| `LWSNpcRelationSubsystem.h/.cpp` | 商队与聚落/势力的交易关系类型 |
|
||||
| `LWSNpcSpatialIndex.h` | 如无结构变化则无需修改 |
|
||||
|
||||
### 2. 势力/聚落模块
|
||||
|
||||
| 文件 | 修改内容 |
|
||||
|------|---------|
|
||||
| `LWSFactionTypes.h` | 势力新增贸易路线数据、商队所有权 |
|
||||
| `LWSSettlementGenerator.h` | 聚落间贸易路线生成(可为商队提供路径) |
|
||||
| `LWSFactionGenerator.h` | 势力初始化时分配商队 |
|
||||
|
||||
### 3. 世界/资源模块
|
||||
|
||||
| 文件 | 修改内容 |
|
||||
|------|---------|
|
||||
| `LWSResourceGenerator.h` | 商队可携带/交易资源类型定义 |
|
||||
| `LWSChronicleSubsystem.h` | 商队到达/被劫事件写入编年史 |
|
||||
|
||||
## 存档结构变化
|
||||
|
||||
**需要变化**:`FLWSNpcData` 新增字段(TradeRoute、TradeGoods 等)会影响序列化。由于 `FLWSNpcData` 是 `USTRUCT` 且直接存储在 `ActiveNpcs`(`TArray<FLWSNpcData>`),新增字段后旧存档将不兼容。需要:
|
||||
|
||||
1. 在 `URPGSaveDataObject::VersionMap` 中递增 NPC 数据版本号
|
||||
2. 提供存档迁移逻辑(`RestoreNpcsFromSave` 中检测旧版本并填充默认值)
|
||||
|
||||
**`FRPGCharacterAttributeData` 和 `URPGAttributeSet`**:如果商队不涉及玩家属性变化,这两处不需要修改。
|
||||
|
||||
## 对 GAS 属性系统的影响
|
||||
|
||||
**直接影响:无。** GAS 属性系统(`URPGAttributeSet`)当前服务于玩家/Actor 角色的战斗属性,而 LivingWorld NPC 是纯数据 `USTRUCT`,不挂载 `AbilitySystemComponent`。
|
||||
|
||||
**间接影响(可选扩展)**:如果未来商队 NPC 需要与玩家发生战斗交互(如劫商队),则需要为商队守卫创建 `RPGAICharacter`(Actor),此时会走 GAS 属性系统。但这属于"商队战斗"子功能,不属于商队基础框架。
|
||||
|
||||
## 涉及文件汇总(约 12 个文件)
|
||||
|
||||
```
|
||||
Plugins/RPGGameCore/Source/LivingWorldSystem/Public/LWSNpcTypes.h
|
||||
Plugins/RPGGameCore/Source/LivingWorldSystem/Public/LWSNpcPersonalityTypes.h
|
||||
Plugins/RPGGameCore/Source/LivingWorldSystem/Public/LWSNpcDecisionSystem.h
|
||||
Plugins/RPGGameCore/Source/LivingWorldSystem/Private/LWSNpcDecisionSystem.cpp
|
||||
Plugins/RPGGameCore/Source/LivingWorldSystem/Public/LWSNpcSimulationSubsystem.h
|
||||
Plugins/RPGGameCore/Source/LivingWorldSystem/Private/LWSNpcSimulationSubsystem.cpp
|
||||
Plugins/RPGGameCore/Source/LivingWorldSystem/Public/LWSNpcGenerator.h
|
||||
Plugins/RPGGameCore/Source/LivingWorldSystem/Private/LWSNpcGenerator.cpp
|
||||
Plugins/RPGGameCore/Source/LivingWorldSystem/Public/LWSNpcRelationSubsystem.h
|
||||
Plugins/RPGGameCore/Source/LivingWorldSystem/Public/LWSFactionTypes.h
|
||||
Plugins/RPGGameCore/Source/LivingWorldSystem/Public/LWSSettlementGenerator.h
|
||||
Plugins/RPGGameCore/Source/LivingWorldSystem/Public/LWSChronicleSubsystem.h
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# 任务 3:「御剑飞行」ActionPose 代码生成
|
||||
|
||||
## 3.1 枚举扩展
|
||||
|
||||
在 `RPGTypes.h:202-260` 的 `ELM_ActionPose` 中,`AirFlying` 已存在,但「御剑飞行」作为一种特殊的战斗移动姿态,建议新增专用枚举值:
|
||||
|
||||
```cpp
|
||||
// RPGTypes.h — 在 AirFlying 之后、AirDodge 之前新增
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class ELM_ActionPose : uint8
|
||||
{
|
||||
// ... 现有值保持不变 ...
|
||||
|
||||
//空行
|
||||
AirFlying,
|
||||
//御剑飞行(战斗移动态,可在飞行中施法/攻击)
|
||||
AirSwordFlying, // <-- 新增
|
||||
//空避
|
||||
AirDodge,
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
## 3.2 头文件声明
|
||||
|
||||
```cpp
|
||||
// SwordFlyingActionPose.h
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "LogicStateMachine/SDHGAState.h"
|
||||
#include "GameplayTagContainer.h"
|
||||
#include "SwordFlyingActionPose.generated.h"
|
||||
|
||||
/**
|
||||
* 御剑飞行 ActionPose 状态
|
||||
*
|
||||
* 设计要点:
|
||||
* - 继承自 USDHGAState,挂载在 USkillSMInstance 状态机中
|
||||
* - 进入此状态时:角色踩上飞剑,移动速度切换为飞行速度,消耗法力
|
||||
* - 在此状态中:可施放子架势技能(SubPose0~5),如御剑冲刺、御剑斩击
|
||||
* - 退出此状态时:飞剑消散,恢复地面移动速度
|
||||
* - 法力耗尽或受到重击时强制退出
|
||||
*/
|
||||
UCLASS(Blueprintable, BlueprintType)
|
||||
class RPGGAMEPLAYABILITY_API USwordFlyingActionPoseState : public USDHGAState
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
USwordFlyingActionPoseState();
|
||||
|
||||
// Begin USDHGAState
|
||||
virtual void OnEnterState(const FGameplayTagContainer& ContextTags) override;
|
||||
virtual void OnExitState(const FGameplayTagContainer& ContextTags) override;
|
||||
virtual void TickState(float DeltaTime) override;
|
||||
// End USDHGAState
|
||||
|
||||
// 御剑飞行专属 GameplayEffect(持续消耗法力、修改移动速度)
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "SwordFlying")
|
||||
TSubclassOf<class UGameplayEffect> SwordFlyingGE;
|
||||
|
||||
// 法力每秒消耗量
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "SwordFlying", meta = (ClampMin = "0"))
|
||||
float ManaCostPerSecond = 5.0f;
|
||||
|
||||
// 飞行移动速度倍率(基于基础 MoveSpeed)
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "SwordFlying", meta = (ClampMin = "1.0"))
|
||||
float FlightSpeedMultiplier = 1.5f;
|
||||
|
||||
// 受击时是否强制退出御剑
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "SwordFlying")
|
||||
bool bForceExitOnHit = true;
|
||||
|
||||
// 最小法力阈值(低于此值强制退出)
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "SwordFlying", meta = (ClampMin = "0"))
|
||||
float MinManaThreshold = 10.0f;
|
||||
|
||||
protected:
|
||||
// 进入时应用的 GE Handle(用于退出时移除)
|
||||
FActiveGameplayEffectHandle ActiveFlyingGEHandle;
|
||||
|
||||
// 检查是否满足持续飞行条件
|
||||
bool CanSustainFlying() const;
|
||||
|
||||
// 获取 OwningCharacter 的属性集
|
||||
class URPGAttributeSet* GetOwnerAttributeSet() const;
|
||||
};
|
||||
```
|
||||
|
||||
## 3.3 关键逻辑实现
|
||||
|
||||
```cpp
|
||||
// SwordFlyingActionPose.cpp
|
||||
#include "SwordFlyingActionPose.h"
|
||||
#include "Character/RPGCharacterBase.h"
|
||||
#include "Character/Attribute/RPGAttributeSet.h"
|
||||
#include "Abilities/RPGAbilitySystemComponent.h"
|
||||
#include "LogicStateMachine/SDHSkillStateMachine.h"
|
||||
|
||||
USwordFlyingActionPoseState::USwordFlyingActionPoseState()
|
||||
{
|
||||
ManaCostPerSecond = 5.0f;
|
||||
FlightSpeedMultiplier = 1.5f;
|
||||
bForceExitOnHit = true;
|
||||
MinManaThreshold = 10.0f;
|
||||
}
|
||||
|
||||
void USwordFlyingActionPoseState::OnEnterState(const FGameplayTagContainer& ContextTags)
|
||||
{
|
||||
Super::OnEnterState(ContextTags);
|
||||
|
||||
ARPGCharacterBase* Owner = Cast<ARPGCharacterBase>(GetOuterActor());
|
||||
if (!Owner) return;
|
||||
|
||||
URPGAbilitySystemComponent* ASC = Owner->GetRPGAbilitySystemComponent();
|
||||
URPGAttributeSet* AttrSet = GetOwnerAttributeSet();
|
||||
if (!ASC || !AttrSet) return;
|
||||
|
||||
// 1. 应用御剑飞行 GE(持续消耗法力 + 移动速度修改)
|
||||
if (SwordFlyingGE)
|
||||
{
|
||||
FGameplayEffectContextHandle Context = ASC->MakeEffectContext();
|
||||
FGameplayEffectSpecHandle Spec = ASC->MakeOutgoingSpec(SwordFlyingGE, 1.0f, Context);
|
||||
if (Spec.IsValid())
|
||||
{
|
||||
ActiveFlyingGEHandle = ASC->ApplyGameplayEffectSpecToSelf(*Spec.Data.Get());
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 标记角色进入御剑飞行状态
|
||||
AttrSet->RPGFlags.AddTag(FGameplayTag::RequestGameplayTag(TEXT("State.ActionPose.SwordFlying")));
|
||||
|
||||
// 3. 播放踩剑动画 / 飞剑视觉效果(此处接入动画蓝图和 Niagara)
|
||||
// Owner->PlayMontageSection(...);
|
||||
}
|
||||
|
||||
void USwordFlyingActionPoseState::OnExitState(const FGameplayTagContainer& ContextTags)
|
||||
{
|
||||
ARPGCharacterBase* Owner = Cast<ARPGCharacterBase>(GetOuterActor());
|
||||
if (!Owner) return;
|
||||
|
||||
URPGAbilitySystemComponent* ASC = Owner->GetRPGAbilitySystemComponent();
|
||||
URPGAttributeSet* AttrSet = GetOwnerAttributeSet();
|
||||
if (!ASC || !AttrSet) return;
|
||||
|
||||
// 1. 移除御剑飞行 GE
|
||||
if (ActiveFlyingGEHandle.IsValid())
|
||||
{
|
||||
ASC->RemoveActiveGameplayEffect(ActiveFlyingGEHandle);
|
||||
ActiveFlyingGEHandle = FActiveGameplayEffectHandle();
|
||||
}
|
||||
|
||||
// 2. 移除状态 Tag
|
||||
AttrSet->RPGFlags.RemoveTag(FGameplayTag::RequestGameplayTag(TEXT("State.ActionPose.SwordFlying")));
|
||||
|
||||
// 3. 恢复地面姿态 → GroundDefault
|
||||
USkillSMInstance* SkillSM = Owner->GetSkillSMInstance();
|
||||
if (SkillSM)
|
||||
{
|
||||
SkillSM->SetDynamicSkillByActionPose(
|
||||
SkillSM->GetDynamicSkillClassByActionPose(ELM_ActionPose::GroundDefault, ELM_SubActionPose::NotSubPose),
|
||||
ELM_ActionPose::GroundDefault,
|
||||
ELM_SubActionPose::NotSubPose
|
||||
);
|
||||
}
|
||||
|
||||
Super::OnExitState(ContextTags);
|
||||
}
|
||||
|
||||
void USwordFlyingActionPoseState::TickState(float DeltaTime)
|
||||
{
|
||||
Super::TickState(DeltaTime);
|
||||
|
||||
// 检查持续飞行条件
|
||||
if (!CanSustainFlying())
|
||||
{
|
||||
// 法力不足或生命值危险 → 强制退出
|
||||
USkillSMInstance* SkillSM = Cast<USkillSMInstance>(GetStateMachineInstance());
|
||||
if (SkillSM)
|
||||
{
|
||||
SkillSM->ConsumeCommandTransmitter(
|
||||
FGameplayTag::RequestGameplayTag(TEXT("SkillTransmitter.QuitState.ForceGround"))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool USwordFlyingActionPoseState::CanSustainFlying() const
|
||||
{
|
||||
URPGAttributeSet* AttrSet = GetOwnerAttributeSet();
|
||||
if (!AttrSet) return false;
|
||||
|
||||
// 法力不足
|
||||
if (AttrSet->GetMana() < MinManaThreshold) return false;
|
||||
|
||||
// 生命值过低
|
||||
if (AttrSet->GetHealth() <= 0.0f) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
URPGAttributeSet* USwordFlyingActionPoseState::GetOwnerAttributeSet() const
|
||||
{
|
||||
ARPGCharacterBase* Owner = Cast<ARPGCharacterBase>(GetOuterActor());
|
||||
if (!Owner) return nullptr;
|
||||
|
||||
URPGAbilitySystemComponent* ASC = Owner->GetRPGAbilitySystemComponent();
|
||||
if (!ASC) return nullptr;
|
||||
|
||||
return const_cast<URPGAttributeSet*>(
|
||||
ASC->GetSet<URPGAttributeSet>()
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## 3.4 注册到 ActionPoseTree
|
||||
|
||||
在 `SystemData.h:113-134` 的 `FRPGSkilllActionPoseTree` 中注册:
|
||||
|
||||
```cpp
|
||||
// 玩家学习御剑飞行技能时:
|
||||
ActionPoseTree.SetActionPoseSkillClass(
|
||||
FLMActionPose(ELM_ActionPose::AirSwordFlying, ELM_SubActionPose::NotSubPose),
|
||||
SwordFlyingSkillSMClass
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# 任务 4:「符修」技能效果系统设计 → GAS Effect 映射
|
||||
|
||||
## 4.1 符修核心机制回顾
|
||||
|
||||
来自 `修仙流派.md`:
|
||||
|
||||
- **符修定位**:将法术预先封存于符纸,战斗中瞬发不消耗灵力,但一次性使用
|
||||
- **加成流派**:魔修、鬼修、音修制符时产出 +20%
|
||||
- **道艺等级**:Lv.0~Lv.5(未入门→登峰造极),Lv.3+ 生效流派加成
|
||||
- **产出**:攻击符、防御符、遁术符、控制符、召唤符
|
||||
|
||||
## 4.2 符箓类型 → GAS Effect 映射
|
||||
|
||||
### 类型 A:攻击符(Instant GameplayEffect)
|
||||
|
||||
```
|
||||
攻击符 = UGameplayEffect (DurationPolicy = Instant)
|
||||
├── Modifiers:
|
||||
│ ├── Attribute = RPGAttributeSet.Damage (Magnitude = SetByCaller, Tag = "Data.Talisman.Damage")
|
||||
│ └── Execution = URPGDamageExecution (复用现有伤害结算)
|
||||
├── SetByCaller Magnitudes:
|
||||
│ ├── Data.Damage.Base = 符纸基础伤害
|
||||
│ ├── Data.Damage.Bonus = 符修加成百分比
|
||||
│ └── Data.Damage.Tough = 韧性伤害
|
||||
└── GameplayTags:
|
||||
├── GrantedTags: Effect.Damage.Talisman
|
||||
└── AssetTags: SkillType.Talisman.Attack
|
||||
```
|
||||
|
||||
### 类型 B:防御符(Duration GameplayEffect — 有限时间 Buff)
|
||||
|
||||
```
|
||||
防御符 = UGameplayEffect (DurationPolicy = HasDuration, Duration = 符纸时长)
|
||||
├── Modifiers:
|
||||
│ ├── Attribute = RPGAttributeSet.Shield (ModifierOp = Additive, 护盾值增加)
|
||||
│ ├── Attribute = RPGAttributeSet.DefensePower (ModifierOp = Multiplicitive, 防御力+%)
|
||||
│ └── Attribute = RPGAttributeSet.BlockRate (ModifierOp = Additive, 格挡率+N%)
|
||||
└── GameplayTags:
|
||||
├── GrantedTags: State.Buff.Talisman.Defense
|
||||
└── AssetTags: SkillType.Talisman.Defense
|
||||
```
|
||||
|
||||
### 类型 C:遁术符(Instant + Duration 混合)
|
||||
|
||||
```
|
||||
遁术符 = 两段式:
|
||||
1) Instant GE: 瞬移(位置修改,走 GameplayCue 或直接 SetActorLocation)
|
||||
2) Duration GE: 移速加成 + 闪避率提升(持续 N 秒)
|
||||
├── Modifiers:
|
||||
│ ├── Attribute = RPGAttributeSet.MoveSpeed (Multiplicitive, +x%)
|
||||
│ └── Attribute = RPGAttributeSet.DodgeRate (Additive, +y%)
|
||||
└── Tags: State.Buff.Talisman.Escape
|
||||
```
|
||||
|
||||
### 类型 D:控制符(Duration GameplayEffect — 施加于目标)
|
||||
|
||||
```
|
||||
控制符 = UGameplayEffect (DurationPolicy = HasDuration, 施加于 Enemy ASC)
|
||||
├── Modifiers:
|
||||
│ ├── Attribute = RPGAttributeSet.MoveSpeed (Multiplicitive, -x%, 减速)
|
||||
│ └── Attribute = RPGAttributeSet.AttackPower (Multiplicitive, -y%, 降攻)
|
||||
└── GameplayTags:
|
||||
├── GrantedTags: State.Debuff.Talisman.Snare (定身/减速)
|
||||
└── AssetTags: SkillType.Talisman.Control
|
||||
```
|
||||
|
||||
### 类型 E:召唤符(Infinite Duration GameplayEffect)
|
||||
|
||||
```
|
||||
召唤符 = UGameplayEffect (DurationPolicy = Infinite)
|
||||
├── 触发 GameplayCue → 生成召唤物 Actor
|
||||
├── Granted Abilities: 召唤物专属技能(如傀儡自动攻击)
|
||||
└── Tags: State.Buff.Talisman.Summon
|
||||
```
|
||||
|
||||
## 4.3 符箓消耗机制
|
||||
|
||||
符箓作为一种**可消耗物品**而非技能冷却资源:
|
||||
|
||||
```cpp
|
||||
// FTalismanItemData — 符箓道具数据结构
|
||||
USTRUCT(BlueprintType)
|
||||
struct FTalismanItemData
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
// 符箓等级(对应道艺等级 Lv.1~5)
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
int32 TalismanLevel = 1;
|
||||
|
||||
// 对应的 GameplayEffect Class
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
TSubclassOf<UGameplayEffect> EffectClass;
|
||||
|
||||
// 符箓所属大道属性(决定伤害/效果类型标签)
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
ERPGElementType DaoElement = ERPGElementType::SRT_Fire;
|
||||
|
||||
// 使用符箓 → ApplyGameplayEffectToTarget/Self → 从背包移除 1 张 → 触发 OnTalismanUsed
|
||||
};
|
||||
```
|
||||
|
||||
**关键设计差异**:符箓不是通过 GAS Ability 释放,而是通过**物品系统 Apply Effect**——这确保了"不消耗灵力"的设计意图,因为 `UGameplayEffect` 的 `Cost` 策略可以为空。
|
||||
|
||||
## 4.4 符修专属 GameplayTag 体系
|
||||
|
||||
```
|
||||
SkillType.Talisman.Attack // 攻击符
|
||||
SkillType.Talisman.Defense // 防御符
|
||||
SkillType.Talisman.Escape // 遁术符
|
||||
SkillType.Talisman.Control // 控制符
|
||||
SkillType.Talisman.Summon // 召唤符
|
||||
|
||||
Effect.Damage.Talisman // 符箓伤害来源标记
|
||||
State.Buff.Talisman.Defense // 符箓防御 Buff
|
||||
State.Buff.Talisman.Escape // 符箓遁术 Buff (MoveSpeed/Dodge)
|
||||
State.Debuff.Talisman.Snare // 符箓减速 Debuff
|
||||
State.Buff.Talisman.Summon // 符箓召唤 Buff
|
||||
|
||||
DaoElement.Fire.Talisman // 火系符箓
|
||||
DaoElement.Water.Talisman // 水系符箓
|
||||
// ... 按大道属性细分
|
||||
|
||||
Profession.Talisman.Specialist // 符修身份标签(挂载到 RPGFlags)
|
||||
```
|
||||
|
||||
## 4.5 属性映射汇总
|
||||
|
||||
| 符修机制 | GAS 组件 | 涉及属性 |
|
||||
|---------|---------|---------|
|
||||
| 攻击符 | `Instant GE` + `URPGDamageExecution` | Damage, AttackPowerMin/Max, FatalRate, ElementFire... |
|
||||
| 防御符 | `Duration GE` | Shield, DefensePower, BlockRate |
|
||||
| 遁术符 | `Instant GE` (位移) + `Duration GE` | MoveSpeed, DodgeRate |
|
||||
| 控制符 | `Duration GE` (施加目标) | MoveSpeed (减益), AttackPower (减益) |
|
||||
| 召唤符 | `Infinite GE` + `GameplayCue` | — (生成 Actor) |
|
||||
| 符纸消耗 | 物品系统 `URPGItemDataAsset` | — (从背包移除) |
|
||||
| 制符加成 | `CraftingSkillData` + Modifier | 产出数量 ×1.2(流派加成) |
|
||||
| 符修身份 | `RPGFlags` GameplayTag | `Profession.Talisman.Specialist` |
|
||||
|
||||
**核心洞察**:符修的 GAS 映射极简——不需要自定义 `ExecutionCalculation`,不需要新建 `AttributeSet`,不需要修改 `SDHGameplayAbility`。它完全依赖现有的 `UGameplayEffect` + `GameplayTag` + 物品系统三层即可实现,是十个修仙流派中与现有 GAS 架构耦合度最低的一个。
|
||||
|
||||
---
|
||||
|
||||
# 附录:项目关键文件索引
|
||||
|
||||
## 架构文档
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `.trae/documents/02_程序架构/spec.md` | 总体架构(表现层/游戏逻辑/核心框架/引擎) |
|
||||
| `.trae/documents/02_程序架构/spec_modules.md` | 模块详细规格 |
|
||||
| `.trae/specs/LivingWorldSystem/spec.md` | LivingWorld 系统完整规格 |
|
||||
|
||||
## NPC 系统
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `.trae/documents/01_策划设计/NPC系统与势力/NPC系统设计.md` | NPC 模拟系统完整设计 |
|
||||
| `Plugins/RPGGameCore/Source/LivingWorldSystem/Public/LWSNpcTypes.h` | NPC 数据结构(FLWSNpcData) |
|
||||
| `Plugins/RPGGameCore/Source/LivingWorldSystem/Public/LWSNpcPersonalityTypes.h` | 性格/目标/秘密/Need/Action 定义 |
|
||||
| `Plugins/RPGGameCore/Source/LivingWorldSystem/Public/LWSNpcSimulationSubsystem.h` | 模拟主循环 |
|
||||
| `Plugins/RPGGameCore/Source/LivingWorldSystem/Public/LWSNpcDecisionSystem.h` | 决策系统(Utility AI) |
|
||||
| `Plugins/RPGGameCore/Source/LivingWorldSystem/Public/LWSNpcRelationSubsystem.h` | 关系网络 |
|
||||
|
||||
## GAS / 属性系统
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `Plugins/RPGGameCore/Source/RPGGameplayAbility/Public/Character/Attribute/RPGAttributeSet.h` | 单一属性容器(5子集) |
|
||||
| `Plugins/RPGGameCore/Source/RPGGameplayAbility/Public/Character/Attribute/RPGAttributeData.h` | ERPGPhase 境界枚举、灵根 |
|
||||
| `Plugins/RPGGameCore/Source/RPGGameplayAbility/Public/Config/RPGDamageExecution.h` | GAS 伤害结算 |
|
||||
| `Plugins/RPGGameCore/Source/RPGGameplayAbility/Public/Abilities/SDHGameplayAbility.h` | 技能基类 |
|
||||
|
||||
## ActionPose / 技能系统
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `Plugins/RPGGameCore/Source/RPGGameplayAbility/Public/RPGTypes.h` | ELM_ActionPose 枚举、FLMActionPose |
|
||||
| `Plugins/RPGGameCore/Source/RPGGameplayAbility/Public/System/SystemData.h` | FRPGSkilllActionPoseTree |
|
||||
| `Plugins/RPGGameCore/Source/RPGGameplayAbility/Public/LogicStateMachine/SDHSkillStateMachine.h` | 技能状态机 |
|
||||
|
||||
## 修仙设计文档
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `.trae/documents/01_策划设计/修仙基础概念设定/修仙概念体系.md` | 流派/道艺/大道属性三层体系 |
|
||||
| `.trae/documents/01_策划设计/修仙基础概念设定/修仙流派.md` | 十大流派详细设计 |
|
||||
| `.trae/documents/01_策划设计/修仙基础概念设定/大道元素属性.md` | 37种大道属性 |
|
||||
@@ -0,0 +1,814 @@
|
||||
# AIDM 项目测试分析报告
|
||||
|
||||
> 生成日期:2026-05-30
|
||||
> 项目:D:\MatrixTA\AIGameDev\AIDM
|
||||
> 基于:LivingWorldSystem Spec、ARPGGameDevelopment Research Report、修仙流派设计文档
|
||||
|
||||
---
|
||||
|
||||
[TOC]
|
||||
|
||||
---
|
||||
|
||||
## 任务 1:NPC 系统完整架构
|
||||
|
||||
### 一、分级机制
|
||||
|
||||
项目采用 **三层 NPC 分级模型**(来自 `rationale_npc_tier_abc` 超边):
|
||||
|
||||
| 级别 | 名称 | 特征 | 数据承载 |
|
||||
|------|------|------|----------|
|
||||
| **A 级** | 核心 NPC(玩家、重要角色) | 完整 3D Actor、行为树、动画、GAS 属性 | `ARPGCharacterBase` + `URPGAbilitySystemComponent` |
|
||||
| **B 级** | 势力 NPC(宗门弟子、城镇守卫) | 轻量 Actor + 基础动画,结合纯数据模拟 | `ARPGAICharacter` + 部分 `FLWSNpcData` 字段 |
|
||||
| **C 级** | 泛 NPC(平民、路人、妖兽) | **纯数据 USTRUCT**,无 Actor,不走 NavMesh,六边形坐标跳转 | `FLWSNpcData`(位于 `LWSNpcTypes.h`) |
|
||||
|
||||
分级依据文档 `00_项目总控/游戏核心创意.md` 中的"NPC锚点和分级"概念,结合 `LivingWorldSystem Spec` 中明确的"NPC 纯数据模拟"策略。
|
||||
|
||||
### 二、决策模型
|
||||
|
||||
**核心架构:Utility AI + 性格权重 + 目标驱动**
|
||||
|
||||
```
|
||||
每个 NPC 每日 Tick:
|
||||
┌────────────────────────────────────────────┐
|
||||
│ ULWSNpcSimulationSubsystem (UWorldSubsystem) │
|
||||
│ ├─ 订阅 URPGGameTimeSubsystem::OnGameTimeChanged │
|
||||
│ ├─ SimulateDays(DeltaDays) │
|
||||
│ └─ 每日遍历 ActiveNpcs │
|
||||
└──────────────┬─────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌────────────────────────────────────────────┐
|
||||
│ ULWSNpcDecisionSystem (决策引擎) │
|
||||
│ ├─ DecayNeeds() — 需求自然衰减(生存↑/安全↑/社交↑...) │
|
||||
│ ├─ ScoreAction() — 对所有可能行为打分 │
|
||||
│ │ ├─ 当前需求值 × 行为匹配度 │
|
||||
│ │ └─ 性格权重因子 PersonalityFactor │
|
||||
│ └─ ApplyActionToBehavior() — 选最高分执行 │
|
||||
└──────────────┬─────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
ELWSNpcAction { Idle, Wander, MoveTo, Trade, Fight, Socialize, Cultivate, ... }
|
||||
```
|
||||
|
||||
**性格三维度**(`FLWSNpcPersonality`,位于 `LWSNpcPersonalityTypes.h`):
|
||||
|
||||
- **冷 ↔ 热**:影响社交行为权重
|
||||
- **慎 ↔ 莽**:影响战斗/探索行为权重
|
||||
- **私 ↔ 义**:影响帮助盟友 vs 追求私利
|
||||
|
||||
**需求六维度**(`ELWSNpcNeed`):生存、安全、社交、权力、资源、修炼
|
||||
|
||||
**决策实现位置**:
|
||||
|
||||
- `Plugins/RPGGameCore/Source/LivingWorldSystem/Public/LWSNpcDecisionSystem.h`
|
||||
- `Plugins/RPGGameCore/Source/LivingWorldSystem/Private/LWSNpcDecisionSystem.cpp`
|
||||
|
||||
### 三、与时间系统的关系
|
||||
|
||||
**时间模型:回合+实时混合制,日为原子单位**(Community 15:策划世界系统)
|
||||
|
||||
```
|
||||
URPGGameTimeSubsystem (UGameInstanceSubsystem,跨 World 持续)
|
||||
│
|
||||
├─ FSDHGameRawTime / FSDHGameTime (30天/月, 12月/年)
|
||||
├─ OnGameTimeChanged 委托广播
|
||||
├─ 世界时间推进 → AddGameTime(DeltaDays)
|
||||
│
|
||||
└──→ ULWSNpcSimulationSubsystem::SimulateDays(DeltaDays)
|
||||
├─ 每日遍历所有 NPC
|
||||
├─ Wander 算法(WanderStayProbability 概率不动,否则随机六邻一步)
|
||||
├─ 调用决策系统 DecideAction
|
||||
└─ 缓存轨迹(环形 buffer 32 步)
|
||||
```
|
||||
|
||||
**关键时间常量**:
|
||||
|
||||
- 1 日 = 最小原子单位
|
||||
- 2 帧完成一轮完整 NPC 模拟(60 FPS 下每帧处理 1/30 NPC)
|
||||
- NPC 模拟在**后台线程**批量执行
|
||||
|
||||
### 四、存档方式
|
||||
|
||||
**双层存档架构**(Community 5 + Community 15):
|
||||
|
||||
```
|
||||
第一层:世界永久层(跨存档持久化)
|
||||
│
|
||||
├─ LWSWorldSaveGame (USaveGame 子类)
|
||||
│ ├─ CachedTileCoords / TileBuffer → 瓦片数据
|
||||
│ ├─ CachedRivers / CachedLakes → 水文数据
|
||||
│ ├─ CachedFactions → 势力数据
|
||||
│ ├─ CachedNpcs → NPC 数据 (TArray<FLWSNpcData>)
|
||||
│ ├─ CachedSpiritualVeins → 灵脉数据
|
||||
│ └─ CachedSettlements / Resources → 聚落/资源数据
|
||||
│
|
||||
└─ 世界编年史(跨存档的人生记录,待阶段二实现)
|
||||
|
||||
第二层:角色存档层(可删除/重建)
|
||||
│
|
||||
└─ URPGPlayerSaveGame
|
||||
├─ RPGAttributeData → FRPGCharacterAttributeData
|
||||
├─ SkillTreeDataPool → 技能树学习状态
|
||||
├─ RPGSkilllActionPoseTree → 架势-技能装配绑定
|
||||
├─ RPGItemDataMap → 物品容器数据
|
||||
└─ TalentComponentSaveData → 天赋数据
|
||||
```
|
||||
|
||||
**存档关键实现**:
|
||||
|
||||
- `ALWSWorldGenerator::SaveWorld()` 写入 `ULWSWorldSaveGame`(蓝图可调用)
|
||||
- `ALWSWorldGenerator::LoadWorld()` 从存档完整还原世界
|
||||
- NPC 数据通过 `ULWSNpcSimulationSubsystem::GetActiveNpcsCopy()` / `RestoreNpcsFromSave()` 同步
|
||||
- **角色存档删除后,世界永久层不受影响**——势力变迁、NPC 死亡/成长、资源消耗写入世界层
|
||||
|
||||
---
|
||||
|
||||
## 任务 2:新增「商队 NPC」跨系统依赖分析
|
||||
|
||||
### 一、需要修改的模块及文件
|
||||
|
||||
#### 1. NPC 数据结构层(核心修改)
|
||||
|
||||
| 文件 | 修改内容 |
|
||||
|------|---------|
|
||||
| `Plugins/RPGGameCore/Source/LivingWorldSystem/Public/LWSNpcTypes.h` | `FLWSNpcData` 新增字段:`TradeRouteIndex`(商队路线 ID)、`TradeGoods`(货物数组 TMap)、`TradeFactionOrigin`/`TradeFactionDestination`(起止势力)、`TradeSpeed`(行进速度,单位 hex/日) |
|
||||
| `Plugins/RPGGameCore/Source/LivingWorldSystem/Public/LWSNpcPersonalityTypes.h` | 新增 `ELWSNpcBehavior::Trade` 行为枚举值;新增 `ELWSNpcRole::CaravanTrader` 角色类型 |
|
||||
|
||||
#### 2. 行为/决策系统
|
||||
|
||||
| 文件 | 修改内容 |
|
||||
|------|---------|
|
||||
| `Plugins/RPGGameCore/Source/LivingWorldSystem/Public/LWSNpcDecisionSystem.h` | `DecideAction()` 新增商队逻辑:到达目的地时触发交易结算、反向切换目的地 |
|
||||
| `Plugins/RPGGameCore/Source/LivingWorldSystem/Private/LWSNpcDecisionSystem.cpp` | 实现 `ScoreAction_Trade()`:需求权重(资源需求×商队距离评分) |
|
||||
| `Plugins/RPGGameCore/Source/LivingWorldSystem/Public/LWSNpcSimulationSubsystem.h` | `SimulateDays()` 新增商队每日推进:沿 A* 路径逐格移动(有别于 Wander 随机) |
|
||||
|
||||
#### 3. 势力与生成
|
||||
|
||||
| 文件 | 修改内容 |
|
||||
|------|---------|
|
||||
| `Plugins/RPGGameCore/Source/LivingWorldSystem/Public/LWSNpcGenerator.h/.cpp` | `GenerateNpcs()` 新增商队生成逻辑:势力边界间配对生成商队 NPC,泊松碟约束 + 路线预计算 |
|
||||
| `Plugins/RPGGameCore/Source/LivingWorldSystem/Public/LWSFactionTypes.h` | `FLWSFaction` 新增 `TradePartners`(贸易伙伴势力 ID 列表)、`TradeRouteFrequencies`(每条路线商队生成频率) |
|
||||
| `Plugins/RPGGameCore/Source/LivingWorldSystem/Private/LWSFactionGenerator.cpp` | 势力生成后自动配对邻近势力建立贸易路线 |
|
||||
|
||||
#### 4. 寻路系统
|
||||
|
||||
| 文件 | 修改内容 |
|
||||
|------|---------|
|
||||
| `Plugins/RPGGameCore/Source/LivingWorldSystem/Public/LWSPathfinder.h` | 商队寻路需在 `FLWSPathfindingParams` 中支持路线成本(避开高危势力区、倾向道路/平原) |
|
||||
|
||||
#### 5. 存档
|
||||
|
||||
| 文件 | 修改内容 |
|
||||
|------|---------|
|
||||
| `Plugins/RPGGameCore/Source/LivingWorldSystem/Public/LWSWorldSaveGame.h` | `FLWSNpcData` 新增字段会自然序列化;新增 `CachedTradeRoutes`(`TArray<FLWSTradeRoute>` 路线拓扑数据) |
|
||||
| `Plugins/RPGGameCore/Source/LivingWorldSystem/Public/LWSTradeTypes.h` | **新建**:`FLWSTradeGoods`(物品 ID + 数量)、`FLWSTradeRoute`(起始势力、途经 hex 坐标数组、路线等级) |
|
||||
|
||||
#### 6. 调试可视化
|
||||
|
||||
| 文件 | 修改内容 |
|
||||
|------|---------|
|
||||
| `Plugins/RPGGameCore/Source/LivingWorldSystem/Private/LWSWorldGenerator.cpp` | 新增 `DebugDrawTradeRoutes()`:商队路线以黄色虚线绘制;商队位置以金色圆点标记 |
|
||||
| `Plugins/RPGGameCore/Source/LivingWorldSystem/Public/LWSResourceTypes.h` | `ELWSDebugViewMode` 新增 `TradeRoutes` 枚举 |
|
||||
|
||||
### 二、存档结构变化
|
||||
|
||||
**不需要破坏性变更**。`FLWSNpcData` 的字段扩展会被 UE 序列化自动兼容(USTRUCT 标记 UPROPERTY 的字段)。需要新增:
|
||||
|
||||
```cpp
|
||||
// 新建 LWSTradeTypes.h
|
||||
USTRUCT()
|
||||
struct FLWSTradeRoute
|
||||
{
|
||||
UPROPERTY() int32 RouteId;
|
||||
UPROPERTY() int32 OriginFactionId;
|
||||
UPROPERTY() int32 DestinationFactionId;
|
||||
UPROPERTY() TArray<FLWSAxialCoord> Waypoints; // A* 预计算路径
|
||||
UPROPERTY() float RouteLevel; // 路线等级(影响货物品质)
|
||||
};
|
||||
|
||||
// LWSWorldSaveGame 新增
|
||||
UPROPERTY() TArray<FLWSTradeRoute> CachedTradeRoutes;
|
||||
```
|
||||
|
||||
**双层存档不受影响**:商队 NPC 属于 `CachedNpcs`(世界永久层),角色存档删除不影响商队。
|
||||
|
||||
### 三、对 GAS 属性系统的影响
|
||||
|
||||
**不影响 GAS 属性系统。** 原因:
|
||||
|
||||
1. 商队 NPC 是**纯数据 C 级 NPC**(`FLWSNpcData`),不持有 `URPGAbilitySystemComponent`,不参与 GAS Attribute 同步
|
||||
2. 商队交易结算是**数值运算**(货物价值 = 距离 × 势力稀缺度 × 路线等级),不涉及战斗伤害管线
|
||||
3. 如果未来需要"商队被劫掠"战斗,才需要通过 C→B 级 NPC 升级机制接入 GAS
|
||||
|
||||
---
|
||||
|
||||
## 任务 3:为「御剑飞行」新增 ActionPose
|
||||
|
||||
### 设计分析
|
||||
|
||||
当前 `ELM_ActionPose` 已有 `AirFlying`(空行)作为通用空中飞行态,但**御剑飞行**是剑修专属的战斗力+移动融合态:站在飞剑上高速移动,可在飞行中发起剑技攻击。需要作为独立主架势加入。
|
||||
|
||||
**状态流转:**
|
||||
|
||||
```
|
||||
地面起势 (GroundDefault)
|
||||
│ 释放御剑飞行技能
|
||||
▼
|
||||
御剑飞行 (AirSwordFlight) ← 新增
|
||||
│
|
||||
├── 输入方向 → 高速移动(飞行移动速度 ×2.5)
|
||||
├── 左键 (SubPose0) → 飞剑斩(空中剑技连段)
|
||||
├── 右键 (SubPose1) → 剑罡护体
|
||||
├── 闪避键 → 御剑急转 (AirSwordFlight → AirDash)
|
||||
│
|
||||
├── 耐力耗尽/被击落 → AirFalling
|
||||
└── 主动取消/落地 → GroundLanding
|
||||
```
|
||||
|
||||
### 1. RPGTypes.h — 新增枚举值
|
||||
|
||||
```cpp
|
||||
// RPGTypes.h — 在 ELM_ActionPose 枚举中 AirDash 之后插入
|
||||
enum class ELM_ActionPose : uint8
|
||||
{
|
||||
// ... 现有值不变 ...
|
||||
AirDash, // 空冲(飞行状态下的快速冲击)
|
||||
|
||||
// === 御剑飞行(新增)===
|
||||
AirSwordFlight, // 御剑飞行态:剑修站在飞剑上高速移动+空中战斗
|
||||
|
||||
AirSpring, // 空遁
|
||||
// ... 后续值不变 ...
|
||||
};
|
||||
```
|
||||
|
||||
### 2. RPGSwordFlightAbility.h — 御剑飞行 GA 头文件(新建)
|
||||
|
||||
```cpp
|
||||
// Plugins/RPGGameCore/Source/RPGGameplayAbility/Public/Abilities/RPGSwordFlightAbility.h
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SDHGameplayAbility.h"
|
||||
#include "GameplayTagContainer.h"
|
||||
#include "RPGSwordFlightAbility.generated.h"
|
||||
|
||||
class AWeaponBase;
|
||||
class UNiagaraSystem;
|
||||
class UGameplayEffect;
|
||||
|
||||
/**
|
||||
* 御剑飞行 GameplayAbility
|
||||
* Lifecycle: ActivateAbility → UpdateAbility(每帧) → EndAbility
|
||||
* 角色站在飞剑上进入 AirSwordFlight 架势,高速飞行 + 空中剑技
|
||||
*/
|
||||
UCLASS(BlueprintType, Blueprintable)
|
||||
class RPGGAMEPLAYABILITY_API URPGSwordFlightAbility : public URPGGameplayAbility
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
URPGSwordFlightAbility();
|
||||
|
||||
virtual void ActivateAbility() override;
|
||||
virtual void UpdateAbility(float DeltaTime) override;
|
||||
virtual void EndAbility() override;
|
||||
|
||||
// === 配置属性 ===
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "SwordFlight|Movement")
|
||||
float FlightSpeed = 2000.f; // 基础飞行速度 (cm/s)
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "SwordFlight|Movement")
|
||||
float MaxAcceleration = 3000.f; // 最大加速度
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "SwordFlight|Movement")
|
||||
float TurnRate = 180.f; // 转向速率 (deg/s)
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "SwordFlight|Resource")
|
||||
float ManaDrainPerSecond = 8.f; // 每秒法力消耗
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "SwordFlight|Resource")
|
||||
float MinManaToActivate = 30.f; // 最低法力阈值(低于此值强制解除)
|
||||
|
||||
// === 视觉 ===
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "SwordFlight|Visual")
|
||||
TSubclassOf<AActor> SwordFlightActorClass; // 飞剑 Actor(附着到角色脚下)
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "SwordFlight|Visual")
|
||||
UNiagaraSystem* FlightTrailEffect; // 飞行拖尾 Niagara 特效
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "SwordFlight|Visual")
|
||||
FRotator SwordMountRotation = FRotator(0.f, 0.f, 15.f); // 飞剑倾斜角度
|
||||
|
||||
// === GAS Effect ===
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "SwordFlight|Effects")
|
||||
TSubclassOf<UGameplayEffect> SwordFlightMovementGE; // 修改 MoveSpeed、GravityScale
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "SwordFlight|Effects")
|
||||
TSubclassOf<UGameplayEffect> SwordFlightDamageBonusGE; // 飞剑期间剑技伤害 +25%
|
||||
|
||||
// === 蓝图事件 ===
|
||||
UFUNCTION(BlueprintImplementableEvent, Category = "SwordFlight")
|
||||
void OnSwordMounted(AActor* SwordActor);
|
||||
|
||||
UFUNCTION(BlueprintImplementableEvent, Category = "SwordFlight")
|
||||
void OnSwordDismounted();
|
||||
|
||||
UFUNCTION(BlueprintImplementableEvent, Category = "SwordFlight")
|
||||
void OnFlightManaDepleted(); // 法力耗尽事件
|
||||
|
||||
private:
|
||||
// === 内部状态 ===
|
||||
UPROPERTY()
|
||||
TObjectPtr<AActor> MountedSword; // 当前挂载的飞剑 Actor
|
||||
|
||||
UPROPERTY()
|
||||
TObjectPtr<UNiagaraComponent> TrailNiagara; // 拖尾特效组件
|
||||
|
||||
UPROPERTY()
|
||||
FActiveGameplayEffectHandle MovementGEHandle; // 移动 GE 句柄
|
||||
|
||||
UPROPERTY()
|
||||
FActiveGameplayEffectHandle DamageBonusHandle; // 伤害加成 GE 句柄
|
||||
|
||||
bool bIsActive = false;
|
||||
float CurrentManaDrainAccum = 0.f; // 法力消耗累加器
|
||||
|
||||
// --- 内部方法 ---
|
||||
void SpawnAndMountSword();
|
||||
void ApplyFlightEffects();
|
||||
void RemoveFlightEffects();
|
||||
bool CheckManaSufficient() const;
|
||||
void DrainManaPerTick(float DeltaTime);
|
||||
};
|
||||
```
|
||||
|
||||
### 3. RPGSwordFlightAbility.cpp — 关键逻辑实现(核心)
|
||||
|
||||
```cpp
|
||||
// Plugins/RPGGameCore/Source/RPGGameplayAbility/Private/Abilities/RPGSwordFlightAbility.cpp
|
||||
|
||||
#include "Abilities/RPGSwordFlightAbility.h"
|
||||
#include "Character/RPGCharacterBase.h"
|
||||
#include "Character/Attribute/RPGAttributeSet.h"
|
||||
#include "Character/Attribute/RPGAttributeComponent.h"
|
||||
#include "NiagaraComponent.h"
|
||||
#include "NiagaraFunctionLibrary.h"
|
||||
#include "GameFramework/CharacterMovementComponent.h"
|
||||
#include "AbilitySystemComponent.h"
|
||||
|
||||
URPGSwordFlightAbility::URPGSwordFlightAbility()
|
||||
{
|
||||
// 标记为持续型 Ability(非一次性瞬发)
|
||||
}
|
||||
|
||||
void URPGSwordFlightAbility::ActivateAbility()
|
||||
{
|
||||
Super::ActivateAbility();
|
||||
|
||||
ARPGCharacterBase* Owner = Cast<ARPGCharacterBase>(GetSkillUser());
|
||||
if (!Owner || !CheckManaSufficient())
|
||||
{
|
||||
SetAbilityValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. 生成飞剑并挂载到角色脚底
|
||||
SpawnAndMountSword();
|
||||
|
||||
// 2. 应用飞行 GE(修改 CMC MoveSpeed、GravityScale)
|
||||
ApplyFlightEffects();
|
||||
|
||||
// 3. 角色进入飞行模式
|
||||
if (UCharacterMovementComponent* CMC = Owner->GetCharacterMovement())
|
||||
{
|
||||
CMC->SetMovementMode(MOVE_Flying);
|
||||
CMC->MaxFlySpeed = FlightSpeed;
|
||||
CMC->MaxAcceleration = MaxAcceleration;
|
||||
CMC->BrakingDecelerationFlying = 1000.f;
|
||||
}
|
||||
|
||||
// 4. 设置架势为 御剑飞行
|
||||
if (USkillSMInstance* SM = Owner->GetSkillSMInstance())
|
||||
{
|
||||
SM->SetActionPose(ELM_ActionPose::AirSwordFlight);
|
||||
}
|
||||
|
||||
// 5. 生成长剑拖尾特效
|
||||
if (FlightTrailEffect)
|
||||
{
|
||||
TrailNiagara = UNiagaraFunctionLibrary::SpawnSystemAttached(
|
||||
FlightTrailEffect,
|
||||
Owner->GetRootComponent(),
|
||||
NAME_None,
|
||||
FVector::ZeroVector,
|
||||
FRotator::ZeroRotator,
|
||||
EAttachLocation::KeepRelativeOffset,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
bIsActive = true;
|
||||
SetAbilityValid(true);
|
||||
}
|
||||
|
||||
void URPGSwordFlightAbility::UpdateAbility(float DeltaTime)
|
||||
{
|
||||
Super::UpdateAbility(DeltaTime);
|
||||
if (!bIsActive) return;
|
||||
|
||||
// 法力消耗检查
|
||||
DrainManaPerTick(DeltaTime);
|
||||
if (!CheckManaSufficient())
|
||||
{
|
||||
OnFlightManaDepleted();
|
||||
EndAbility();
|
||||
return;
|
||||
}
|
||||
|
||||
// 可选:根据输入方向调整飞剑倾斜
|
||||
// 通过蓝图 OnFlightUpdate 事件暴露给设计师微调
|
||||
}
|
||||
|
||||
void URPGSwordFlightAbility::EndAbility()
|
||||
{
|
||||
Super::EndAbility();
|
||||
|
||||
ARPGCharacterBase* Owner = Cast<ARPGCharacterBase>(GetSkillUser());
|
||||
if (!Owner) return;
|
||||
|
||||
// 1. 恢复地面移动模式
|
||||
if (UCharacterMovementComponent* CMC = Owner->GetCharacterMovement())
|
||||
{
|
||||
CMC->SetMovementMode(MOVE_Walking);
|
||||
CMC->MaxFlySpeed = 600.f; // 恢复默认
|
||||
}
|
||||
|
||||
// 2. 移除 GE
|
||||
RemoveFlightEffects();
|
||||
|
||||
// 3. 销毁拖尾
|
||||
if (TrailNiagara)
|
||||
{
|
||||
TrailNiagara->Deactivate();
|
||||
TrailNiagara = nullptr;
|
||||
}
|
||||
|
||||
// 4. 拆卸飞剑 → 切换到 AirFalling
|
||||
OnSwordDismounted();
|
||||
if (MountedSword)
|
||||
{
|
||||
MountedSword->Destroy();
|
||||
MountedSword = nullptr;
|
||||
}
|
||||
|
||||
// 5. 架势切换:御剑 → 空中下落
|
||||
if (USkillSMInstance* SM = Owner->GetSkillSMInstance())
|
||||
{
|
||||
SM->SetActionPose(ELM_ActionPose::AirFalling);
|
||||
}
|
||||
|
||||
bIsActive = false;
|
||||
}
|
||||
|
||||
// ============ 内部实现 ============
|
||||
|
||||
void URPGSwordFlightAbility::SpawnAndMountSword()
|
||||
{
|
||||
ARPGCharacterBase* Owner = Cast<ARPGCharacterBase>(GetSkillUser());
|
||||
if (!Owner || !SwordFlightActorClass) return;
|
||||
|
||||
FActorSpawnParameters SpawnParams;
|
||||
SpawnParams.Owner = Owner;
|
||||
SpawnParams.Instigator = Owner;
|
||||
|
||||
// 飞剑生成在角色脚下
|
||||
FVector SpawnLoc = Owner->GetActorLocation() + FVector(0, 0, -70.f);
|
||||
MountedSword = GetWorld()->SpawnActor<AActor>(
|
||||
SwordFlightActorClass, SpawnLoc, FRotator::ZeroRotator, SpawnParams
|
||||
);
|
||||
|
||||
if (MountedSword)
|
||||
{
|
||||
MountedSword->AttachToComponent(
|
||||
Owner->GetRootComponent(),
|
||||
FAttachmentTransformRules::KeepRelativeTransform
|
||||
);
|
||||
MountedSword->SetActorRelativeLocation(FVector(0, 0, -70.f));
|
||||
MountedSword->SetActorRelativeRotation(SwordMountRotation);
|
||||
OnSwordMounted(MountedSword);
|
||||
}
|
||||
}
|
||||
|
||||
void URPGSwordFlightAbility::ApplyFlightEffects()
|
||||
{
|
||||
ARPGCharacterBase* Owner = Cast<ARPGCharacterBase>(GetSkillUser());
|
||||
if (!Owner) return;
|
||||
|
||||
URPGAbilitySystemComponent* ASC = Owner->GetRPGAbilitySystemComponent();
|
||||
if (!ASC) return;
|
||||
|
||||
// 施加飞行移动 GE
|
||||
if (SwordFlightMovementGE)
|
||||
{
|
||||
MovementGEHandle = ASC->ApplyGameplayEffectToSelf(
|
||||
SwordFlightMovementGE->GetDefaultObject<UGameplayEffect>(),
|
||||
1.f, ASC->MakeEffectContext()
|
||||
);
|
||||
}
|
||||
|
||||
// 施加伤害加成 GE
|
||||
if (SwordFlightDamageBonusGE)
|
||||
{
|
||||
DamageBonusHandle = ASC->ApplyGameplayEffectToSelf(
|
||||
SwordFlightDamageBonusGE->GetDefaultObject<UGameplayEffect>(),
|
||||
1.f, ASC->MakeEffectContext()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void URPGSwordFlightAbility::RemoveFlightEffects()
|
||||
{
|
||||
ARPGCharacterBase* Owner = Cast<ARPGCharacterBase>(GetSkillUser());
|
||||
if (!Owner) return;
|
||||
|
||||
URPGAbilitySystemComponent* ASC = Owner->GetRPGAbilitySystemComponent();
|
||||
if (!ASC) return;
|
||||
|
||||
if (MovementGEHandle.IsValid())
|
||||
ASC->RemoveActiveGameplayEffect(MovementGEHandle);
|
||||
if (DamageBonusHandle.IsValid())
|
||||
ASC->RemoveActiveGameplayEffect(DamageBonusHandle);
|
||||
}
|
||||
|
||||
bool URPGSwordFlightAbility::CheckManaSufficient() const
|
||||
{
|
||||
ARPGCharacterBase* Owner = Cast<ARPGCharacterBase>(GetSkillUser());
|
||||
if (!Owner) return false;
|
||||
|
||||
URPGAbilitySystemComponent* ASC = Owner->GetRPGAbilitySystemComponent();
|
||||
if (!ASC) return false;
|
||||
|
||||
return ASC->GetNumericAttribute(URPGAttributeSet::GetManaAttribute()) >= MinManaToActivate;
|
||||
}
|
||||
|
||||
void URPGSwordFlightAbility::DrainManaPerTick(float DeltaTime)
|
||||
{
|
||||
CurrentManaDrainAccum += ManaDrainPerSecond * DeltaTime;
|
||||
if (CurrentManaDrainAccum >= 1.f)
|
||||
{
|
||||
int32 DrainAmount = FMath::FloorToInt(CurrentManaDrainAccum);
|
||||
CurrentManaDrainAccum -= DrainAmount;
|
||||
|
||||
ARPGCharacterBase* Owner = Cast<ARPGCharacterBase>(GetSkillUser());
|
||||
if (Owner)
|
||||
{
|
||||
Owner->GetRPGAbilitySystemComponent()->SetNumericAttributeBase(
|
||||
URPGAttributeSet::GetManaAttribute(),
|
||||
FMath::Max(0.f, Owner->GetRPGAbilitySystemComponent()->
|
||||
GetNumericAttribute(URPGAttributeSet::GetManaAttribute()) - DrainAmount)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 任务 4:「符修」技能效果系统设计(映射到 GAS Effect)
|
||||
|
||||
### 设计前提
|
||||
|
||||
符修在流派体系中的定位:通过绘制**符文符箓**将法术封印在纸上,战斗中消耗符箓瞬间释放。核心机制是**制符(战前准备)→ 释符(战斗中消耗)**。符文效果通过 GAS GameplayEffect 实现。
|
||||
|
||||
### 一、符修核心机制数据模型
|
||||
|
||||
#### FRTalismanData.h(新建)
|
||||
|
||||
```cpp
|
||||
// Plugins/RPGGameCore/Source/RPGGameplayAbility/Public/Abilities/Talisman/FRTalismanData.h
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GameplayTagContainer.h"
|
||||
#include "GameplayEffect.h"
|
||||
#include "FRTalismanData.generated.h"
|
||||
|
||||
/** 符箓等级 */
|
||||
UENUM(BlueprintType)
|
||||
enum class ERPGTalismanTier : uint8
|
||||
{
|
||||
YellowPaper UMETA(DisplayName = "黄纸符"), // 基础符,单次效果
|
||||
SilverScript UMETA(DisplayName = "银篆符"), // 中级符,可叠加2层
|
||||
GoldSeal UMETA(DisplayName = "金印符"), // 高级符,效果翻倍
|
||||
JadeEdict UMETA(DisplayName = "玉敕符"), // 顶级符,范围效果
|
||||
};
|
||||
|
||||
/** 符箓触发方式 */
|
||||
UENUM(BlueprintType)
|
||||
enum class ERPGTalismanTrigger : uint8
|
||||
{
|
||||
OnUse UMETA(DisplayName = "主动释放"), // 主动从快捷栏使用
|
||||
OnHit UMETA(DisplayName = "受击触发"), // 被攻击时自动触发
|
||||
OnLowHP UMETA(DisplayName = "濒死护身"), // HP < 30% 自动触发
|
||||
OnTimer UMETA(DisplayName = "定时触发"), // 定时延迟触发
|
||||
};
|
||||
|
||||
/** 单个符箓效果定义 — 映射到 1 个 GAS GameplayEffect */
|
||||
USTRUCT(BlueprintType)
|
||||
struct RPGGAMEPLAYABILITY_API FRPGTalismanEffect
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
// 符箓配置
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Talisman|Identity")
|
||||
FName TalismanId; // 符箓唯一 ID
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Talisman|Identity")
|
||||
FText TalismanName; // 显示名:"烈火符"、"金刚符"
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Talisman|Identity")
|
||||
ERPGTalismanTier Tier = ERPGTalismanTier::YellowPaper;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Talisman|Identity")
|
||||
ERPGTalismanTrigger TriggerType = ERPGTalismanTrigger::OnUse;
|
||||
|
||||
// === GAS 映射 ===
|
||||
// 核心:每个符箓效果对应一个 UGameplayEffect 蓝图子类
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Talisman|GAS")
|
||||
TSubclassOf<UGameplayEffect> PrimaryEffectClass; // 主 GE(修改属性/施加 Tag)
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Talisman|GAS")
|
||||
TSubclassOf<UGameplayEffect> SecondaryEffectClass; // 副 GE(可选,范围/连锁效果)
|
||||
|
||||
// SetByCaller 动态参数(符箓等级越高,倍率越大)
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Talisman|GAS")
|
||||
TMap<FGameplayTag, float> SetByCallerMagnitudes; // Tag → 基础数值
|
||||
|
||||
// 消耗
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Talisman|Cost")
|
||||
int32 ManaCost = 20; // 释符消耗法力
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Talisman|Cost")
|
||||
float CooldownSeconds = 3.f; // 释符冷却
|
||||
};
|
||||
```
|
||||
|
||||
### 二、符修五大符系 → GAS GameplayEffect 映射表
|
||||
|
||||
| 符系 | 代表符箓 | GAS GE 类型 | 修改的 Attribute | Duration Policy | 关键 SetByCaller Tag |
|
||||
|------|---------|------------|-----------------|-----------------|---------------------|
|
||||
| **攻击符系** | 烈火符 | `GE_Talisman_Fire` (Instant) | `Damage` (临时变量) | Instant | `SetByCaller.FireDamage` |
|
||||
| | 冰封符 | `GE_Talisman_Ice` (HasDuration) | `MoveSpeed` (减速 %) | 5s Duration | `SetByCaller.SlowPercent` |
|
||||
| | 雷击符 | `GE_Talisman_Thunder` (Instant) | `Damage` + `Tough` (削韧) | Instant | `SetByCaller.ThunderDamage` |
|
||||
| **防御符系** | 金刚符 | `GE_Talisman_Barrier` (HasDuration) | `Shield` (+护盾值) | 10s Duration | `SetByCaller.ShieldAmount` |
|
||||
| | 铁壁符 | `GE_Talisman_IronWall` (HasDuration) | `DefensePower` (+%) | 15s Duration | `SetByCaller.DefenseBonus` |
|
||||
| | 净身符 | `GE_Talisman_Cleanse` (Instant) | 移除 `State.Debuff.*` Tag | Instant | — |
|
||||
| **辅助符系** | 神行符 | `GE_Talisman_Speed` (HasDuration) | `MoveSpeed` (+%) | 20s Duration | `SetByCaller.SpeedBonus` |
|
||||
| | 聚灵符 | `GE_Talisman_Meditate` (HasDuration) | `Mana` (回复速率) | 30s Duration | `SetByCaller.ManaRegenRate` |
|
||||
| | 破阵符 | `GE_Talisman_Break` (Instant) | 移除敌方 Buff Tag | Instant | `SetByCaller.DispelCount` |
|
||||
| **诅咒符系** | 虚弱符 | `GE_Talisman_Weaken` (HasDuration) | `AttackPower` (-%敌方) | 8s Duration | `SetByCaller.AttackReduce` |
|
||||
| | 定身符 | `GE_Talisman_Root` (HasDuration) | 施加 `State.CrowdControl.Root` Tag | 3s Duration | `SetByCaller.RootDuration` |
|
||||
| | 噬魂符 | `GE_Talisman_SoulDrain` (HasDuration) | 敌方 `Health` DoT + 自身 `Health` Heal | 6s Duration | `SetByCaller.DrainAmount` |
|
||||
| **阵法符系** | 困龙阵符 | `GE_Talisman_TrapField` (Infinite/HasDuration) | 范围 `MoveSpeed` -80% | 15s 范围 Duration | `SetByCaller.TrapRadius` |
|
||||
| | 万剑阵符 | `GE_Talisman_SwordArray` (Instant × N) | 范围内 N 次 `Damage` 结算 | Instant (周期触发) | `SetByCaller.PerSwordDamage` |
|
||||
| | 回春阵符 | `GE_Talisman_HealField` (Infinite) | 范围内友方 `Health` 持续回复 | UntilCancelled | `SetByCaller.HealPerTick` |
|
||||
|
||||
### 三、与现有 GAS Effect 架构的融合
|
||||
|
||||
#### 3.1 对接伤害管线
|
||||
|
||||
符修攻击符接入现有五段伤害管线(来自 Community 5):
|
||||
|
||||
```
|
||||
释符(烈火符)
|
||||
│ URPGGameplayAbility::ActivateAbility()
|
||||
├── 构造 FSkillDamageData
|
||||
│ ├─ SkillDamage = SetByCaller.FireDamage × TierMultiplier
|
||||
│ ├─ SkillToughDamage = SetByCaller.FireDamage × 0.3
|
||||
│ └─ HitLevel = ERPGHitLevel::LV1(黄纸)~ LV3(玉敕)
|
||||
│
|
||||
└── ARPGCharacterBase::ReceiveDamageEvent()
|
||||
├── USDHDamageCaculationSetting::CaculateDamage()
|
||||
│ ├─ 暴击 / 命中 / 闪避 / 防御减伤
|
||||
│ └─ 输出 { ShieldDamage, ToughDamage, HealthDamage }
|
||||
├── 优先扣 Shield → 再扣 Tough → 最后扣 Health
|
||||
└── URPGAttributeSet::PostGameplayEffectExecute
|
||||
```
|
||||
|
||||
#### 3.2 符箓充能与释放系统
|
||||
|
||||
```cpp
|
||||
// URPGFuXiuAbilityComponent — 符修专属 ASC 扩展
|
||||
UCLASS()
|
||||
class URPGFuXiuAbilityComponent : public UActorComponent
|
||||
{
|
||||
// 符箓背包(最多携带 N 张符)
|
||||
UPROPERTY()
|
||||
TArray<FRPGTalismanEffect> EquippedTalismans;
|
||||
|
||||
// 制符(非战斗状态,消耗材料+法力+时间)
|
||||
UFUNCTION(BlueprintCallable)
|
||||
FRPGTalismanEffect CraftTalisman(FName TalismanId, ERPGTalismanTier Tier);
|
||||
|
||||
// 释符(战斗中触发 GAS GE)
|
||||
UFUNCTION(BlueprintCallable)
|
||||
bool ActivateTalisman(int32 TalismanIndex, AActor* Target = nullptr);
|
||||
|
||||
// 符箓等级倍率
|
||||
float GetTierMultiplier(ERPGTalismanTier Tier) const
|
||||
{
|
||||
static const TMap<ERPGTalismanTier, float> Multipliers = {
|
||||
{ ERPGTalismanTier::YellowPaper, 1.0f },
|
||||
{ ERPGTalismanTier::SilverScript, 1.5f },
|
||||
{ ERPGTalismanTier::GoldSeal, 2.2f },
|
||||
{ ERPGTalismanTier::JadeEdict, 3.0f },
|
||||
};
|
||||
return Multipliers.FindRef(Tier);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
#### 3.3 SetByCaller 符箓 Tag 体系
|
||||
|
||||
```cpp
|
||||
// 在 SDHGameTagSettings 中新增符箓专属 SetByCaller Tag
|
||||
namespace RPGSetByCaller
|
||||
{
|
||||
// 攻击符
|
||||
UE_DECLARE_GAMEPLAY_TAG_EXTERN(Talisman_Fire_Damage);
|
||||
UE_DECLARE_GAMEPLAY_TAG_EXTERN(Talisman_Ice_SlowPercent);
|
||||
UE_DECLARE_GAMEPLAY_TAG_EXTERN(Talisman_Thunder_Damage);
|
||||
|
||||
// 防御符
|
||||
UE_DECLARE_GAMEPLAY_TAG_EXTERN(Talisman_Barrier_ShieldAmount);
|
||||
UE_DECLARE_GAMEPLAY_TAG_EXTERN(Talisman_IronWall_DefenseBonus);
|
||||
|
||||
// 辅助符
|
||||
UE_DECLARE_GAMEPLAY_TAG_EXTERN(Talisman_Speed_Bonus);
|
||||
UE_DECLARE_GAMEPLAY_TAG_EXTERN(Talisman_Meditate_ManaRegen);
|
||||
|
||||
// 诅咒符
|
||||
UE_DECLARE_GAMEPLAY_TAG_EXTERN(Talisman_Weaken_AttackReduce);
|
||||
UE_DECLARE_GAMEPLAY_TAG_EXTERN(Talisman_SoulDrain_Amount);
|
||||
|
||||
// 阵法符
|
||||
UE_DECLARE_GAMEPLAY_TAG_EXTERN(Talisman_Trap_Radius);
|
||||
UE_DECLARE_GAMEPLAY_TAG_EXTERN(Talisman_SwordArray_PerSwordDamage);
|
||||
UE_DECLARE_GAMEPLAY_TAG_EXTERN(Talisman_HealField_HealPerTick);
|
||||
}
|
||||
```
|
||||
|
||||
### 四、符箓效果示例:「裂空·雷击符」
|
||||
|
||||
```
|
||||
蓝图配置(BP_GE_Talisman_Thunder_Base):
|
||||
|
||||
Modifiers:
|
||||
├─ URPGAttributeSet::Damage
|
||||
│ ├─ ModifierOp: Override
|
||||
│ └─ Magnitude: SetByCaller (Tag=Talisman_Thunder_Damage)
|
||||
├─ URPGAttributeSet::Tough
|
||||
│ ├─ ModifierOp: Add
|
||||
│ └─ Magnitude: SetByCaller (Tag=Talisman_Thunder_Damage) × -0.3
|
||||
└─ GameplayTag:
|
||||
└─ Grant: State.HitReaction.Stagger(击退硬直)
|
||||
|
||||
Duration Policy: Instant
|
||||
|
||||
Damage 计算链:
|
||||
Base Damage = SetByCaller.Talisman_Thunder_Damage (50)
|
||||
× TierMultiplier (黄纸=1.0 / 银篆=1.5 / 金印=2.2 / 玉敕=3.0)
|
||||
× 符修修为加成 (境界 × 0.05)
|
||||
× 当前灵力系数 (Mana/MaxMana × 0.5 + 0.5)
|
||||
|
||||
黄纸雷击符 = 50 × 1.0 × 1.0 × 1.0 = 50 伤害 + 15 削韧
|
||||
玉敕雷击符 = 50 × 3.0 × 2.0 × 1.0 = 300 伤害 + 90 削韧
|
||||
```
|
||||
|
||||
### 五、涉及文件清单
|
||||
|
||||
| 文件(新建/修改) | 内容 |
|
||||
|------|------|
|
||||
| `Public/Abilities/Talisman/FRTalismanData.h` | **新建**:符箓数据结构、枚举 |
|
||||
| `Public/Abilities/Talisman/URPGFuXiuAbilityComponent.h/.cpp` | **新建**:符修 ASC 扩展组件 |
|
||||
| `Public/Abilities/Talisman/GE_Talisman_*.h` | **新建**:5 类 14 个 GameplayEffect 蓝图基类 |
|
||||
| `Public/Config/SDHGameTagSettings.h` | **修改**:新增 SetByCaller.Talisman_* Tag |
|
||||
| `Public/Character/Attribute/RPGAttributeSet.h` | **不变**:符箓几何修改现有 Health/Shield/Tough/Mana/MoveSpeed/AttackPower/DefensePower 属性 |
|
||||
| `Public/Items/RPGItem.h` | **修改**:新增 `URPGTalismanItem` 物品类型 |
|
||||
| `.trae/documents/01_策划设计/修仙基础概念设定/修仙流派.md` | **修改**:符修独立为独立流派(当前在魔修路径下) |
|
||||
|
||||
---
|
||||
|
||||
## 附录:关键文件速查
|
||||
|
||||
| 缩写 | 全称 | 核心文件位置 |
|
||||
|------|------|------------|
|
||||
| LWS | LivingWorldSystem | `Plugins/RPGGameCore/Source/LivingWorldSystem/` |
|
||||
| GA/GAS | Gameplay Ability System | `Plugins/RPGGameCore/Source/RPGGameplayAbility/` |
|
||||
| ASC | AbilitySystemComponent | `URPGAbilitySystemComponent` |
|
||||
| GE | GameplayEffect | UGameplayEffect 蓝图子类 |
|
||||
| CMC | CharacterMovementComponent | `LCMCharacterMovementComponent` |
|
||||
| ActionPose | 架势(主姿态) | `ELM_ActionPose` 在 `RPGTypes.h:203`,24 个主架势 |
|
||||
| SM | SkillStateMachine | `USkillSMInstance` (LogicDriver) |
|
||||
@@ -61,3 +61,6 @@ tags:
|
||||
| Token 消耗(估算) | | |
|
||||
| 结果完整性 | /10 | /10 |
|
||||
| 用时 | | |
|
||||
# 结果
|
||||
- No Graphify:[[图谱 vs 传统 NPC 对比测试]]
|
||||
- Graphify:[[AIDM_NPC与修仙系统分析报告_Graphify]]
|
||||
@@ -0,0 +1,909 @@
|
||||
---
|
||||
tags:
|
||||
- GAS
|
||||
- UE5
|
||||
- 架构
|
||||
- 重构
|
||||
- 插件
|
||||
date: 2026-05-30
|
||||
project: MusicFighterGame
|
||||
plugin: RPGGameplayAbility
|
||||
status: 设计阶段
|
||||
---
|
||||
|
||||
# RPGGameplayAbility 插件重构文档
|
||||
|
||||
## 概述
|
||||
|
||||
本文档基于对以下三个 UE5 项目的深度研究,分析其 GameplayAbilitySystem (GAS) 架构、插件设计和技术亮点,并对 `RPGGameplayAbility` 插件提出全面的重构建议。
|
||||
|
||||
### 研究项目
|
||||
|
||||
| 项目 | 类型 | 亮点 |
|
||||
|------|------|------|
|
||||
| [[LyraStarterGame]] | Epic 官方 UE5 示例 | GameFeature 模块化、GameplayTag 输入路由、装备系统、GamePhase |
|
||||
| [[GASShooter]] | Epic 官方 UE4 射击示例 | 多 Mesh 蒙太奇、武器能力授予、EffectContainer、可重用 TargetActor |
|
||||
| [[UE5_GAS_Aura]] | 社区 RPG 教程项目 | 三层属性模型、MMC 派生属性、MVVC WidgetController、DataAsset 驱动 |
|
||||
|
||||
### 当前插件现状
|
||||
|
||||
`RPGGameplayAbility` 插件基于 GASShooter 框架衍生,已具备:
|
||||
|
||||
- ✅ 多 Mesh 蒙太奇复制系统
|
||||
- ✅ EffectContainer + TargetType 效果容器系统
|
||||
- ✅ RPC 批处理 (`ShouldDoServerAbilityRPCBatch`)
|
||||
- ✅ 伤害元属性模式 (DamageExecutionCalc)
|
||||
- ✅ 可重用 GATA_Trace 瞄准 Actor
|
||||
- ✅ GameplayMessageSubsystem 基础设施
|
||||
|
||||
但存在以下核心架构问题:
|
||||
|
||||
- ❌ 硬编码 `EGSAbilityInputID` 枚举输入绑定
|
||||
- ❌ 单一巨型属性集 (18 个属性)
|
||||
- ❌ 角色基类手动维护 15+ 个属性 getter 函数
|
||||
- ❌ 无 AbilitySet DataAsset 模块化能力配置
|
||||
- ❌ LoadingScreen 模块耦合在 gameplay 插件中
|
||||
- ❌ 无 GameplayTag 驱动的输入路由
|
||||
- ❌ 无 MVVM/WidgetController UI 模式
|
||||
- ❌ 无装备/武器系统与 GAS 集成
|
||||
- ❌ 无队伍/阵营系统
|
||||
- ❌ 无 GamePhase 阶段管理
|
||||
- ❌ 硬编码骨骼名称 (`"b_head"`)
|
||||
|
||||
---
|
||||
|
||||
## 核心重构优先级
|
||||
|
||||
### 优先级 1:GameplayTag 输入路由替换硬编码枚举
|
||||
|
||||
> [!important] 最高优先级
|
||||
> 这是影响最大的单一改动,Lyra 和 Aura 都采用此模式。
|
||||
|
||||
**当前实现(差):**
|
||||
|
||||
```cpp
|
||||
// RPGAbilityTypes.h
|
||||
UENUM(BlueprintType)
|
||||
enum class EGSAbilityInputID : uint8 {
|
||||
None = 0, Confirm = 1, Cancel = 2,
|
||||
Sprint = 3, Jump = 4, PrimaryFire = 5,
|
||||
SecondaryFire = 6, AlternateFire = 7,
|
||||
Reload = 8, NextWeapon = 9, PrevWeapon = 10,
|
||||
Interact = 11
|
||||
};
|
||||
```
|
||||
|
||||
**推荐实现(Lyra 模式):**
|
||||
|
||||
```cpp
|
||||
// RPGInputConfig.h - DataAsset 驱动
|
||||
USTRUCT(BlueprintType)
|
||||
struct FRPGInputAction {
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
TObjectPtr<const UInputAction> InputAction;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
FGameplayTag InputTag;
|
||||
};
|
||||
|
||||
UCLASS(BlueprintType)
|
||||
class URPGInputConfig : public UDataAsset {
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
TArray<FRPGInputAction> AbilityInputActions;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
TArray<FRPGInputAction> NativeInputActions;
|
||||
};
|
||||
|
||||
// RPGInputComponent.h - 模板绑定
|
||||
class URPGInputComponent : public UEnhancedInputComponent {
|
||||
template<class UserClass, typename PressedFuncType,
|
||||
typename ReleasedFuncType, typename HeldFuncType>
|
||||
void BindAbilityActions(const URPGInputConfig* InputConfig,
|
||||
UserClass* Object, PressedFuncType PressedFunc,
|
||||
ReleasedFuncType ReleasedFunc, HeldFuncType HeldFunc);
|
||||
};
|
||||
|
||||
// RpgAbilitySystemComponent.h - ASC 输入处理
|
||||
void URPGAbilitySystemComponent::AbilityInputTagPressed(FGameplayTag InputTag) {
|
||||
for (FGameplayAbilitySpec& Spec : ActivatableAbilities.Items) {
|
||||
if (Spec.GetDynamicSpecSourceTags().HasTagExact(InputTag)) {
|
||||
Spec.InputPressed = true;
|
||||
if (Spec.IsActive()) {
|
||||
AbilitySpecInputPressed(Spec);
|
||||
} else {
|
||||
TryActivateAbility(Spec.Handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**优势:**
|
||||
- 新增能力无需重新编译枚举
|
||||
- 输入可通过 DataAsset 按角色重新绑定
|
||||
- GameFeature 插件可在不接触核心代码的情况下添加新输入标签
|
||||
- 支持 Pressed/Held/Released 三种策略(类似 Aura 的 `AbilityInputTagHeld`/`Released`)
|
||||
|
||||
---
|
||||
|
||||
### 优先级 2:拆分巨型属性集
|
||||
|
||||
> [!important] 核心架构改动
|
||||
> Aura 的三层属性模型是 RPG 游戏的标准做法。
|
||||
|
||||
**当前问题:** `RPGAttributeSetBase` 包含 18 个属性,混在一起不可拆分。
|
||||
|
||||
**推荐结构:**
|
||||
|
||||
```cpp
|
||||
// 第一层:主要属性(可投入加点的属性)
|
||||
UCLASS()
|
||||
class URPGVitalAttributeSet : public UAttributeSet {
|
||||
// Health, MaxHealth, HealthRegenRate
|
||||
// Mana, MaxMana, ManaRegenRate
|
||||
// Stamina, MaxStamina, StaminaRegenRate
|
||||
// Shield, MaxShield, ShieldRegenRate
|
||||
};
|
||||
|
||||
// 第二层:次要属性(通过 MMC 派生的战斗属性)
|
||||
UCLASS()
|
||||
class URPGCombatAttributeSet : public UAttributeSet {
|
||||
// Armor, ArmorPenetration
|
||||
// CritChance, CritDamage, CritResistance
|
||||
// BlockChance
|
||||
// MoveSpeed
|
||||
};
|
||||
|
||||
// 第三层:主要属性(核心加点属性)
|
||||
UCLASS()
|
||||
class URPGPrimaryAttributeSet : public UAttributeSet {
|
||||
// Strength, Intelligence, Agility, Vitality
|
||||
};
|
||||
|
||||
// Meta 属性(临时、非复制、仅服务器)
|
||||
UCLASS()
|
||||
class URPGMetaAttributeSet : public UAttributeSet {
|
||||
// Damage (meta, 仅服务器)
|
||||
// Healing (meta, 仅服务器)
|
||||
};
|
||||
|
||||
// 进度属性
|
||||
UCLASS()
|
||||
class URPGProgressionAttributeSet : public UAttributeSet {
|
||||
// CharacterLevel, XP, Gold
|
||||
};
|
||||
```
|
||||
|
||||
**MMC 派生属性计算(Aura 模式):**
|
||||
|
||||
```cpp
|
||||
// MMC_MaxHealth.cpp
|
||||
float UMMC_MaxHealth::CalculateBaseMagnitude_Implementation(
|
||||
const FGameplayEffectSpec& Spec) const {
|
||||
|
||||
float Vitality = 0.f;
|
||||
GetCapturedAttributeMagnitude(
|
||||
VitalityDef, Spec, FAggregatorEvaluateParameters(), Vitality);
|
||||
|
||||
int32 Level = 1;
|
||||
if (Spec.GetContext().GetSourceObject()) {
|
||||
// 通过 ICombatInterface 获取等级
|
||||
}
|
||||
|
||||
return 80.f + 2.5f * Vitality + 10.f * Level;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 优先级 3:引入 AbilitySet DataAsset
|
||||
|
||||
> [!important] 模块化配置
|
||||
> 替换硬编码的 `CharacterAbilities` 数组。
|
||||
|
||||
```cpp
|
||||
USTRUCT(BlueprintType)
|
||||
struct FRPGGameplayAbilitySet_GameplayAbility {
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
TSubclassOf<URPGGameplayAbility> Ability;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
int32 AbilityLevel = 1;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
FGameplayTag InputTag;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
ERPGAbilityActivationPolicy ActivationPolicy;
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FRPGGameplayAbilitySet_GameplayEffect {
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
TSubclassOf<UGameplayEffect> GameplayEffect;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
float EffectLevel = 1.f;
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FRPGGameplayAbilitySet_AttributeSet {
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
TSubclassOf<UAttributeSet> AttributeSet;
|
||||
};
|
||||
|
||||
UCLASS(BlueprintType)
|
||||
class URPGGameplayAbilitySet : public UPrimaryDataAsset {
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
TArray<FRPGGameplayAbilitySet_GameplayAbility> GrantedAbilities;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
TArray<FRPGGameplayAbilitySet_GameplayEffect> GrantedEffects;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
TArray<FRPGGameplayAbilitySet_AttributeSet> GrantedAttributes;
|
||||
|
||||
void GiveToAbilitySystem(
|
||||
URPGAbilitySystemComponent* ASC,
|
||||
FRPGGameplayAbilitySet_GrantedHandles& OutHandles,
|
||||
UObject* SourceObject = nullptr) const;
|
||||
|
||||
void TakeFromAbilitySystem(
|
||||
FRPGGameplayAbilitySet_GrantedHandles& Handles) const;
|
||||
};
|
||||
```
|
||||
|
||||
**使用场景:**
|
||||
- 角色职业定义:`DA_FighterAbilitySet`、`DA_MageAbilitySet`
|
||||
- 武器/装备授予:装备授予 `DA_SwordAbilitySet`
|
||||
- 被动技能树:技能树节点授予特定的 AbilitySet
|
||||
- Buff/Debuff:临时添加/移除 AbilitySet
|
||||
|
||||
---
|
||||
|
||||
### 优先级 4:MVVM WidgetController UI 模式
|
||||
|
||||
> [!important] UI 解耦
|
||||
> 当前插件直接在角色代码中 push UI 数据,耦合度高。
|
||||
|
||||
**Aura 的 WidgetController 架构:**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ FWidgetControllerParams(模型数据) │
|
||||
│ - PlayerController │
|
||||
│ - PlayerState │
|
||||
│ - AbilitySystemComponent │
|
||||
│ - AttributeSet │
|
||||
└──────────────┬──────────────────────────────────┘
|
||||
│
|
||||
┌──────────────▼──────────────────────────────────┐
|
||||
│ URPGWidgetController(ViewModel 基类) │
|
||||
│ - BroadcastInitialValues() │
|
||||
│ - BindCallbacksToDependencies() │
|
||||
│ - 所有权:PlayerController │
|
||||
└──────────────┬──────────────────────────────────┘
|
||||
│
|
||||
┌──────────┴──────────┐
|
||||
│ │
|
||||
┌───▼──────────┐ ┌──────▼──────────┐
|
||||
│ OverlayWidget │ │ AttributeMenu │
|
||||
│ Controller │ │ WidgetController│
|
||||
│ - Health/Mana │ │ - 动态属性菜单 │
|
||||
│ - Messages │ │ - TagsToAttrs │
|
||||
└───┬───────────┘ └──────┬──────────┘
|
||||
│ │
|
||||
┌───▼─────────────────────▼──────────────────────┐
|
||||
│ URPGUserWidget(View - UMG Blueprint) │
|
||||
│ - SetWidgetController() 事件 │
|
||||
│ - 绑定 BlueprintAssignable 委托 │
|
||||
└─────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**HUD 工厂模式:**
|
||||
|
||||
```cpp
|
||||
UCLASS()
|
||||
class ARPGHUD : public AHUD {
|
||||
// 懒加载单例工厂
|
||||
UOverlayWidgetController* GetOverlayWidgetController(
|
||||
const FRPGWidgetControllerParams& Params);
|
||||
|
||||
UAttributeMenuWidgetController* GetAttributeMenuWidgetController(
|
||||
const FRPGWidgetControllerParams& Params);
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 优先级 5:插件模块拆分
|
||||
|
||||
**当前问题:** 5 个模块(RPGGameplayAbility、CommonLoadingScreen、CommonStartupLoadingScreen、GameplayMessageRuntime、GameplayMessageNodes)全部在一个插件中。
|
||||
|
||||
**推荐结构:**
|
||||
|
||||
```
|
||||
Plugins/
|
||||
├── RPGGameplayAbility/ # 核心 GAS 扩展
|
||||
│ ├── Source/
|
||||
│ │ └── RPGGameplayAbility/ # 唯一模块
|
||||
│ └── RPGGameplayAbility.uplugin
|
||||
│
|
||||
├── CommonLoadingScreen/ # 独立加载画面插件
|
||||
│ └── CommonLoadingScreen.uplugin
|
||||
│
|
||||
├── CommonStartupLoadingScreen/ # 独立启动加载画面插件
|
||||
│ └── CommonStartupLoadingScreen.uplugin
|
||||
│
|
||||
└── GameplayMessageRouter/ # 消息路由器(保持独立)
|
||||
├── GameplayMessageRuntime/
|
||||
└── GameplayMessageNodes/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 各系统详细重构建议
|
||||
|
||||
### 1. ASC 扩展 (URPGAbilitySystemComponent)
|
||||
|
||||
**保留:**
|
||||
- 多 Mesh 蒙太奇复制系统(格斗游戏需要 1P/3P 双骨骼)
|
||||
- RPC 批处理 (`ShouldDoServerAbilityRPCBatch`)
|
||||
- Blueprint 标签操作辅助函数
|
||||
- 本地 GameplayCue 执行
|
||||
|
||||
**新增(来自 Lyra):**
|
||||
|
||||
| 功能 | 说明 |
|
||||
|------|------|
|
||||
| `AbilityInputTagPressed/Released/Held` | GameplayTag 驱动的输入处理 |
|
||||
| `ProcessAbilityInput(DeltaTime)` | 每帧统一的输入分发 |
|
||||
| 激活组系统 | Independent / Exclusive_Replaceable / Exclusive_Blocking |
|
||||
| 动态 Tag GE 应用 | 运行时 Tag 管理 |
|
||||
| TagRelationshipMapping 支持 | 跨能力阻塞/取消关系 |
|
||||
|
||||
**新增(来自 Aura):**
|
||||
|
||||
| 功能 | 说明 |
|
||||
|------|------|
|
||||
| `ClientEffectApplied` RPC | GE 应用时客户端通知 UI |
|
||||
| `m_EffectAssetTag` 多播委托 | Widget 创建触发 |
|
||||
|
||||
**激活组系统(格斗游戏关键):**
|
||||
|
||||
```cpp
|
||||
UENUM(BlueprintType)
|
||||
enum class ERPGAbilityActivationGroup : uint8 {
|
||||
Independent, // 不阻塞任何能力,不被任何能力阻塞
|
||||
Exclusive_Replaceable, // 可被其他 Exclusive 能力取消
|
||||
Exclusive_Blocking, // 阻塞其他 Exclusive 能力,自身不可被取消
|
||||
};
|
||||
|
||||
// 使用场景:
|
||||
// - 普通攻击:Independent(可叠加)
|
||||
// - 必杀技:Exclusive_Replaceable(会被新必杀技取消)
|
||||
// - 超必杀技:Exclusive_Blocking(不可取消,阻塞其他技能)
|
||||
// - 防御/受击:Exclusive_Blocking(不可取消)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. GameplayAbility 基类 (URPGGameplayAbility)
|
||||
|
||||
**保留:**
|
||||
- EffectContainer 系统(Tag → TargetType + GEs)
|
||||
- 自定义 Cost 检查(RPGCheckCost/RPGApplyCost BlueprintNativeEvent)
|
||||
- 多 Mesh 动画辅助函数
|
||||
|
||||
**新增(来自 Lyra):**
|
||||
|
||||
```cpp
|
||||
UENUM(BlueprintType)
|
||||
enum class ERPGAbilityActivationPolicy : uint8 {
|
||||
OnInputTriggered, // 按键按下触发
|
||||
WhileInputActive, // 按键持续期间激活
|
||||
OnSpawn, // 授予时立即激活(被动能力)
|
||||
OnRhythmBeat, // 节奏节拍触发(MusicFighter 特有)
|
||||
};
|
||||
|
||||
// 组合式 Cost 系统
|
||||
UCLASS(Abstract, EditInlineNew, DefaultToInstanced)
|
||||
class URPGAbilityCost : public UObject {
|
||||
virtual bool CheckCost(const URPGGameplayAbility* Ability,
|
||||
const FGameplayAbilitySpecHandle Handle,
|
||||
const FGameplayAbilityActorInfo* ActorInfo,
|
||||
FGameplayTagContainer* OptionalRelevantTags) const;
|
||||
|
||||
virtual void ApplyCost(const URPGGameplayAbility* Ability,
|
||||
const FGameplayAbilitySpecHandle Handle,
|
||||
const FGameplayAbilityActorInfo* ActorInfo,
|
||||
const FGameplayAbilityActivationInfo ActivationInfo);
|
||||
};
|
||||
|
||||
// 子类:
|
||||
// - URPGAbilityCost_GameplayEffect(GE 消耗)
|
||||
// - URPGAbilityCost_ItemTagStack(物品标记栈消耗,如弹药)
|
||||
// - URPGAbilityCost_Attribute(直接属性消耗,如怒气值)
|
||||
```
|
||||
|
||||
**删除/替换:**
|
||||
- `EGSAbilityInputID AbilityInputID` → `FGameplayTag StartupInputTag`
|
||||
- `bActivateOnInput` → `ERPGAbilityActivationPolicy ActivationPolicy`
|
||||
- `bSourceObjectMustEqualCurrentWeaponToActivate` → 泛化为 Tag 需求检查
|
||||
|
||||
---
|
||||
|
||||
### 3. 属性系统 - 完整重构
|
||||
|
||||
```
|
||||
Primary Attributes(主要/可投资属性)
|
||||
├── Strength → 影响 PhysicalAttack, MaxHealth
|
||||
├── Intelligence → 影响 MagicAttack, MaxMana
|
||||
├── Agility → 影响 CritChance, MoveSpeed, DodgeChance
|
||||
└── Vitality → 影响 MaxHealth, MaxStamina, HealthRegenRate
|
||||
|
||||
Secondary Attributes(派生/战斗属性 - 通过 MMC 计算)
|
||||
├── MaxHealth = f(Vitality, Level)
|
||||
├── MaxMana = f(Intelligence, Level)
|
||||
├── MaxStamina = f(Vitality, Level)
|
||||
├── PhysicalAttack = f(Strength, Level)
|
||||
├── MagicAttack = f(Intelligence, Level)
|
||||
├── Armor = f(Agility, Vitality, Level)
|
||||
├── ArmorPenetration = f(Strength, Level)
|
||||
├── CritChance = f(Agility, Level)
|
||||
├── CritDamage = 1.5x (基础) + 装备加成
|
||||
├── CritResistance = f(Vitality, Level)
|
||||
├── BlockChance = f(Strength, Level)
|
||||
├── DodgeChance = f(Agility, Level)
|
||||
└── MoveSpeed = Base(400) + f(Agility, Level)
|
||||
|
||||
Vital Attributes(运行时资源)
|
||||
├── Health → [0, MaxHealth]
|
||||
├── Mana → [0, MaxMana]
|
||||
└── Stamina → [0, MaxStamina]
|
||||
|
||||
Meta Attributes(临时,服务器专用)
|
||||
├── Damage → ExecutionCalc 写入 → PostGameplayEffectExecute 处理后归零
|
||||
└── Healing → HealingExecutionCalc 写入 → 处理后归零
|
||||
|
||||
Progression(进度)
|
||||
├── CharacterLevel → 影响所有 MMC 计算
|
||||
├── XP → 经验值
|
||||
└── Gold → 货币
|
||||
```
|
||||
|
||||
**伤害计算管道:**
|
||||
|
||||
```
|
||||
1. 技能设置 SetByCaller Magnitude (Tag: "Data.Damage")
|
||||
2. URPGDamageExecutionCalc 捕获:
|
||||
- Source: PhysicalAttack/MagicAttack
|
||||
- Target: Armor, ArmorPenetration, CritResistance, BlockChance, DodgeChance
|
||||
3. 计算流程:
|
||||
a. 命中判定 (DodgeChance)
|
||||
b. 暴击判定 (CritChance vs CritResistance)
|
||||
c. 格挡判定 (BlockChance)
|
||||
d. 护甲减免 (Armor vs ArmorPenetration)
|
||||
e. 属性克制修正(元素标签)
|
||||
f. 最终伤害写入 Target.Damage
|
||||
4. PostGameplayEffectExecute:
|
||||
a. Shield 吸收
|
||||
b. Health 扣减 → Clamp
|
||||
c. 存活/死亡判定 → 广播 (GameplayMessageSubsystem)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. 瞄准系统
|
||||
|
||||
**保留:**
|
||||
- `URPGTargetType` 蓝图化瞄准逻辑
|
||||
- `RPGATA_Trace` / `RPGATA_LineTrace` / `RPGATA_SphereTrace`
|
||||
|
||||
**新增(格斗游戏专用):**
|
||||
|
||||
```cpp
|
||||
// 近战弧形瞄准
|
||||
UCLASS(Blueprintable)
|
||||
class URPGTargetType_MeleeArc : public URPGTargetType {
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
float ArcAngle = 90.f; // 弧形角度
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
float ArcRadius = 200.f; // 弧形半径
|
||||
};
|
||||
|
||||
// AOE 圆形瞄准
|
||||
UCLASS(Blueprintable)
|
||||
class URPGTargetType_CircleAOE : public URPGTargetType {
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
float Radius = 300.f;
|
||||
};
|
||||
|
||||
// 组合状态过滤
|
||||
// "已在此连招中被击中过的目标不重复选取"
|
||||
void GetTargets_Implementation(...) {
|
||||
// 检查 Combat.AlreadyHit 标签
|
||||
for (AActor* Target : Candidates) {
|
||||
if (!Target->HasMatchingGameplayTag(Combat_AlreadyHit)) {
|
||||
OutActors.Add(Target);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5. 输入系统
|
||||
|
||||
**替换整个 `EGSAbilityInputID` 枚举为以下架构:**
|
||||
|
||||
```
|
||||
┌─────────────────────────┐
|
||||
│ URPGInputConfig │ DataAsset
|
||||
│ - AbilityInputActions │ 映射 InputAction → GameplayTag
|
||||
│ - NativeInputActions │
|
||||
└───────────┬─────────────┘
|
||||
│
|
||||
┌───────────▼─────────────┐
|
||||
│ URPGInputComponent │ extends UEnhancedInputComponent
|
||||
│ - BindAbilityActions() │ 模板函数,自动绑定
|
||||
└───────────┬─────────────┘
|
||||
│
|
||||
┌───────────▼─────────────┐
|
||||
│ ULyraHeroComponent │ (或 RPGHeroComponent)
|
||||
│ - InitializePlayerInput│
|
||||
└───────────┬─────────────┘
|
||||
│
|
||||
┌───────────▼─────────────┐
|
||||
│ URPGAbilitySystemComp │
|
||||
│ - AbilityInputTagPressed│ 匹配 DynamicSpecSourceTags
|
||||
│ - AbilityInputTagReleased│
|
||||
│ - AbilityInputTagHeld │
|
||||
│ - ProcessAbilityInput │ 每帧统一处理
|
||||
└─────────────────────────┘
|
||||
```
|
||||
|
||||
**MusicFighter 特有:节奏输入缓冲**
|
||||
|
||||
```cpp
|
||||
// 在 ProcessAbilityInput 中
|
||||
void URPGAbilitySystemComponent::ProcessAbilityInput(float DeltaTime, bool bGamePaused) {
|
||||
// ... 标准处理 ...
|
||||
|
||||
// 节奏检测
|
||||
if (bIsOnBeat) {
|
||||
for (FGameplayAbilitySpec& Spec : ActivatableAbilities.Items) {
|
||||
if (Spec.Ability->GetActivationPolicy() == OnRhythmBeat) {
|
||||
// 应用节奏加成标签
|
||||
Spec.DynamicSpecSourceTags.AddTag(RhythmBonusTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 输入缓冲(格斗游戏标准做法)
|
||||
FlushInputBuffer(DeltaTime);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6. UI 系统
|
||||
|
||||
**当前问题:** 直接在 Character/PlayerState/PlayerController 中 push UI 数据。
|
||||
|
||||
**使用 Aura 的 MVVC 模式替换:**
|
||||
|
||||
```cpp
|
||||
// WidgetController 管理 ASC 委托绑定
|
||||
// Widget (UMG) 仅负责显示
|
||||
// 中间通过 BlueprintAssignable 委托通信
|
||||
|
||||
// 消息 Widget 通过 DataTable 驱动:
|
||||
USTRUCT(BlueprintType)
|
||||
struct FRPGMessageWidgetRow : public FTableRowBase {
|
||||
UPROPERTY(EditAnywhere)
|
||||
FGameplayTag MessageTag;
|
||||
|
||||
UPROPERTY(EditAnywhere)
|
||||
TSubclassOf<URPGUserWidget> MessageWidgetClass;
|
||||
|
||||
UPROPERTY(EditAnywhere)
|
||||
UTexture2D* MessageImage;
|
||||
|
||||
UPROPERTY(EditAnywhere)
|
||||
FText MessageText;
|
||||
};
|
||||
```
|
||||
|
||||
**GameplayMessageSubsystem 集成:**
|
||||
|
||||
```cpp
|
||||
// 替换直接调用 PC->ShowDamageNumber(...)
|
||||
// 使用消息通道广播:
|
||||
UGameplayMessageSubsystem::Get(this).BroadcastMessage(
|
||||
RPGGameplayTags::Get().DamageDealt,
|
||||
FRPGDamageMessage{
|
||||
Instigator, Target, Damage, DamageTags
|
||||
}
|
||||
);
|
||||
|
||||
// UI Widget 订阅:
|
||||
UGameplayMessageSubsystem::Get(this).RegisterListener<FRPGDamageMessage>(
|
||||
RPGGameplayTags::Get().DamageDealt,
|
||||
this, &URPGDamageWidget::OnDamageMessage
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 7. 装备系统
|
||||
|
||||
> [!note] 新增功能
|
||||
> 当前插件无装备系统,使用 Lyra 模式新增。
|
||||
|
||||
```cpp
|
||||
// 装备定义(DataAsset)
|
||||
UCLASS(BlueprintType)
|
||||
class URPGEquipmentDefinition : public UObject {
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
TSubclassOf<URPGEquipmentInstance> InstanceType;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
TArray<URPGGameplayAbilitySet*> AbilitySetsToGrant;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
TArray<FRPGEquipmentActorToSpawn> ActorsToSpawn;
|
||||
};
|
||||
|
||||
// 装备实例(运行时)
|
||||
UCLASS(BlueprintType)
|
||||
class URPGEquipmentInstance : public UObject {
|
||||
// 授予的能力句柄
|
||||
FRPGGameplayAbilitySet_GrantedHandles GrantedHandles;
|
||||
|
||||
// 关联的源对象(武器/乐器/道具)
|
||||
UObject* GetInstigator() const;
|
||||
};
|
||||
|
||||
// 装备管理器组件(挂在 Pawn 上)
|
||||
UCLASS()
|
||||
class URPGEquipmentManagerComponent : public UPawnComponent {
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void EquipItem(TSubclassOf<URPGEquipmentDefinition> EquipmentDef);
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void UnequipItem(URPGEquipmentInstance* EquipmentInstance);
|
||||
};
|
||||
|
||||
// 装备能力基类
|
||||
UCLASS()
|
||||
class URPGGameplayAbility_FromEquipment : public URPGGameplayAbility {
|
||||
// 可反查装备实例获取属性/状态
|
||||
URPGEquipmentInstance* GetAssociatedEquipment() const;
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 8. GamePhase 阶段系统
|
||||
|
||||
> [!note] 新增功能
|
||||
> 音乐格斗游戏需要回合管理。
|
||||
|
||||
```cpp
|
||||
UCLASS()
|
||||
class URPGamePhaseSubsystem : public UWorldSubsystem {
|
||||
// 使用层级 GameplayTag 管理阶段
|
||||
// Game.WaitingForPlayers
|
||||
// Game.Countdown
|
||||
// Game.Playing.Round1
|
||||
// Game.Playing.Round1.Break
|
||||
// Game.Playing.Round2
|
||||
// Game.ShowingResult
|
||||
|
||||
void StartPhase(TSubclassOf<URPGamePhaseAbility> PhaseAbility,
|
||||
FRPGamePhaseDelegate PhaseEndedCallback);
|
||||
|
||||
void WhenPhaseStartsOrIsActive(FGameplayTag PhaseTag,
|
||||
EPhaseTagMatchType MatchType,
|
||||
const FRPGamePhaseTagDelegate& WhenActive);
|
||||
|
||||
void WhenPhaseEnds(FGameplayTag PhaseTag,
|
||||
EPhaseTagMatchType MatchType,
|
||||
const FRPGamePhaseTagDelegate& WhenEnd);
|
||||
};
|
||||
|
||||
// 阶段能力
|
||||
UCLASS()
|
||||
class URPGamePhaseAbility : public URPGGameplayAbility {
|
||||
// ReplicationPolicy = ReplicateNo
|
||||
// NetExecutionPolicy = ServerInitiated
|
||||
// NetSecurityPolicy = ServerOnly
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
FGameplayTag GamePhaseTag;
|
||||
};
|
||||
```
|
||||
|
||||
**能力阶段门控:**
|
||||
- `ActivationRequiredTags` 添加 `Game.Playing` → 非 Playing 阶段无法使用能力
|
||||
- `ActivationBlockedTags` 添加 `Game.ShowingResult` → 结果显示时禁用能力
|
||||
- 阶段观察者:音乐播放、UI 切换、生成逻辑
|
||||
|
||||
---
|
||||
|
||||
### 9. 队伍系统
|
||||
|
||||
> [!note] 新增功能
|
||||
> 格斗游戏需要队伍/阵营支持。
|
||||
|
||||
```cpp
|
||||
UCLASS()
|
||||
class URPGTeamSubsystem : public UWorldSubsystem {
|
||||
void ChangeTeamForActor(AActor* Actor, int32 NewTeamId);
|
||||
int32 FindTeamFromObject(UObject* Obj) const;
|
||||
bool CanCauseDamage(AActor* Instigator, AActor* Target) const;
|
||||
|
||||
// 队伍标记栈(跟踪队伍得分等)
|
||||
void AddTeamTagStack(int32 TeamId, FGameplayTag Tag, int32 Count);
|
||||
void RemoveTeamTagStack(int32 TeamId, FGameplayTag Tag, int32 Count);
|
||||
int32 GetTeamTagStackCount(int32 TeamId, FGameplayTag Tag) const;
|
||||
};
|
||||
|
||||
// ILyraTeamAgentInterface 实现
|
||||
class ILyraTeamAgentInterface : public IGenericTeamAgentInterface {
|
||||
FOnLyraTeamIndexChangedDelegate OnTeamChanged;
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 实施路线图
|
||||
|
||||
### 阶段 1:基础改造(低风险、高回报)
|
||||
|
||||
| # | 改动 | 来<><E69DA5><EFBFBD> | 影响范围 |
|
||||
|---|------|------|----------|
|
||||
| 1 | 拆分属性集为 Primary/Combat/Vital/Meta/Progression | Aura | 属性系统 |
|
||||
| 2 | GameplayTag 输入路由替换 EGSAbilityInputID 枚举 | Lyra | 输入/ASC |
|
||||
| 3 | 创建 RPGInputConfig DataAsset + RPGInputComponent | Lyra+Aura | 输入 |
|
||||
| 4 | 实现 AbilitySet DataAsset 模块化能力授予 | Lyra | 能力授予 |
|
||||
|
||||
### 阶段 2:核心改进
|
||||
|
||||
| # | 改动 | 来源 | 影响范围 |
|
||||
|---|------|------|----------|
|
||||
| 5 | 能力激活策略 (OnInputTriggered/WhileInputActive/OnSpawn/OnRhythmBeat) | Lyra | 能力基类 |
|
||||
| 6 | MMC 派生属性计算(含等级缩放) | Aura | 属性系统 |
|
||||
| 7 | 激活组系统(格斗游戏攻击取消) | Lyra | ASC |
|
||||
| 8 | 重构伤害管道(Meta属性 + ExecutionCalc) | Lyra+GASShooter | 伤害 |
|
||||
| 9 | ClientEffectApplied RPC UI 通知 | Aura | ASC/UI |
|
||||
|
||||
### 阶段 3:架构升级
|
||||
|
||||
| # | 改动 | 来源 | 影响范围 |
|
||||
|---|------|------|----------|
|
||||
| 10 | MVVM WidgetController UI 模式 | Aura | UI |
|
||||
| 11 | 拆分 LoadingScreen 为独立插件 | 最佳实践 | 插件结构 |
|
||||
| 12 | GameplayMessageSubsystem 集成(解耦事件) | Lyra | 全局通信 |
|
||||
| 13 | 装备系统(装备 → AbilitySet → ASC) | Lyra | 装备/物品 |
|
||||
| 14 | GamePhase 阶段系统(回合管理) | Lyra | 游戏流程 |
|
||||
|
||||
### 阶段 4:高级特性
|
||||
|
||||
| # | 改动 | 来源 | 影响范围 |
|
||||
|---|------|------|----------|
|
||||
| 15 | TagRelationshipMapping 跨能力阻塞/取消 | Lyra | 能力管理 |
|
||||
| 16 | 组合式能力 Cost 系统 | Lyra | 能力消耗 |
|
||||
| 17 | 队伍子系统 | Lyra | 队伍/阵营 |
|
||||
| 18 | GameFeature 模块化扩展 | Lyra | 插件架构 |
|
||||
| 19 | Save/Load GAS 状态序列化 | 自定义 | 存档 |
|
||||
|
||||
---
|
||||
|
||||
## MusicFighterGame 特有建议
|
||||
|
||||
### 节奏输入系统
|
||||
|
||||
```cpp
|
||||
// 在 ASC 中添加
|
||||
void URPGAbilitySystemComponent::SetCurrentBeatFraction(float BeatFraction) {
|
||||
// 从 FMOD/AudioAnalysis 获取节拍数据
|
||||
CurrentBeatPrecision = CalculateBeatPrecision(BeatFraction);
|
||||
|
||||
if (CurrentBeatPrecision < PerfectThreshold) {
|
||||
// Perfect 判定
|
||||
AddDynamicTagToAllAbilities(RhythmPerfectTag);
|
||||
} else if (CurrentBeatPrecision < GoodThreshold) {
|
||||
// Good 判定
|
||||
AddDynamicTagToAllAbilities(RhythmGoodTag);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 连招系统建议
|
||||
|
||||
```
|
||||
利用 GameplayTag 层级管理连招状态:
|
||||
- Combat.Combo.Hit1 → Combat.Combo.Hit2 → Combat.Combo.Hit3
|
||||
- 每个连招段使用 EffectContainer Map 的不同 Tag
|
||||
- 下一段能力需要上一段的 Tag 作为 ActivationRequiredTag
|
||||
- 节奏加成通过 SetByCaller 修改伤害系数
|
||||
```
|
||||
|
||||
### 乐器/武器即 AbilitySource
|
||||
|
||||
```
|
||||
游戏中的乐器(吉他、贝斯、鼓、键盘)作为 Equipment:
|
||||
- 每个乐器有独立的 AbilitySet
|
||||
- 不同乐器授予不同的攻击模式和效果
|
||||
- 节奏精准度影响伤害倍率
|
||||
- 装备管理器处理乐器切换
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 对比总结
|
||||
|
||||
| 系统 | 当前状态 | 目标状态 | 参考来源 |
|
||||
|------|----------|----------|----------|
|
||||
| 输入路由 | 硬编码枚举 | GameplayTag 驱动 | Lyra |
|
||||
| 属性系统 | 单一 18 属性集 | 5 个分层属性集 + MMC | Aura |
|
||||
| 能力配置 | CharacterAbilities 数组 | AbilitySet DataAsset | Lyra |
|
||||
| UI 模式 | 直接 Push | MVVM WidgetController | Aura |
|
||||
| 伤害计算 | ExecutionCalc + AttributeSet 混用 | 完整 Meta 属性管道 | Lyra+GASShooter |
|
||||
| 插件模块 | 5 模块混装 | 核心 + 独立 LoadingScreen | 最佳实践 |
|
||||
| 装备系统 | 无 | 装备 → AbilitySet → ASC | Lyra |
|
||||
| 阶段管理 | 无 | 层级 Tag GamePhase 子系统 | Lyra |
|
||||
| 队伍系统 | 无 | TeamSubsystem + TeamAgent | Lyra |
|
||||
| 消息通信 | 已引入未使用 | GameplayMessageSubsystem 全系统集成 | Lyra |
|
||||
| 多 Mesh 蒙太奇 | ✅ 已实现 | 保留并优化 | GASShooter |
|
||||
| EffectContainer | ✅ 已实现 | 保留并扩展类型 | GASShooter |
|
||||
| RPC 批处理 | ✅ 已实现 | 保留 | GASShooter |
|
||||
|
||||
---
|
||||
|
||||
## 附录
|
||||
|
||||
### 参考项目文件索引
|
||||
|
||||
**LyraStarterGame:**
|
||||
- `Source/LyraGame/AbilitySystem/LyraAbilitySystemComponent.h` - ASC 标签输入 + 激活组
|
||||
- `Source/LyraGame/AbilitySystem/Abilities/LyraGameplayAbility.h` - 能力基类 + 策略
|
||||
- `Source/LyraGame/AbilitySystem/LyraAbilitySet.h` - AbilitySet DataAsset
|
||||
- `Source/LyraGame/AbilitySystem/Phases/LyraGamePhaseSubsystem.h` - 阶段子系统
|
||||
- `Source/LyraGame/AbilitySystem/Attributes/LyraHealthSet.h` - 元属性模式
|
||||
- `Source/LyraGame/Equipment/LyraEquipmentDefinition.h` - 装备定义
|
||||
- `Source/LyraGame/Input/LyraInputConfig.h` - 输入 DataAsset
|
||||
- `Source/LyraGame/GameFeatures/GameFeatureAction_AddAbilities.h` - 模块化能力授予
|
||||
- `Plugins/GameplayMessageRouter/Source/.../GameplayMessageSubsystem.h` - 消息系统
|
||||
|
||||
**GASShooter:**
|
||||
- `Source/GASShooter/Characters/Abilities/GSAbilitySystemComponent.h` - 多 Mesh ASC
|
||||
- `Source/GASShooter/Characters/Abilities/GSGameplayAbility.h` - 能力基类
|
||||
- `Source/GASShooter/Characters/Abilities/AttributeSets/GSAttributeSetBase.h` - 属性集
|
||||
- `Source/GASShooter/Characters/Abilities/GSDamageExecutionCalc.cpp` - 伤害计算
|
||||
- `Source/GASShooter/Characters/Abilities/GSAbilityTypes.h` - EffectContainer
|
||||
- `Source/GASShooter/Weapons/GSWeapon.h` - 武器系统
|
||||
- `Source/GASShooter/Characters/Abilities/GSGATA_Trace.h` - 瞄准系统
|
||||
|
||||
**UE5_GAS_Aura:**
|
||||
- `Source/Aura/Public/AbilitySystem/AuraAbilitySystemComponent.h` - Tag 输入 ASC
|
||||
- `Source/Aura/Public/AbilitySystem/AuraAttributeSet.h` - 三层属性集 + TagsToAttributes
|
||||
- `Source/Aura/Public/AbilitySystem/Abilities/AuraGameplayAbility.h` - 能力基类
|
||||
- `Source/Aura/Public/AbilitySystem/ModMagCalc/MMC_MaxHealth.cpp` - MMC 示例
|
||||
- `Source/Aura/Public/Input/AuraInputConfig.h` - 输入 DataAsset
|
||||
- `Source/Aura/Public/Input/AuraInputComponent.h` - 输入组件模板
|
||||
- `Source/Aura/Public/UI/WidgetController/AuraWidgetController.h` - WidgetController 基类
|
||||
- `Source/Aura/Public/UI/WidgetController/OverlayWidgetController.cpp` - UI 绑定示例
|
||||
- `Source/Aura/Public/UI/WidgetController/AttributeMenuWidgetController.cpp` - 动态属性菜单
|
||||
- `Source/Aura/Public/UI/HUD/AuraHUD.h` - HUD 工厂
|
||||
|
||||
---
|
||||
|
||||
> 本文档基于 2024-05-30 对三个参考项目的深度代码分析编写。
|
||||
> 所有推荐模式均已在对应项目中验证可行。
|
||||
File diff suppressed because it is too large
Load Diff
299
07-Other/AI/AI Agent/UnrealEngine/UI/Figma MCP =》OpenDesign.md
Normal file
299
07-Other/AI/AI Agent/UnrealEngine/UI/Figma MCP =》OpenDesign.md
Normal file
@@ -0,0 +1,299 @@
|
||||
- MCP & Skill
|
||||
- ClaudeCode:
|
||||
- https://developers.figma.com/docs/figma-mcp-server/remote-server-installation/#claude-code
|
||||
- https://claude.com/plugins/figma
|
||||
- CodeX Skill:
|
||||
- https://developers.figma.com/docs/figma-mcp-server/remote-server-installation/#claude-code
|
||||
- https://github.com/openai/skills/blob/main/skills/.curated/figma-implement-design/SKILL.md
|
||||
|
||||
|
||||
|
||||
# Skill
|
||||
---
|
||||
name: ui-review
|
||||
description: "使用 Chrome DevTools MCP + Figma MCP 对 Web 页面进行自动化 UI 走查,对比 Figma 设计稿与实际页面的字体、颜色、间距、布局等差异,检测响应式溢出问题,生成含 CSS 选择器和修复代码的 Bug 清单。当用户提到 UI 走查、设计还原度检查、对比设计稿、帮我走查页面、页面和设计稿对不上、CSS 样式不对、像素级还原、检查页面实现、视觉回归、前端还原度、responsive 问题、移动端适配检查、设计稿 diff 时触发。即使用户只说"帮我看看这个页面"或"这个实现和设计稿差多少",只要涉及设计稿与实现的对比,都应该触发本技能。"
|
||||
user-invokable: true
|
||||
args:
|
||||
- name: figma-url
|
||||
description: Figma 设计稿链接(含 fileKey 和 nodeId)
|
||||
required: true
|
||||
- name: page-url
|
||||
description: 要走查的实际页面 URL
|
||||
required: true
|
||||
- name: breakpoints
|
||||
description: "要测试的响应式断点,默认: 375,768,1440"
|
||||
required: false
|
||||
---
|
||||
|
||||
# UI 走查 Skill — Chrome DevTools MCP + Figma MCP
|
||||
|
||||
通过 AI 连接真实浏览器和 Figma 设计稿,自动化完成 UI 走查工作。产出一份开发可直接使用的 Bug 修复清单。
|
||||
|
||||
走查的核心价值在于**发现实现与设计的偏差**——这些偏差在开发时往往难以察觉,但会累积成用户可感知的粗糙感。本技能通过结构化流程确保不遗漏。
|
||||
|
||||
---
|
||||
|
||||
## 第零步:环境检查
|
||||
|
||||
走查依赖两个 MCP Server。如果工具列表中缺少对应工具,引导用户配置。
|
||||
|
||||
### Chrome DevTools MCP
|
||||
|
||||
需要 `take_screenshot`、`take_snapshot`、`evaluate_script`、`navigate_page` 等工具。如果缺失:
|
||||
|
||||
1. 安装:`npm install -g chrome-devtools-mcp@latest`(需 Node.js >= 20.19.0)
|
||||
2. 在 `.vscode/mcp.json` 中添加:
|
||||
```json
|
||||
{ "servers": { "chrome-devtools": { "command": "npx", "args": ["-y", "chrome-devtools-mcp@latest"], "type": "stdio" } } }
|
||||
```
|
||||
3. `Cmd+Shift+P` → `Reload Window`,确认 MCP 启用
|
||||
|
||||
### Figma MCP
|
||||
|
||||
需要 `get_figma_data`、`download_figma_images` 工具。如果缺失:
|
||||
|
||||
1. 获取 API Key:Figma → 头像 → Settings → Personal access tokens → 生成
|
||||
2. 在 `.vscode/mcp.json` 中添加:
|
||||
```json
|
||||
{
|
||||
"servers": {
|
||||
"figma": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "figma-developer-mcp", "--stdio"],
|
||||
"env": {
|
||||
"FIGMA_API_KEY": "<替换为你的 Figma API Key>"
|
||||
},
|
||||
"type": "stdio"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
3. `Cmd+Shift+P` → `Reload Window`,确认 MCP 启用
|
||||
|
||||
两个 MCP 都就绪后,进入走查流程。
|
||||
|
||||
---
|
||||
|
||||
## 第一步:需求确认与走查规划
|
||||
|
||||
### 1.1 确认走查范围
|
||||
|
||||
向用户确认:
|
||||
- **走查页面**:单页面还是多步骤流程(如弹窗步骤 1→2→3→完成)?
|
||||
- **是否需要登录**:需要则请用户提供测试账号
|
||||
- **交互前置条件**:如"点击按钮后出现弹窗"
|
||||
- **关注的断点**:默认 375px / 768px / 1440px,可自定义
|
||||
- **输出格式**:HTML 报告(含一键复制、可局域网分享)或 Markdown(适合 Git/飞书/Notion)
|
||||
|
||||
### 1.2 多步骤流程规划
|
||||
|
||||
如果是多步骤流程,列出所有步骤,每个步骤都在**桌面端和移动端**分别走查:
|
||||
|
||||
```
|
||||
例:艺术家入驻流程
|
||||
├── 步骤 0: 欢迎弹窗
|
||||
├── 步骤 1: 行为准则
|
||||
├── 步骤 2: 基本信息 1/3
|
||||
└── 步骤 3: 完成页
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 第二步:获取设计稿数据
|
||||
|
||||
从 Figma URL 提取 `fileKey` 和 `nodeId`,用 `get_figma_data` 获取设计数据。
|
||||
|
||||
重点提取的属性(这些是设计还原度对比的基准):
|
||||
|
||||
| 类别 | 属性 |
|
||||
|------|------|
|
||||
| 字体 | fontFamily, fontSize, fontWeight, lineHeight, letterSpacing |
|
||||
| 颜色 | fill colors, text colors(记录 HEX 值和 Design Token 名) |
|
||||
| 间距 | padding, gap, itemSpacing |
|
||||
| 圆角 | cornerRadius |
|
||||
| 尺寸 | width, height |
|
||||
| 布局 | layoutMode, layoutAlign |
|
||||
| 效果 | effects (shadow), strokes |
|
||||
|
||||
如果 Figma 有多端设计(移动端/桌面端分开),需分别获取对应的 nodeId。记录 Design Token 名称(如 `--color-primary`),报告中会用到。
|
||||
|
||||
---
|
||||
|
||||
## 第三步:获取实际页面数据
|
||||
|
||||
### 3.1 导航与登录
|
||||
|
||||
用 `navigate_page` 打开目标 URL(timeout: 60000)。
|
||||
|
||||
SPA 应用常超时但页面已加载——超时后先用 `list_pages` + `take_screenshot` 确认状态,不必盲目重试。
|
||||
|
||||
登录流程:`take_snapshot` → `fill` 表单 → `click` 登录 → `wait_for` 成功标志 → 导航到目标页。
|
||||
|
||||
### 3.2 多步骤交互
|
||||
|
||||
弹窗/模态框需先触发才能看到。流程:`take_snapshot` 找触发按钮 → `click` → 等待弹窗出现 → 截图+提取样式。
|
||||
|
||||
> ⚠️ SPA 中弹窗可能不响应普通 click。遇到此情况时,阅读 `references/troubleshooting.md` 中的"SPA 弹窗交互"章节获取详细解决方案(包括 Vue/React 组件直接调用、移动端行为差异等)。
|
||||
|
||||
### 3.3 截图
|
||||
|
||||
- 视口截图:`take_screenshot`
|
||||
- 全页截图:`take_screenshot({ fullPage: true })`
|
||||
- 始终用 `filePath` 保存到 `screenshots/`,命名规则:
|
||||
```
|
||||
d01-welcome-desktop.png ← 桌面端
|
||||
m01-welcome-mobile.png ← 移动端
|
||||
```
|
||||
截图是 Bug 报告的证据,会嵌入最终报告。
|
||||
|
||||
### 3.4 提取样式
|
||||
|
||||
用 `evaluate_script` 注入 JavaScript 提取关键元素的 computed styles。需覆盖:标题(h1-h4)、正文(p, span)、按钮(button, a)、容器(section, [class*=card])、表单(input, textarea, select)、图片(img)、弹窗外层容器。
|
||||
|
||||
> 📄 高效提取脚本见 `references/extract-styles.md`——一次调用即可获取弹窗内所有元素的样式,避免多次 evaluate_script。
|
||||
|
||||
---
|
||||
|
||||
## 第四步:逐项对比 — 设计还原度
|
||||
|
||||
这是走查的**核心工作**。
|
||||
|
||||
### 4.1 先抓全局,再看局部
|
||||
|
||||
在逐页对比之前,先扫描所有页面中**反复出现的组件**。如果某个组件在所有页面中有相同偏差,记录为**全局问题(Global Issue)**,只写一次。这样做是因为全局组件的修复只需改一处 CSS,在每页重复报告只会让开发者困惑。
|
||||
|
||||
常见全局组件:XXL 按钮、标准输入框、文本域、弹窗容器、标签/徽章。
|
||||
|
||||
识别方法:第一页提取样式 → 对比 Figma → 如有偏差,后续页面验证是否一致 → 一致则为全局问题。
|
||||
|
||||
### 4.2 对比维度与容差
|
||||
|
||||
| 检查项 | 容差标准 | 说明 |
|
||||
|--------|---------|------|
|
||||
| fontFamily | 精确匹配 | 字体族必须完全一致 |
|
||||
| fontSize | ≤1px | 亚像素渲染可能有微小差异 |
|
||||
| fontWeight | 精确匹配 | 400 vs 500 视觉差异明显 |
|
||||
| lineHeight | ≤2px | 行高差 1-2px 在正文中不易察觉 |
|
||||
| letterSpacing | ≤0.5px | 字间距非常敏感 |
|
||||
| color (RGB各通道) | ≤5 | 颜色管理可能引入微小偏差 |
|
||||
| padding/margin/gap | ≤2px | 盒模型差异在 2px 内可接受 |
|
||||
| borderRadius | 精确匹配 | 圆角差异视觉上很明显 |
|
||||
| box-shadow | 逐项对比 x/y/blur/spread/color | 阴影差异需要拆开比较 |
|
||||
|
||||
对比时注意带透明度的颜色(如 `rgba(28,28,30,0.2)`),alpha 值也要比较。
|
||||
|
||||
**凡是超出容差的,全部记录为 Bug,包含:Figma 值 → 实际值、CSS 选择器、可复制的修复代码。**
|
||||
|
||||
---
|
||||
|
||||
## 第五步:响应式走查
|
||||
|
||||
用 `emulate` 模拟不同断点:
|
||||
|
||||
```
|
||||
emulate({ viewport: "375x812x2,mobile,touch" }) // 手机
|
||||
emulate({ viewport: "768x1024x2,mobile,touch" }) // 平板
|
||||
emulate({ viewport: "1440x900x1" }) // 桌面
|
||||
```
|
||||
|
||||
每个断点执行:
|
||||
1. **全页截图** — 记录布局
|
||||
2. **溢出检测** — 水平溢出是移动端最常见的 Bug,用 `evaluate_script` 检查 `scrollWidth > innerWidth` 的元素
|
||||
3. **字号梯度** — 标题在不同断点下字号变化应平滑
|
||||
4. **布局断点** — 卡片网格列数、导航折叠是否合理
|
||||
|
||||
### 移动端深度检查(375px)
|
||||
|
||||
移动端不能只看截图,以下问题截图中看不出来:
|
||||
|
||||
| 检查项 | 原因 | 检测方法 |
|
||||
|--------|------|----------|
|
||||
| 弹窗 max-height ≤ 80vh | 超出会被系统裁剪,用户无法操作 | 检查 `.modal` computedStyle.maxHeight |
|
||||
| 弹窗内部滚动 | 内容溢出时弹窗应内滚,而非页面滚 | 检查 `overflow-y: auto/scroll` |
|
||||
| 遮罩层 z-index | header/footer 可能穿透遮罩 | 对比 z-index |
|
||||
| 动画溢出 | 庆祝动画常产生水平滚动条 | 检查容器 `overflow: hidden` |
|
||||
| 触摸区域 ≥ 44×44px | Apple HIG 最低要求 | 提取 offsetWidth/Height |
|
||||
| Safe Area | iOS 刘海屏遮挡 | 检查 `env(safe-area-inset-*)` |
|
||||
| 图片缩放 | 避免拉伸变形 | 检查 `object-fit` |
|
||||
|
||||
---
|
||||
|
||||
## 第六步:生成 Bug 修复清单
|
||||
|
||||
### 输出原则
|
||||
|
||||
- **精简、可执行**:开发拿到就能改,不做鼓励、不做设计评审
|
||||
- **每个 Bug 附修复代码**:含 CSS 选择器和可复制代码
|
||||
- **全局问题只写一次**:页面级 Bug 只注明"受 G1 影响"
|
||||
|
||||
### 优先级
|
||||
|
||||
| 级别 | 定义 |
|
||||
|------|------|
|
||||
| **P0** | 设计还原度差异 + 影响用户体验(字体/颜色/间距不一致;全断点溢出) |
|
||||
| **P1** | 建议修复(某些断点溢出;缺交互反馈) |
|
||||
| **P2** | 可优化(布局建议;排版优化) |
|
||||
|
||||
### 报告结构
|
||||
|
||||
```
|
||||
📋 UI 走查报告
|
||||
├── 🌐 全局问题(Global Issues)
|
||||
├── 📄 页面/步骤 N: [名称](P0 → P1 → P2 排序)
|
||||
├── 📱 移动端专项检查(375px)
|
||||
└── 📊 溢出检测汇总表(元素 × 断点矩阵)
|
||||
```
|
||||
|
||||
### Bug 卡片格式
|
||||
|
||||
```
|
||||
#编号 Bug 标题 [P0/P1/P2]
|
||||
问题描述(元素 / CSS 选择器 / 影响断点)
|
||||
[标签: 还原度 / 响应式 / 体验]
|
||||
Figma: xxx → 实际: yyy
|
||||
📸 screenshots/d01-xxx.png
|
||||
修复代码(可直接复制)
|
||||
```
|
||||
|
||||
### HTML 报告(默认)
|
||||
|
||||
单文件 HTML,含:页头信息、全局问题区、分步 Bug 卡片(一键复制按钮)、截图嵌入、移动端专项、溢出矩阵。报告本身也应响应式。可通过 `python3 -m http.server 9090 --bind 0.0.0.0` 局域网分享。
|
||||
|
||||
### Markdown 报告
|
||||
|
||||
标准 GFM 格式,截图用相对路径引用 `screenshots/`,适合 Git/飞书/Notion。
|
||||
|
||||
---
|
||||
|
||||
## 走查范围
|
||||
|
||||
### ✅ 必须关注
|
||||
|
||||
1. **设计还原度**:任何与 Figma 的偏差(字体/颜色/间距/圆角/阴影/尺寸)
|
||||
2. **全局组件一致性**:按钮、输入框、弹窗等全站统一组件
|
||||
3. **响应式布局**:各断点溢出、布局断裂、内容裁剪
|
||||
4. **移动端交互**:弹窗高度、内部滚动、触摸区域、z-index
|
||||
5. **图标还原**:设计稿矢量图标 vs 实现用 emoji/位图
|
||||
6. **表单元素**:输入框/文本域/下拉框的边框/圆角/颜色
|
||||
7. **动画溢出**:过渡效果产生意外滚动条
|
||||
|
||||
### ❌ 不关注
|
||||
|
||||
1. 测试环境特有内容(vConsole、测试数据)
|
||||
2. 设计决策(对比度、文案、配色——那是设计过程的决定)
|
||||
3. 功能逻辑(业务逻辑是功能测试的工作)
|
||||
4. 后端数据正确性
|
||||
5. 浏览器兼容性(除非用户明确要求)
|
||||
6. 性能、SEO、可访问性(除非用户明确要求)
|
||||
|
||||
---
|
||||
|
||||
## 参考文件
|
||||
|
||||
遇到以下场景时,阅读对应的参考文件:
|
||||
|
||||
| 场景 | 参考文件 |
|
||||
|------|---------|
|
||||
| SPA 弹窗不弹出、导航超时、页面太多 | `references/troubleshooting.md` |
|
||||
| 需要批量提取 CSS 样式的 JS 脚本 | `references/extract-styles.md` |
|
||||
| 走查过程中对照检查项清单 | `references/checklist.md` |
|
||||
@@ -0,0 +1,99 @@
|
||||
---
|
||||
tags:
|
||||
- windows
|
||||
- claude-code
|
||||
- tooling
|
||||
created: 2026-05-31
|
||||
---
|
||||
# Windows Terminal 快捷方式启动 Claude Code 项目
|
||||
|
||||
## 原理
|
||||
|
||||
桌面快捷方式(`.lnk`)先启动 Windows Terminal,再由 Windows Terminal 的 Profile 定义工作目录和启动命令,最终自动进入指定项目的 Claude Code 会话。
|
||||
|
||||
```
|
||||
桌面快捷方式 (.lnk)
|
||||
→ wt.exe -p "ProfileName"
|
||||
→ Windows Terminal 读取 settings.json 中对应 Profile
|
||||
→ cmd.exe /k "cd 项目目录 && claude --dangerously-skip-permissions"
|
||||
→ Claude Code 启动,进入交互会话
|
||||
```
|
||||
|
||||
## 两层结构
|
||||
|
||||
### 1. Windows Terminal Profile(settings.json)
|
||||
|
||||
位置:`%LOCALAPPDATA%\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json`
|
||||
|
||||
每个项目一个 Profile,例如:
|
||||
|
||||
```json
|
||||
{
|
||||
"guid": "{30e2bee9-2311-49a4-9798-fe50e1fb872e}",
|
||||
"name": "AIDM",
|
||||
"commandline": "cmd.exe /k \"cd /d D:\\MatrixTA\\AIGameDev\\AIDM && set CLAUDE_CODE_DISABLE_TERMINAL_TITLE=1 && claude --dangerously-skip-permissions\"",
|
||||
"startingDirectory": "D:\\MatrixTA\\AIGameDev\\AIDM",
|
||||
"tabColor": "#16A34A",
|
||||
"suppressApplicationTitle": true,
|
||||
"icon": "🎮",
|
||||
"hidden": false
|
||||
}
|
||||
```
|
||||
|
||||
字段说明:
|
||||
|
||||
| 字段 | 作用 |
|
||||
|------|------|
|
||||
| `guid` | 唯一标识,内部匹配用 |
|
||||
| `name` | 显示在下拉菜单和标签页标题,也是 `-p` 参数的匹配值 |
|
||||
| `commandline` | 实际执行的命令,通过 `cmd.exe /k` 保证窗口保持 |
|
||||
| `startingDirectory` | 初始工作目录 |
|
||||
| `tabColor` | 标签页颜色,方便区分项目 |
|
||||
| `suppressApplicationTitle` | 禁止应用修改终端标题 |
|
||||
| `icon` | 标签页图标(emoji) |
|
||||
|
||||
### 2. 桌面快捷方式(.lnk)
|
||||
|
||||
PowerShell 创建方式:
|
||||
|
||||
```powershell
|
||||
$shell = New-Object -ComObject WScript.Shell
|
||||
$desktop = [Environment]::GetFolderPath('Desktop')
|
||||
$shortcut = $shell.CreateShortcut("$desktop\AIDM.lnk")
|
||||
$shortcut.TargetPath = "C:\Users\loujiajie\AppData\Local\Microsoft\WindowsApps\wt.exe"
|
||||
$shortcut.Arguments = '-p "AIDM"'
|
||||
$shortcut.WorkingDirectory = "D:\MatrixTA\AIGameDev\AIDM"
|
||||
$shortcut.Save()
|
||||
```
|
||||
|
||||
字段说明:
|
||||
|
||||
| 属性 | 值 | 说明 |
|
||||
|------|-----|------|
|
||||
| `TargetPath` | `wt.exe` 完整路径 | Windows Terminal 可执行文件 |
|
||||
| `Arguments` | `-p "ProfileName"` | 匹配 settings.json 中 Profile 的 `name` 字段 |
|
||||
| `WorkingDirectory` | 项目目录 | 与 Profile 中的 `startingDirectory` 一致 |
|
||||
|
||||
## 新增项目的步骤
|
||||
|
||||
> [!note] 完整流程
|
||||
> 1. 在 `settings.json` 的 `profiles.list` 数组中添加新 Profile
|
||||
> 2. 生成新的 GUID(PowerShell: `[guid]::NewGuid()`)
|
||||
> 3. 创建桌面 `.lnk` 快捷方式指向 `wt.exe -p "新Profile名"`
|
||||
|
||||
## 已有项目 Profile 一览
|
||||
|
||||
| 项目 | Tab 颜色 | 图标 | 目录 |
|
||||
|------|----------|------|------|
|
||||
| CharacterMaker | `#1E3CB4` (蓝) | 🔥 | `D:\AI\Website\CharacterMaker` |
|
||||
| AIDM | `#16A34A` (绿) | 🎮 | `D:\MatrixTA\AIGameDev\AIDM` |
|
||||
| POPODocs | `#0078D7` (蓝) | 📄 | `D:\AI\Skill\MatrixAITA-POPODocs-Skill` |
|
||||
| NeteaseAITA_Artlib | `#808080` (灰) | 🎨 | `D:\AI\Website\NeteaseAITA_Artlib` |
|
||||
|
||||
## 关键细节
|
||||
|
||||
- **`cmd.exe /k`**:执行完后续命令后保持窗口不关闭,用户可继续交互
|
||||
- **`--dangerously-skip-permissions`**:跳过 Claude Code 的权限提示,适合本地开发
|
||||
- **`CLAUDE_CODE_DISABLE_TERMINAL_TITLE=1`**:禁止 Claude Code 修改终端标题,保持 Profile 名称显示
|
||||
- **`suppressApplicationTitle: true`**:配合上一条,双重保障标题不被覆盖
|
||||
- **GUID 必须唯一**:每个 Profile 的 `guid` 用于内部匹配,`name` 用于 `-p` 参数匹配
|
||||
Reference in New Issue
Block a user