Project02/ProjectFish/Docs/TutorialSystemDesign.md

1060 lines
28 KiB
Markdown
Raw Normal View History

2025-11-24 10:58:30 +08:00
# 新手引导系统设计文档
## 一、系统整体架构
### 1.1 核心组件
```
TutorialSystem/
├── TutorialSubsystem (UGameInstanceSubsystem)
│ ├── 管理引导流程状态
│ ├── 协调各个系统的引导行为
│ └── 持久化引导进度
├── TutorialStepAsset (UDataAsset)
│ ├── 定义每个引导步骤的配置
│ ├── 触发条件和完成条件
│ └── UI显示配置
├── TutorialUIController (UObject)
│ ├── 管理UI遮罩层
│ ├── 控制高亮区域
│ └── 显示引导提示
├── TutorialModeInterface (Interface)
│ ├── UI组件实现此接口
│ ├── 提供正常模式/引导模式切换
│ └── 提供UI元素过滤逻辑
└── TutorialEventListener (UObject)
├── 监听游戏事件
├── 触发引导步骤推进
└── 验证玩家操作
```
### 1.2 数据流设计
```
TutorialSubsystem (中央控制器)
├→ TutorialStepAsset (步骤配置)
├→ TutorialUIController (UI控制)
├→ QuestManager (任务系统集成)
├→ DialogueAsset (对话系统集成)
├→ FishingMapSubSystem (地图系统集成)
└→ GameInfoManager (进度存档)
```
---
## 二、核心系统设计
### 2.1 引导子系统 (TutorialSubsystem)
#### 头文件结构
```cpp
// TutorialSubsystem.h
#pragma once
#include "CoreMinimal.h"
#include "Subsystems/GameInstanceSubsystem.h"
#include "TutorialSubsystem.generated.h"
// 引导步骤状态
UENUM(BlueprintType)
enum class ETutorialStepState : uint8
{
NotStarted, // 未开始
InProgress, // 进行中
WaitingForUser, // 等待用户操作
Completed // 已完成
};
// 引导步骤类型
UENUM(BlueprintType)
enum class ETutorialStepType : uint8
{
Dialogue, // 对话步骤
UIInteraction, // UI交互步骤
Gameplay, // 游戏玩法步骤
Battle, // 战斗步骤
Custom // 自定义步骤
};
// 引导事件委托
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnTutorialStepChanged, int32, StepIndex, ETutorialStepState, NewState);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnTutorialModeChanged, bool, bInTutorialMode);
UCLASS()
class PROJECTFISH_API UTutorialSubsystem : public UGameInstanceSubsystem
{
GENERATED_BODY()
public:
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
virtual void Deinitialize() override;
// 引导控制
UFUNCTION(BlueprintCallable, Category = "Tutorial")
void StartTutorial();
UFUNCTION(BlueprintCallable, Category = "Tutorial")
void StopTutorial();
UFUNCTION(BlueprintCallable, Category = "Tutorial")
void AdvanceToNextStep();
UFUNCTION(BlueprintCallable, Category = "Tutorial")
void CompleteCurrentStep();
UFUNCTION(BlueprintCallable, Category = "Tutorial")
bool IsInTutorialMode() const { return bInTutorialMode; }
UFUNCTION(BlueprintCallable, Category = "Tutorial")
int32 GetCurrentStepIndex() const { return CurrentStepIndex; }
// 条件检查
UFUNCTION(BlueprintCallable, Category = "Tutorial")
bool CanShowUIElement(FName ElementTag) const;
UFUNCTION(BlueprintCallable, Category = "Tutorial")
bool ShouldHighlightUIElement(FName ElementTag) const;
// 事件委托
UPROPERTY(BlueprintAssignable, Category = "Tutorial")
FOnTutorialStepChanged OnTutorialStepChanged;
UPROPERTY(BlueprintAssignable, Category = "Tutorial")
FOnTutorialModeChanged OnTutorialModeChanged;
protected:
// 引导步骤列表
UPROPERTY(EditDefaultsOnly, Category = "Tutorial")
TArray<class UTutorialStepAsset*> TutorialSteps;
// 当前状态
UPROPERTY()
bool bInTutorialMode = false;
UPROPERTY()
int32 CurrentStepIndex = -1;
UPROPERTY()
ETutorialStepState CurrentStepState = ETutorialStepState::NotStarted;
// UI控制器
UPROPERTY()
class UTutorialUIController* UIController;
private:
void ExecuteStep(int32 StepIndex);
void OnStepCompleted();
};
```
---
### 2.2 引导步骤资产 (TutorialStepAsset)
#### 数据资产设计
```cpp
// TutorialStepAsset.h
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataAsset.h"
#include "TutorialStepAsset.generated.h"
// UI元素过滤配置
USTRUCT(BlueprintType)
struct FTutorialUIFilter
{
GENERATED_BODY()
// 可见的UI元素标签列表
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TArray<FName> VisibleElementTags;
// 高亮的UI元素标签
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TArray<FName> HighlightedElementTags;
// 可交互的UI元素标签
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TArray<FName> InteractableElementTags;
// 是否使用黑名单模式(默认白名单)
UPROPERTY(EditAnywhere, BlueprintReadWrite)
bool bUseBlacklist = false;
};
// 引导提示配置
USTRUCT(BlueprintType)
struct FTutorialHintConfig
{
GENERATED_BODY()
// 提示文本
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FText HintText;
// 提示位置锚定到某个UI元素
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FName AnchorElementTag;
// 提示偏移
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FVector2D Offset = FVector2D::ZeroVector;
// 箭头指向
UPROPERTY(EditAnywhere, BlueprintReadWrite)
bool bShowArrow = true;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FVector2D ArrowDirection = FVector2D(0, 1);
};
// 完成条件类型
UENUM(BlueprintType)
enum class ETutorialCompletionType : uint8
{
Manual, // 手动完成(代码调用)
UIClick, // 点击指定UI
TaskCompleted, // 任务完成
DialogueFinished, // 对话结束
BattleWon, // 战斗胜利
ItemCollected, // 收集物品
LocationReached // 到达位置
};
// 完成条件配置
USTRUCT(BlueprintType)
struct FTutorialCompletionCondition
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
ETutorialCompletionType CompletionType;
// 条件参数(根据类型不同含义不同)
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FName ConditionParameter;
// 数值参数
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 NumericParameter = 1;
};
UCLASS(BlueprintType)
class PROJECTFISH_API UTutorialStepAsset : public UDataAsset
{
GENERATED_BODY()
public:
// 步骤基本信息
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Basic")
FName StepID;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Basic")
FText StepName;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Basic")
ETutorialStepType StepType;
// UI过滤配置
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI")
FTutorialUIFilter UIFilter;
// 引导提示
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI")
FTutorialHintConfig HintConfig;
// 完成条件
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Completion")
FTutorialCompletionCondition CompletionCondition;
// 对话资产(如果是对话步骤)
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Dialogue")
class UDialogueAsset* DialogueAsset;
// 特殊地图配置(如果需要)
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Map")
class UMapConfigAsset* OverrideMapConfig;
// 特殊战斗配置
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Battle")
class UFishInfoConfigAsset* OverrideFishConfig;
// 自动进入下一步的延迟时间(秒)
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Flow")
float AutoAdvanceDelay = 0.0f;
// 是否在此步骤暂停游戏
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Flow")
bool bPauseGame = false;
};
```
---
### 2.3 UI引导控制器 (TutorialUIController)
```cpp
// TutorialUIController.h
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "TutorialUIController.generated.h"
UCLASS()
class PROJECTFISH_API UTutorialUIController : public UObject
{
GENERATED_BODY()
public:
// 创建遮罩层
UFUNCTION(BlueprintCallable, Category = "Tutorial UI")
void ShowMaskOverlay();
UFUNCTION(BlueprintCallable, Category = "Tutorial UI")
void HideMaskOverlay();
// 高亮指定区域
UFUNCTION(BlueprintCallable, Category = "Tutorial UI")
void HighlightWidget(UWidget* TargetWidget, float Padding = 10.0f);
UFUNCTION(BlueprintCallable, Category = "Tutorial UI")
void ClearHighlight();
// 显示引导提示
UFUNCTION(BlueprintCallable, Category = "Tutorial UI")
void ShowHint(const FTutorialHintConfig& HintConfig);
UFUNCTION(BlueprintCallable, Category = "Tutorial UI")
void HideHint();
protected:
// 遮罩Widget类
UPROPERTY(EditDefaultsOnly, Category = "Tutorial UI")
TSubclassOf<class UUserWidget> MaskOverlayClass;
// 提示Widget类
UPROPERTY(EditDefaultsOnly, Category = "Tutorial UI")
TSubclassOf<class UUserWidget> HintWidgetClass;
UPROPERTY()
class UUserWidget* MaskOverlayWidget;
UPROPERTY()
class UUserWidget* HintWidget;
};
```
---
### 2.4 UI引导接口 (ITutorialModeInterface)
```cpp
// TutorialModeInterface.h
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "TutorialModeInterface.generated.h"
UINTERFACE(MinimalAPI, Blueprintable)
class UTutorialModeInterface : public UInterface
{
GENERATED_BODY()
};
class PROJECTFISH_API ITutorialModeInterface
{
GENERATED_BODY()
public:
// 切换到引导模式
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Tutorial")
void EnterTutorialMode(const FTutorialUIFilter& Filter);
// 退出引导模式
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Tutorial")
void ExitTutorialMode();
// 检查元素是否应该显示
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Tutorial")
bool ShouldShowElement(FName ElementTag) const;
// 检查元素是否应该高亮
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Tutorial")
bool ShouldHighlightElement(FName ElementTag) const;
// 设置元素Tag在UI组件中实现
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Tutorial")
void SetElementTag(FName Tag);
};
```
---
## 三、UI双模式实现方案
### 3.1 基础Widget改造
所有需要参与引导的Widget都应该
1. 实现 `ITutorialModeInterface` 接口
2. 为关键子控件设置 `ElementTag`
3. 在引导模式下动态控制显示/隐藏
#### 改造示例家园UI
```cpp
// HomeUIWidget.h
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "TutorialModeInterface.h"
#include "HomeUIWidget.generated.h"
UCLASS()
class PROJECTFISH_API UHomeUIWidget : public UUserWidget, public ITutorialModeInterface
{
GENERATED_BODY()
public:
virtual void NativeConstruct() override;
// ITutorialModeInterface implementation
virtual void EnterTutorialMode_Implementation(const FTutorialUIFilter& Filter) override;
virtual void ExitTutorialMode_Implementation() override;
virtual bool ShouldShowElement_Implementation(FName ElementTag) const override;
virtual bool ShouldHighlightElement_Implementation(FName ElementTag) const override;
protected:
// UI元素绑定
UPROPERTY(meta = (BindWidget))
class UButton* Btn_Sail;
UPROPERTY(meta = (BindWidget))
class UButton* Btn_Market;
UPROPERTY(meta = (BindWidget))
class UButton* Btn_Shop;
UPROPERTY(meta = (BindWidget))
class UButton* Btn_Backpack;
// 元素Tag映射
UPROPERTY(EditDefaultsOnly, Category = "Tutorial")
TMap<FName, UWidget*> ElementTagMap;
// 引导模式状态
bool bInTutorialMode = false;
FTutorialUIFilter CurrentFilter;
private:
void InitializeElementTags();
void UpdateUIVisibility();
void UpdateUIHighlight();
};
```
```cpp
// HomeUIWidget.cpp
#include "HomeUIWidget.h"
#include "Components/Button.h"
#include "TutorialSubsystem.h"
void UHomeUIWidget::NativeConstruct()
{
Super::NativeConstruct();
InitializeElementTags();
}
void UHomeUIWidget::InitializeElementTags()
{
// 为每个UI元素设置Tag
ElementTagMap.Add(TEXT("Btn_Sail"), Btn_Sail);
ElementTagMap.Add(TEXT("Btn_Market"), Btn_Market);
ElementTagMap.Add(TEXT("Btn_Shop"), Btn_Shop);
ElementTagMap.Add(TEXT("Btn_Backpack"), Btn_Backpack);
}
void UHomeUIWidget::EnterTutorialMode_Implementation(const FTutorialUIFilter& Filter)
{
bInTutorialMode = true;
CurrentFilter = Filter;
UpdateUIVisibility();
UpdateUIHighlight();
}
void UHomeUIWidget::ExitTutorialMode_Implementation()
{
bInTutorialMode = false;
// 恢复所有元素为可见
for (auto& Elem : ElementTagMap)
{
if (Elem.Value)
{
Elem.Value->SetVisibility(ESlateVisibility::Visible);
// 移除高亮效果
}
}
}
bool UHomeUIWidget::ShouldShowElement_Implementation(FName ElementTag) const
{
if (!bInTutorialMode)
return true;
if (CurrentFilter.bUseBlacklist)
{
// 黑名单模式:不在列表中的显示
return !CurrentFilter.VisibleElementTags.Contains(ElementTag);
}
else
{
// 白名单模式:在列表中的显示
return CurrentFilter.VisibleElementTags.Contains(ElementTag);
}
}
bool UHomeUIWidget::ShouldHighlightElement_Implementation(FName ElementTag) const
{
if (!bInTutorialMode)
return false;
return CurrentFilter.HighlightedElementTags.Contains(ElementTag);
}
void UHomeUIWidget::UpdateUIVisibility()
{
for (auto& Elem : ElementTagMap)
{
if (Elem.Value)
{
bool bShouldShow = ShouldShowElement_Implementation(Elem.Key);
Elem.Value->SetVisibility(bShouldShow ? ESlateVisibility::Visible : ESlateVisibility::Collapsed);
}
}
}
void UHomeUIWidget::UpdateUIHighlight()
{
for (auto& Elem : ElementTagMap)
{
if (Elem.Value && ShouldHighlightElement_Implementation(Elem.Key))
{
// 添加高亮效果(例如:发光边框、脉冲动画等)
// 可以使用UMG动画或者材质参数
}
}
}
```
### 3.2 通用UI引导基类
为了简化改造,可以创建一个基类:
```cpp
// TutorialEnabledWidget.h
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "TutorialModeInterface.h"
#include "TutorialEnabledWidget.generated.h"
UCLASS()
class PROJECTFISH_API UTutorialEnabledWidget : public UUserWidget, public ITutorialModeInterface
{
GENERATED_BODY()
public:
virtual void NativeConstruct() override;
virtual void NativeTick(const FGeometry& MyGeometry, float InDeltaTime) override;
// ITutorialModeInterface implementation
virtual void EnterTutorialMode_Implementation(const FTutorialUIFilter& Filter) override;
virtual void ExitTutorialMode_Implementation() override;
virtual bool ShouldShowElement_Implementation(FName ElementTag) const override;
virtual bool ShouldHighlightElement_Implementation(FName ElementTag) const override;
protected:
// 子类需要重写此方法来注册UI元素
UFUNCTION(BlueprintNativeEvent, Category = "Tutorial")
void RegisterTutorialElements();
virtual void RegisterTutorialElements_Implementation() {}
// 注册单个元素
UFUNCTION(BlueprintCallable, Category = "Tutorial")
void RegisterElement(FName Tag, UWidget* Widget);
// 引导模式状态
UPROPERTY(BlueprintReadOnly, Category = "Tutorial")
bool bInTutorialMode = false;
UPROPERTY(BlueprintReadOnly, Category = "Tutorial")
FTutorialUIFilter CurrentFilter;
// 元素映射
UPROPERTY()
TMap<FName, UWidget*> ElementMap;
private:
void UpdateAllElements();
void ApplyHighlight(UWidget* Widget, bool bHighlight);
};
```
---
## 四、关卡特殊配置系统
### 4.1 战斗关卡配置扩展
为新手引导创建特殊的战斗配置:
```cpp
// TutorialBattleConfig.h
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataAsset.h"
#include "TutorialBattleConfig.generated.h"
// 战斗事件触发点
UENUM(BlueprintType)
enum class ETutorialBattleTrigger : uint8
{
OnBattleStart, // 战斗开始时
OnFirstCast, // 第一次抛竿时
OnFishHooked, // 鱼上钩时
OnTurnStart, // 回合开始时
OnTurnEnd, // 回合结束时
OnVictory, // 胜利时
OnHPThreshold // HP到达阈值时
};
// 战斗中对话触发配置
USTRUCT(BlueprintType)
struct FTutorialBattleDialogueTrigger
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
ETutorialBattleTrigger TriggerType;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float TriggerValue = 0.0f; // 用于HP阈值等
UPROPERTY(EditAnywhere, BlueprintReadWrite)
class UDialogueAsset* DialogueAsset;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
bool bPauseBattle = true;
};
// 强制奖励配置
USTRUCT(BlueprintType)
struct FTutorialBattleReward
{
GENERATED_BODY()
// 强制掉落的物品ID
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TArray<FName> ForcedDropItemIDs;
// 是否强制玩家拾取所有奖励
UPROPERTY(EditAnywhere, BlueprintReadWrite)
bool bMustCollectAll = true;
// 拾取提示文本
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FText CollectHintText;
};
UCLASS(BlueprintType)
class PROJECTFISH_API UTutorialBattleConfig : public UDataAsset
{
GENERATED_BODY()
public:
// 使用的敌人配置
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Battle")
class UFishInfoConfigAsset* FishConfig;
// 对话触发器列表
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Battle")
TArray<FTutorialBattleDialogueTrigger> DialogueTriggers;
// 奖励配置
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Battle")
FTutorialBattleReward RewardConfig;
// 禁用的UI元素
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Battle")
TArray<FName> DisabledUIElements;
// 是否禁用返航按钮
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Battle")
bool bDisableReturnButton = false;
};
```
### 4.2 地图系统引导模式
```cpp
// 在 FishingMapSubSystem 中添加引导模式支持
// FishingMapSubSystem.h 中添加:
UCLASS()
class PROJECTFISH_API UFishingMapSubSystem : public UGameInstanceSubsystem
{
// ... 现有代码 ...
public:
// 引导模式:生成固定的单节点地图
UFUNCTION(BlueprintCallable, Category = "Tutorial")
void GenerateTutorialMap(const FVector2D& NodePosition);
// 引导模式:只显示指定节点
UFUNCTION(BlueprintCallable, Category = "Tutorial")
void SetTutorialVisibleNodes(const TArray<int32>& VisibleNodeIDs);
// 引导模式:高亮指定节点
UFUNCTION(BlueprintCallable, Category = "Tutorial")
void SetTutorialHighlightNode(int32 NodeID);
protected:
UPROPERTY()
bool bInTutorialMode = false;
UPROPERTY()
TArray<int32> TutorialVisibleNodes;
UPROPERTY()
int32 TutorialHighlightNodeID = -1;
};
```
---
## 五、实现流程步骤拆解
根据你的需求新手引导分为15个步骤。以下是每个步骤的配置示例
### Step 1: 家园初始对话
```cpp
// Content/DataAssets/Tutorial/Step01_HomeIntro.uasset
StepID: "Tutorial_Step01"
StepName: "家园初始对话"
StepType: Dialogue
DialogueAsset: DA_Tutorial_HomeIntro
CompletionCondition:
CompletionType: DialogueFinished
ConditionParameter: "DA_Tutorial_HomeIntro"
AutoAdvanceDelay: 0.5
```
### Step 2: 引导出航按钮
```cpp
// Content/DataAssets/Tutorial/Step02_SailButton.uasset
StepID: "Tutorial_Step02"
StepName: "引导点击出航"
StepType: UIInteraction
UIFilter:
VisibleElementTags: ["Btn_Sail"]
HighlightedElementTags: ["Btn_Sail"]
InteractableElementTags: ["Btn_Sail"]
HintConfig:
HintText: "点击【出航】按钮开始冒险"
AnchorElementTag: "Btn_Sail"
bShowArrow: true
CompletionCondition:
CompletionType: UIClick
ConditionParameter: "Btn_Sail"
```
### Step 3: 地图界面单点
```cpp
// Content/DataAssets/Tutorial/Step03_MapSingleNode.uasset
StepID: "Tutorial_Step03"
StepName: "地图单节点引导"
StepType: UIInteraction
OverrideMapConfig: DA_Tutorial_MapConfig_SingleNode
UIFilter:
VisibleElementTags: ["MapNode_0"]
HighlightedElementTags: ["MapNode_0"]
HintConfig:
HintText: "点击这个地点开始探险"
AnchorElementTag: "MapNode_0"
CompletionCondition:
CompletionType: UIClick
ConditionParameter: "MapNode_0"
```
### Step 5: 移动按键引导
```cpp
// Content/DataAssets/Tutorial/Step05_MovementGuide.uasset
StepID: "Tutorial_Step05"
StepName: "移动操作引导"
StepType: Gameplay
HintConfig:
HintText: "使用 WASD 键移动船只"
Offset: (0, -200)
CompletionCondition:
CompletionType: LocationReached
ConditionParameter: "FishingSpot_01"
```
### Step 6-10: 战斗引导(特殊配置)
```cpp
// Content/DataAssets/Tutorial/Battle01_Config.uasset
FishConfig: DA_Fish_Tutorial_Bass01
DialogueTriggers:
[0]:
TriggerType: OnBattleStart
DialogueAsset: DA_Tutorial_Battle_Intro
[1]:
TriggerType: OnVictory
DialogueAsset: DA_Tutorial_Battle_Victory01
RewardConfig:
ForcedDropItemIDs: ["Item_Bass"]
bMustCollectAll: true
CollectHintText: "左键选中,右键旋转,收集所有鱼获"
DisabledUIElements: ["Btn_Backpack", "Btn_Return"]
```
---
## 六、代码结构建议
### 6.1 目录结构
```
Source/ProjectFish/
└── Tutorial/
├── TutorialSubsystem.h/cpp # 核心子系统
├── TutorialUIController.h/cpp # UI控制器
├── TutorialEventListener.h/cpp # 事件监听器
├── TutorialModeInterface.h # UI接口
├── DataAsset/
│ ├── TutorialStepAsset.h/cpp # 步骤资产
│ └── TutorialBattleConfig.h/cpp # 战斗配置
└── Widget/
└── TutorialEnabledWidget.h/cpp # UI基类
Content/
├── DataAssets/
│ └── Tutorial/
│ ├── Steps/ # 引导步骤资产
│ │ ├── Step01_HomeIntro.uasset
│ │ ├── Step02_SailButton.uasset
│ │ └── ...
│ ├── Battles/ # 战斗配置
│ │ ├── Battle01_FirstFish.uasset
│ │ └── Battle02_SecondFish.uasset
│ └── Maps/ # 地图配置
│ └── Tutorial_SingleNode.uasset
└── UI/
└── Tutorial/
├── WBP_TutorialMask.uasset # 遮罩Widget
├── WBP_TutorialHint.uasset # 提示Widget
└── WBP_TutorialHighlight.uasset # 高亮效果
```
### 6.2 现有系统集成点
#### QuestManager 集成
```cpp
// 在 QuestManager.h 中添加:
UFUNCTION(BlueprintCallable, Category = "Tutorial")
void AcceptTutorialQuest(UQuestAsset* QuestAsset);
```
#### DialogueAsset 集成
```cpp
// 对话系统已经有事件委托,直接监听即可
// 在 TutorialSubsystem 中:
void UTutorialSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
// 监听对话结束事件
// UDialogueAsset::OnDialogueFinished.AddDynamic(this, &UTutorialSubsystem::OnDialogueFinished);
}
```
#### FishingMapSubSystem 集成
```cpp
// 在地图生成前检查是否引导模式
void UFishingMapSubSystem::GenerateMap()
{
UTutorialSubsystem* TutorialSys = GetGameInstance()->GetSubsystem<UTutorialSubsystem>();
if (TutorialSys && TutorialSys->IsInTutorialMode())
{
// 使用引导专用地图配置
GenerateTutorialMap(...);
return;
}
// 正常地图生成
...
}
```
---
## 七、UI改造优先级
### 高优先级(必须改造)
1. **HomeUI** - 家园界面(出航、鱼市、道具店、背包按钮)
2. **MapUI** - 地图界面(节点显示和高亮)
3. **BattleUI** - 战斗界面(技能、背包、返航按钮控制)
4. **RewardUI** - 奖励界面(强制拾取逻辑)
### 中优先级
5. **MarketUI** - 鱼市界面(任务提交)
6. **FishingSceneUI** - 钓鱼场景UI移动提示
### 低优先级
7. 其他辅助UI
---
## 八、实现建议
### 8.1 分阶段实现
**Phase 1: 核心框架**
- [ ] 实现 TutorialSubsystem
- [ ] 实现 TutorialStepAsset
- [ ] 实现 ITutorialModeInterface
- [ ] 实现 TutorialUIController
**Phase 2: UI改造**
- [ ] 创建 TutorialEnabledWidget 基类
- [ ] 改造 HomeUI
- [ ] 改造 MapUI
- [ ] 改造 BattleUI
- [ ] 改造 RewardUI
**Phase 3: 系统集成**
- [ ] 集成对话系统
- [ ] 集成任务系统
- [ ] 集成地图系统
- [ ] 集成战斗系统
**Phase 4: 配置数据**
- [ ] 创建15个引导步骤资产
- [ ] 创建引导专用对话
- [ ] 创建引导专用战斗配置
- [ ] 创建引导专用地图配置
**Phase 5: 测试优化**
- [ ] 流程测试
- [ ] UI表现优化
- [ ] 存档系统集成
- [ ] Bug修复
### 8.2 关键技术点
1. **UI遮罩实现**:使用 Canvas Panel + Image黑色半透明+ Retainer Box剪切高亮区域
2. **高亮效果**
- 方案AMaterial + 发光参数
- 方案BUMG Animation缩放脉冲
- 方案CBorder + 高亮颜色
3. **事件监听**
- 使用委托系统
- 在 TutorialEventListener 中统一管理
- 避免硬编码,使用数据驱动
4. **存档集成**
- 在 PlayerInfoSaveGame 中添加:
```cpp
UPROPERTY()
bool bTutorialCompleted = false;
UPROPERTY()
int32 LastCompletedTutorialStep = -1;
```
---
## 九、最佳实践建议
### 9.1 设计原则
- **数据驱动**:所有配置用 DataAsset方便策划调整
- **解耦设计**:引导系统不侵入现有逻辑
- **接口隔离**UI组件实现接口即可支持引导
- **事件驱动**:使用委托而非轮询
### 9.2 性能优化
- 引导模式下禁用不必要的Tick
- UI过滤用 Collapsed 而非 Hidden减少渲染
- 遮罩层使用单例复用
### 9.3 可扩展性
- 预留自定义步骤类型
- 支持蓝图扩展 TutorialStepAsset
- UI标签系统支持动态注册
---
## 十、示例流程图
```
[游戏启动]
[检查存档:是否完成引导]
↓ 否
[TutorialSubsystem::StartTutorial()]
[Step 1: 家园对话] → DialogueAsset 播放
↓ 对话结束
[Step 2: 出航按钮] → HomeUI.EnterTutorialMode({Btn_Sail})
↓ 点击出航
[Step 3: 地图界面] → MapUI.EnterTutorialMode({MapNode_0})
↓ 点击节点
[Loading...]
[Step 4-10: 战斗流程]
├→ Step 5: 移动引导
├→ Step 6: 钓鱼引导
├→ Step 7: 战斗1 + 收获
├→ Step 8: 对话提示
├→ Step 9: 战斗2中间插入对话
└→ Step 10: 收获(魔法书)
[Step 11: 返航引导] → 显示返航按钮
[Loading...]
[Step 12-15: 家园流程]
├→ Step 13: 家园对话
├→ Step 14: 鱼市引导 + 任务提交
└→ Step 15: 解锁功能
[引导完成] → 保存进度 → 退出引导模式
```
---
## 总结
这套新手引导系统设计具有以下特点:
**非侵入式**:通过接口和子系统,不破坏现有代码结构
**数据驱动**:使用 DataAsset 配置所有步骤,策划友好
**灵活可扩展**:支持自定义步骤类型和条件
**UI双模式**:正常模式和引导模式无缝切换
**系统集成**:充分利用现有的对话、任务、地图、战斗系统
**性能友好**:按需加载,最小化运行时开销
建议按照分阶段实现计划逐步推进优先完成核心框架和关键UI改造。