Compare commits

...

3 Commits

Author SHA1 Message Date
0526f25058 更新新手引导系统 2025-11-26 16:58:17 +08:00
a83eeacbc5 修复bug 2025-11-25 14:21:55 +08:00
1a5c391707 修复新手引导bug 2025-11-25 13:34:51 +08:00
49 changed files with 109 additions and 30 deletions

View File

@ -84,8 +84,8 @@ TSet<int32> UContainerInfo::GetOverlapOtherItem(FContainerItem Item)
if (Item.IsSlotUsing(FIntPoint(x, y))) if (Item.IsSlotUsing(FIntPoint(x, y)))
{ {
if (ContainerShape->IsSlotActive(Item.ContainerStartPos.X + x, Item.ContainerStartPos.Y + y) && if (ContainerShape->IsSlotActive(Item.ContainerStartPos.X + x, Item.ContainerStartPos.Y + y) && SlotItems.Contains(FIntPoint(x + Item.ContainerStartPos.X, y + Item.ContainerStartPos.Y))
SlotItems[FIntPoint(x + Item.ContainerStartPos.X, y + Item.ContainerStartPos.Y)] != -1 ///SlotItems[FIntPoint(x + Item.ContainerStartPos.X, y + Item.ContainerStartPos.Y)] != -1
) )
{ {
OverlapItems.Add(SlotItems[FIntPoint(x + Item.ContainerStartPos.X, y + Item.ContainerStartPos.Y)] ); OverlapItems.Add(SlotItems[FIntPoint(x + Item.ContainerStartPos.X, y + Item.ContainerStartPos.Y)] );

View File

@ -5,12 +5,18 @@
#include "ProjectFish/Gameplay/Subsystem/GameInfoManager.h" #include "ProjectFish/Gameplay/Subsystem/GameInfoManager.h"
void UPlayerInfoSaveGame::BeginDestroy()
{
Super::BeginDestroy();
}
void UPlayerInfoSaveGame::SetShipContainerItems(TArray<FContainerItemSaveData> NewItems) void UPlayerInfoSaveGame::SetShipContainerItems(TArray<FContainerItemSaveData> NewItems)
{ {
ShipContainerItems = NewItems; ShipContainerItems = NewItems;
if (GetWorld())
if (GetOuter())
{ {
GetWorld()->GetGameInstance()->GetSubsystem<UGameInfoManager>()->SaveGameInfo(); GetOuter()->GetWorld()->GetGameInstance()->GetSubsystem<UGameInfoManager>()->SaveGameInfo();
OnShipContainerUpdate.Broadcast(); OnShipContainerUpdate.Broadcast();
} }
} }

View File

@ -18,6 +18,8 @@ class PROJECTFISH_API UPlayerInfoSaveGame : public USaveGame
{ {
GENERATED_BODY() GENERATED_BODY()
public: public:
virtual void BeginDestroy() override;
UPROPERTY(SaveGame, BlueprintReadWrite, meta = (ToolTip = "开启教程模式")) UPROPERTY(SaveGame, BlueprintReadWrite, meta = (ToolTip = "开启教程模式"))
bool TutorialMode = true; bool TutorialMode = true;
@ -57,10 +59,11 @@ public:
UPROPERTY(SaveGame, BlueprintReadWrite, meta = (ToolTip = "被击败的鱼")) UPROPERTY(SaveGame, BlueprintReadWrite, meta = (ToolTip = "被击败的鱼"))
TArray<int32> Fish_defeated_IDS; TArray<int32> Fish_defeated_IDS;
protected: public:
UPROPERTY(BlueprintAssignable, Category = "PlayerInfoSaveGame") UPROPERTY(BlueprintAssignable, Category = "PlayerInfoSaveGame")
FOnShipContainerUpdate OnShipContainerUpdate; FOnShipContainerUpdate OnShipContainerUpdate;
protected:
UFUNCTION(BlueprintCallable, Category= "PlayerInfoSaveGame") UFUNCTION(BlueprintCallable, Category= "PlayerInfoSaveGame")
void SetShipContainerItems(TArray<FContainerItemSaveData> NewItems); void SetShipContainerItems(TArray<FContainerItemSaveData> NewItems);
}; };

View File

@ -514,5 +514,8 @@ public:
//引导task //引导task
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Tutorial Asset") UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Tutorial Asset")
TSubclassOf<class UTutorialTask_Base> TutorialTaskClass; TSubclassOf<class UTutorialTask_Base> TutorialTaskClass;
UPROPERTY()
UTutorialTask_Base* TutorialTaskObject;
}; };

View File

@ -16,7 +16,7 @@ class PROJECTFISH_API UFishGameInstance : public UGameInstance
public: public:
/** GameInstace */ /** GameInstace */
virtual void OnStart() override; virtual void OnStart() override;
UFUNCTION(BlueprintImplementableEvent) UFUNCTION(BlueprintImplementableEvent)
void InitTutorialSteps(); void InitTutorialSteps();
}; };

