Project02/ProjectFish/Docs/TutorialSystemDesign.md

1060 lines
28 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 新手引导系统设计文档
## 一、系统整体架构
### 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改造。