View File

@ -24,9 +24,10 @@ void UGameInfoManager::NewSaveGame()
void UGameInfoManager::SaveGameInfo() void UGameInfoManager::SaveGameInfo()
{ {
if (!IsValid(PlayerInfo.Get())) if (!IsValid(PlayerInfo))
{ {
PlayerInfo = NewObject<UPlayerInfoSaveGame>(this);
PlayerInfo = NewObject<UPlayerInfoSaveGame>(GetGameInstance());
} }
// 保存任务数据 // 保存任务数据
if (UQuestManager* QuestManager = GetGameInstance()->GetSubsystem<UQuestManager>()) if (UQuestManager* QuestManager = GetGameInstance()->GetSubsystem<UQuestManager>())
@ -34,7 +35,7 @@ void UGameInfoManager::SaveGameInfo()
PlayerInfo->QuestSaveData = QuestManager->GetQuestSaveData(); PlayerInfo->QuestSaveData = QuestManager->GetQuestSaveData();
} }
if (UGameplayStatics::SaveGameToSlot(PlayerInfo.Get(), SaveGameSlotName, 0)) if (UGameplayStatics::SaveGameToSlot(PlayerInfo, SaveGameSlotName, 0))
{ {
UE_LOG(LogTemp, Warning, TEXT("存档保存成功")); UE_LOG(LogTemp, Warning, TEXT("存档保存成功"));
} }
@ -49,7 +50,7 @@ bool UGameInfoManager::LoadGameInfo()
if (UGameplayStatics::DoesSaveGameExist(SaveGameSlotName, 0)) if (UGameplayStatics::DoesSaveGameExist(SaveGameSlotName, 0))
{ {
PlayerInfo = Cast<UPlayerInfoSaveGame>(UGameplayStatics::LoadGameFromSlot(SaveGameSlotName, 0)); PlayerInfo = Cast<UPlayerInfoSaveGame>(UGameplayStatics::LoadGameFromSlot(SaveGameSlotName, 0));
PlayerInfo->Rename(nullptr, this);
// 加载任务数据 // 加载任务数据
if (UQuestManager* QuestManager = GetGameInstance()->GetSubsystem<UQuestManager>()) if (UQuestManager* QuestManager = GetGameInstance()->GetSubsystem<UQuestManager>())
{ {
@ -74,7 +75,8 @@ bool UGameInfoManager::LoadGameInfo()
void UGameInfoManager::CreateGameInfo(UContainerInfo* ShipContainer, UContainerInfo* PlayerContainer) void UGameInfoManager::CreateGameInfo(UContainerInfo* ShipContainer, UContainerInfo* PlayerContainer)
{ {
PlayerInfo = NewObject<UPlayerInfoSaveGame>(this); if (!IsValid(PlayerInfo))
PlayerInfo = NewObject<UPlayerInfoSaveGame>(GetGameInstance());
PlayerInfo->ShipContainerItems = ShipContainer->GetSaveData(); PlayerInfo->ShipContainerItems = ShipContainer->GetSaveData();
PlayerInfo->ShipContainerShapeID = ShipContainer->ContainerShape->GetPrimaryAssetId(); PlayerInfo->ShipContainerShapeID = ShipContainer->ContainerShape->GetPrimaryAssetId();
@ -93,7 +95,7 @@ void UGameInfoManager::CreateGameInfoAndSave(UShapeAsset* ShipContainerShape, US
PlayerContainer->InitContainerByShape(PlayerContainerShape); PlayerContainer->InitContainerByShape(PlayerContainerShape);
//创建要保存的额存档信息 //创建要保存的额存档信息
PlayerInfo = NewObject<UPlayerInfoSaveGame>(this); PlayerInfo = NewObject<UPlayerInfoSaveGame>(GetGameInstance());
PlayerInfo->ShipContainerItems = ShipContainer->GetSaveData(); PlayerInfo->ShipContainerItems = ShipContainer->GetSaveData();
PlayerInfo->ShipContainerShapeID = ShipContainer->ContainerShape->GetPrimaryAssetId(); PlayerInfo->ShipContainerShapeID = ShipContainer->ContainerShape->GetPrimaryAssetId();
@ -119,7 +121,7 @@ void UGameInfoManager::SetTutorialMode(bool bTutorialMode)
{ {
if (!IsValid(PlayerInfo)) if (!IsValid(PlayerInfo))
{ {
PlayerInfo = NewObject<UPlayerInfoSaveGame>(this); PlayerInfo = NewObject<UPlayerInfoSaveGame>(GetGameInstance());
} }
PlayerInfo->TutorialMode = bTutorialMode; PlayerInfo->TutorialMode = bTutorialMode;
} }
@ -137,7 +139,7 @@ void UGameInfoManager::AddDefeatedFish(int32 FishID)
{ {
if (!IsValid(PlayerInfo)) if (!IsValid(PlayerInfo))
{ {
PlayerInfo = NewObject<UPlayerInfoSaveGame>(this); PlayerInfo = NewObject<UPlayerInfoSaveGame>(GetGameInstance());
} }
PlayerInfo->Fish_defeated_IDS.Add(FishID); PlayerInfo->Fish_defeated_IDS.Add(FishID);
SaveGameInfo(); SaveGameInfo();

View File

@ -3,6 +3,7 @@
#pragma once #pragma once
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "DialogueAsset.h"
#include "ProjectFish/Data/PlayerInfoSaveGame.h" #include "ProjectFish/Data/PlayerInfoSaveGame.h"
#include "Subsystems/GameInstanceSubsystem.h" #include "Subsystems/GameInstanceSubsystem.h"
#include "GameInfoManager.generated.h" #include "GameInfoManager.generated.h"
@ -41,9 +42,11 @@ public:
UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable)
void AddDefeatedFish(int32 FishID); void AddDefeatedFish(int32 FishID);
TObjectPtr<class UPlayerInfoSaveGame> GetPlayerInfo() {return PlayerInfo;}
protected: protected:
UPROPERTY(BlueprintReadOnly) UPROPERTY(BlueprintReadWrite)
TObjectPtr<class UPlayerInfoSaveGame> PlayerInfo; class UPlayerInfoSaveGame* PlayerInfo;
static FString SaveGameSlotName; static FString SaveGameSlotName;
}; };

View File

@ -32,6 +32,7 @@ void UTutorialManagerSubsystem::ApplyCurrentTutorialStep()
{ {
if (TutorialSteps.Num() > CurrentTutorialStep ) if (TutorialSteps.Num() > CurrentTutorialStep )
{ {
UE_LOG(LogTemp, Warning, TEXT("执行 CurrentTutorialStep = %d || name = %s "), CurrentTutorialStep, *GetCurrentTutorialStep().StepName.ToString() );
bTutorialing = true; bTutorialing = true;
FTutorialStep CurrentStep = TutorialSteps[CurrentTutorialStep]; FTutorialStep CurrentStep = TutorialSteps[CurrentTutorialStep];
if (IsValid(CurrentStep.Dialogue)) if (IsValid(CurrentStep.Dialogue))
@ -52,7 +53,7 @@ void UTutorialManagerSubsystem::ApplyCurrentTutorialStep()
} }
if (IsValid(CurrentStep.TutorialTaskClass)) if (IsValid(CurrentStep.TutorialTaskClass))
{ {
CreateTask();
} }
} }
else else
@ -66,12 +67,18 @@ void UTutorialManagerSubsystem::CompleteTutorialStep()
{ {
if (bTutorialing) if (bTutorialing)
{ {
if (TutorialTask) if (TutorialTaskObject)
{ {
TutorialTask->ConditionalBeginDestroy(); TutorialTaskObject->BeforTutorialComplete();
TutorialTask = nullptr; TutorialTaskObject->ConditionalBeginDestroy();
TutorialTaskObject = nullptr;
} }
UE_LOG(LogTemp, Warning, TEXT("教程进行下一步 currentstep = %d"), CurrentTutorialStep); if (TutorialWidget)
{
TutorialWidget->RemoveFromViewport();
TutorialWidget = nullptr;
}
UE_LOG(LogTemp, Warning, TEXT(" 教程进行下一步"));
OnStepComplete.Broadcast(CurrentTutorialStep); OnStepComplete.Broadcast(CurrentTutorialStep);
CurrentTutorialStep++; CurrentTutorialStep++;
ApplyCurrentTutorialStep(); ApplyCurrentTutorialStep();
@ -138,7 +145,7 @@ void UTutorialManagerSubsystem::AccepAndFollowQuest()
void UTutorialManagerSubsystem::ShowTutorialUI() void UTutorialManagerSubsystem::ShowTutorialUI()
{ {
FTutorialStep CurrentStep = TutorialSteps[CurrentTutorialStep]; FTutorialStep CurrentStep = TutorialSteps[CurrentTutorialStep];
UUserWidget* TutorialWidget = CreateWidget<UUserWidget>(GetWorld(), CurrentStep.TutorialUI); TutorialWidget = CreateWidget<UUserWidget>(GetWorld(), CurrentStep.TutorialUI);
TutorialWidget->AddToViewport(99); TutorialWidget->AddToViewport(99);
} }
@ -161,6 +168,7 @@ void UTutorialManagerSubsystem::ControlUI()
void UTutorialManagerSubsystem::CreateTask() void UTutorialManagerSubsystem::CreateTask()
{ {
TutorialTask = NewObject<UTutorialTask_Base>(this); FTutorialStep CurrentStep = TutorialSteps[CurrentTutorialStep];
TutorialTask->Execute(GetWorld()->GetAuthGameMode()); TutorialTaskObject = NewObject<UTutorialTask_Base>(this, CurrentStep.TutorialTaskClass);
TutorialTaskObject->Execute(GetWorld()->GetAuthGameMode());
} }

View File

@ -12,7 +12,7 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnStepComplete, int32, CompleteInde
/** /**
* *
*/ */
UCLASS() UCLASS(BlueprintType)
class PROJECTFISH_API UTutorialManagerSubsystem : public UGameInstanceSubsystem class PROJECTFISH_API UTutorialManagerSubsystem : public UGameInstanceSubsystem
{ {
GENERATED_BODY() GENERATED_BODY()
@ -48,10 +48,11 @@ protected:
void ControlUI(); void ControlUI();
//创建task //创建task
void CreateTask(); void CreateTask();
private: protected:
FDelegateHandle LevelLoadedDelegateHandle; FDelegateHandle LevelLoadedDelegateHandle;
UPROPERTY(BlueprintAssignable) UPROPERTY(BlueprintAssignable)
FOnStepComplete OnStepComplete; FOnStepComplete OnStepComplete;
UPROPERTY(BlueprintReadOnly)
bool bTutorialing; bool bTutorialing;
TArray<FTutorialStep> TutorialSteps; TArray<FTutorialStep> TutorialSteps;
@ -59,7 +60,10 @@ private:
FString DialogueUIPath; FString DialogueUIPath;
UPROPERTY() UPROPERTY()
class UDialogueWidget_Base* DialogueWidget; class UDialogueWidget_Base* DialogueWidget;
UPROPERTY() UPROPERTY()
class UTutorialTask_Base* TutorialTask; UUserWidget* TutorialWidget;
UPROPERTY()
class UTutorialTask_Base* TutorialTaskObject;
}; };

View File

@ -24,4 +24,5 @@ public:
UFUNCTION(BlueprintNativeEvent, Category= "TutorialTask") UFUNCTION(BlueprintNativeEvent, Category= "TutorialTask")
void BeforTutorialComplete(); void BeforTutorialComplete();
virtual void BeforTutorialComplete_Implementation(); virtual void BeforTutorialComplete_Implementation();
}; };

View File

@ -3,13 +3,32 @@
#include "TutorialTask_CheckShipContainer.h" #include "TutorialTask_CheckShipContainer.h"
#include "GameFramework/GameModeBase.h"
#include "ProjectFish/Gameplay/Subsystem/GameInfoManager.h"
#include "ProjectFish/Gameplay/Subsystem/TutorialManagerSubsystem.h"
void UTutorialTask_CheckShipContainer::Execute_Implementation(class AGameModeBase* GameMode) void UTutorialTask_CheckShipContainer::Execute_Implementation(class AGameModeBase* GameMode)
{ {
Super::Execute_Implementation(GameMode); Super::Execute_Implementation(GameMode);
if (GameMode)
{
GameMode->GetGameInstance()->GetSubsystem<UGameInfoManager>()->GetPlayerInfo()
->OnShipContainerUpdate.AddDynamic(this, &UTutorialTask_CheckShipContainer::OnShipContainerUpdate);
}
} }
void UTutorialTask_CheckShipContainer::BeforTutorialComplete_Implementation() void UTutorialTask_CheckShipContainer::BeforTutorialComplete_Implementation()
{ {
Super::BeforTutorialComplete_Implementation(); Super::BeforTutorialComplete_Implementation();
} }
void UTutorialTask_CheckShipContainer::OnShipContainerUpdate()
{
//只有3个物品时才完成当前的引导步骤
int CurrentItemCount = GetOuter()->GetWorld()->GetGameInstance()->GetSubsystem<UGameInfoManager>()->GetPlayerInfo()->ShipContainerItems.Num();
if (CurrentItemCount == ReqItemsCount)
{
Cast<UTutorialManagerSubsystem>(GetOuter())->CompleteTutorialStep();
}
}

View File

@ -13,7 +13,14 @@ UCLASS()
class PROJECTFISH_API UTutorialTask_CheckShipContainer : public UTutorialTask_Base class PROJECTFISH_API UTutorialTask_CheckShipContainer : public UTutorialTask_Base
{ {
GENERATED_BODY() GENERATED_BODY()
virtual void Execute_Implementation(class AGameModeBase* GameMode) override; virtual void Execute_Implementation(class AGameModeBase* GameMode) override;
virtual void BeforTutorialComplete_Implementation() override; virtual void BeforTutorialComplete_Implementation() override;
UFUNCTION()
void OnShipContainerUpdate();
protected:
UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "TutorialTask_CheckShipContainer")
int32 ReqItemsCount;
}; };

View File

@ -8,6 +8,10 @@
void UTutorialTask_GamePause::Execute_Implementation(class AGameModeBase* GameMode) void UTutorialTask_GamePause::Execute_Implementation(class AGameModeBase* GameMode)
{ {
Super::Execute_Implementation(GameMode); Super::Execute_Implementation(GameMode);
// LevelLoadedDelegateHandle = FCoreUObjectDelegates::PostLoadMapWithWorld.AddUObject(
// this,
// &UTutorialTask_GamePause::OnLevelLoaded
// );
UGameplayStatics::SetGamePaused(this, true); UGameplayStatics::SetGamePaused(this, true);
} }
@ -16,3 +20,18 @@ void UTutorialTask_GamePause::BeforTutorialComplete_Implementation()
Super::BeforTutorialComplete_Implementation(); Super::BeforTutorialComplete_Implementation();
UGameplayStatics::SetGamePaused(this, false); UGameplayStatics::SetGamePaused(this, false);
} }
void UTutorialTask_GamePause::OnLevelLoaded(UWorld* World)
{
// FCoreUObjectDelegates::PostLoadMapWithWorld.Remove(LevelLoadedDelegateHandle);
// FTimerHandle LambdaTimerHandle;
// GetWorld()->GetTimerManager().SetTimer(
// LambdaTimerHandle,
// [this]()
// {
// UGameplayStatics::SetGamePaused(this, true);
// },
// 1.5f,
// false
// );
}

View File

@ -18,4 +18,8 @@ public:
virtual void Execute_Implementation(class AGameModeBase* GameMode) override; virtual void Execute_Implementation(class AGameModeBase* GameMode) override;
virtual void BeforTutorialComplete_Implementation() override; virtual void BeforTutorialComplete_Implementation() override;
void OnLevelLoaded(UWorld* World);
private:
FDelegateHandle LevelLoadedDelegateHandle;
}; };

View File

@ -23,7 +23,7 @@ void USkillManager::Tick(float DeltaTime)
bool USkillManager::IsTickable() const bool USkillManager::IsTickable() const
{ {
return !bGameEnd && IsValid(GameMode) && GameMode->GetBattleIsBegin(); return !bGameEnd && IsValid(GameMode) && GameMode->GetBattleIsBegin() && !GameMode->IsPaused();
} }
TStatId USkillManager::GetStatId() const TStatId USkillManager::GetStatId() const