SubwaySurf minigame, bugfixes

This commit is contained in:
Oleg Petruny 2024-07-24 21:57:25 +02:00
parent 4037fe3f1a
commit d8933a111b
25 changed files with 162 additions and 51 deletions

Binary file not shown.

View File

@ -10,12 +10,9 @@
#include "LevelSequencePlayer.h" #include "LevelSequencePlayer.h"
#include "CutsceneManager.h" #include "CutsceneManager.h"
#include "MainGameModeBase.h"
void ALevel1::BeginPlay() void ALevel1::BeginPlay()
{ {
AMainGameModeBase::leadLevel = this;
ALevelBase::BeginPlay(); ALevelBase::BeginPlay();
TurnLight(false); TurnLight(false);

View File

@ -3,19 +3,8 @@
#include "Level2.h" #include "Level2.h"
#include "Atmosphere/AtmosphericFog.h"
#include "Components/LightComponent.h"
#include "Engine/DirectionalLight.h"
#include "Engine/SkyLight.h"
#include "LevelSequencePlayer.h"
#include "CutsceneManager.h"
#include "MainGameModeBase.h"
void ALevel2::BeginPlay() void ALevel2::BeginPlay()
{ {
AMainGameModeBase::leadLevel = this;
ALevelBase::BeginPlay(); ALevelBase::BeginPlay();
CallNextState(); CallNextState();

View File

@ -4,17 +4,33 @@
#include "LevelBase.h" #include "LevelBase.h"
#include "EngineUtils.h" #include "EngineUtils.h"
#include "InputMappingContext.h"
#include "LevelSequencePlayer.h" #include "LevelSequencePlayer.h"
#include "CommonFunctions.h" #include "CommonFunctions.h"
#include "CustomGameInstanceBase.h" #include "CustomGameInstanceBase.h"
#include "Interactable/Interactable.h" #include "Interactable/Interactable.h"
#include "Levels/Checkpoint.h" #include "Levels/Checkpoint.h"
#include "MainGameModeBase.h"
#include "Minigame/Minigame.h"
#include "PlayerBase.h" #include "PlayerBase.h"
#include "SaveData.h" #include "SaveData.h"
void ALevelBase::BeginPlay() void ALevelBase::BeginPlay()
{ {
AMainGameModeBase::leadLevel = this;
if(auto world = GetWorld())
{
if(auto GI = Cast<UCustomGameInstanceBase>(world->GetGameInstance()))
{
for(TActorIterator<AMinigame> it(GetWorld()); it; ++it)
{
GI->inputContexts.Add(it->GetInputMappings());
}
}
}
ALevelScriptActor::BeginPlay(); ALevelScriptActor::BeginPlay();
BroadcastNewLevelBeginPlay(); BroadcastNewLevelBeginPlay();

View File

@ -15,6 +15,9 @@ public:
UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable)
inline void CallNextState() { ++state; NextState(); } inline void CallNextState() { ++state; NextState(); }
UFUNCTION(BlueprintImplementableEvent)
void CallEvent(int32 id);
inline int32 GetState() { return state; }; inline int32 GetState() { return state; };
protected: protected:

View File

@ -76,6 +76,12 @@ void AMainGameModeBase::CallNextLevelState()
leadLevel->CallNextState(); leadLevel->CallNextState();
} }
void AMainGameModeBase::CallLevelEvent(int32 id)
{
if(leadLevel)
leadLevel->CallEvent(id);
}
void AMainGameModeBase::SwitchCameraMode() void AMainGameModeBase::SwitchCameraMode()
{ {
static TWeakObjectPtr<APawn> _playerPawn = nullptr; static TWeakObjectPtr<APawn> _playerPawn = nullptr;

View File

@ -27,6 +27,8 @@ public:
UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable)
static void CallNextLevelState(); static void CallNextLevelState();
UFUNCTION(BlueprintCallable)
static void CallLevelEvent(int32 id);
void SwitchCameraMode(); void SwitchCameraMode();

View File

@ -3,14 +3,26 @@
#include "Minigame.h" #include "Minigame.h"
#include "InputMappingContext.h"
AMinigame::AMinigame() AMinigame::AMinigame()
: AActor()
{ {
//PrimaryActorTick.bCanEverTick = true; PrimaryActorTick.bStartWithTickEnabled = false;
PrimaryActorTick.bCanEverTick = true;
} }
void AMinigame::End() void AMinigame::End()
{} {}
void AMinigame::Restart()
{}
UInputMappingContext* AMinigame::GetInputMappings()
{
return input.LoadSynchronous();
}
void AMinigame::Start(class APlayerBase* playerPawn, FMinigameEndCallback delegate) void AMinigame::Start(class APlayerBase* playerPawn, FMinigameEndCallback delegate)
{ {
player = playerPawn; player = playerPawn;

View File

@ -29,8 +29,11 @@ public:
UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable)
virtual void End(); virtual void End();
UFUNCTION(BlueprintCallable)
virtual void Restart();
UFUNCTION(BlueprintPure) UFUNCTION(BlueprintPure)
inline class UInputMappingContext* GetInputMappings() { return input.LoadSynchronous(); } class UInputMappingContext* GetInputMappings();
protected: protected:
FMinigameEndCallback callback; FMinigameEndCallback callback;
@ -39,6 +42,9 @@ protected:
UPROPERTY(EditAnywhere, BlueprintReadWrite) UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 score = 0; int32 score = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
bool ended = false;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly) UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
TSoftObjectPtr<class UInputMappingContext> input = nullptr; TSoftObjectPtr<class UInputMappingContext> input = nullptr;
}; };

View File

@ -3,23 +3,46 @@
#include "SubwaySurfManager.h" #include "SubwaySurfManager.h"
#include "Camera/CameraComponent.h"
#include "Components/SkeletalMeshComponent.h"
#include "Components/SplineComponent.h" #include "Components/SplineComponent.h"
#include "EnhancedInputComponent.h" #include "EnhancedInputComponent.h"
#include "InputMappingContext.h" #include "InputMappingContext.h"
#include "CustomGameInstanceBase.h"
#include "MainGameModeBase.h"
#include "PlayerBase.h" #include "PlayerBase.h"
#include "SubwaySurfObstacle.h" #include "SubwaySurfObstacle.h"
#include "Widgets/WidgetsManager.h"
ASubwaySurfManager::ASubwaySurfManager() ASubwaySurfManager::ASubwaySurfManager()
: AMinigame()
{ {
input = { FSoftObjectPath{ TEXT("/Script/EnhancedInput.InputMappingContext'/Game/Input/Minigame/IMC_SubwaySurf.IMC_SubwaySurf'") } }; input = { FSoftObjectPath{ TEXT("/Script/EnhancedInput.InputMappingContext'/Game/Input/Minigame/IMC_SubwaySurf.IMC_SubwaySurf'") } };
auto root = CreateDefaultSubobject<USceneComponent>(TEXT("Scene"));
playerPos = CreateDefaultSubobject<USceneComponent>(TEXT("PlayerPos"));
playerPos->AttachToComponent(root, FAttachmentTransformRules::KeepRelativeTransform);
camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
camera->AttachToComponent(root, FAttachmentTransformRules::KeepRelativeTransform);
mannequin = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Mannequin"));
mannequin->AttachToComponent(root, FAttachmentTransformRules::KeepRelativeTransform);
} }
void ASubwaySurfManager::Start(APlayerBase* playerPawn, FMinigameEndCallback delegate) void ASubwaySurfManager::Start(APlayerBase* playerPawn, FMinigameEndCallback delegate)
{ {
if(!playerPawn)
return;
AMinigame::Start(playerPawn, delegate); AMinigame::Start(playerPawn, delegate);
AMainGameModeBase::GetWidgetsManager()->HideInteractionHints(nullptr);
player->LockPlayer(FPlayerLock::All()); player->LockPlayer(FPlayerLock::All());
player->SwitchToView(this);
for(auto& mapping : input.LoadSynchronous()->GetMappings()) for(auto& mapping : input.LoadSynchronous()->GetMappings())
{ {
@ -33,27 +56,34 @@ void ASubwaySurfManager::Start(APlayerBase* playerPawn, FMinigameEndCallback del
inputHandlers.Add(player->inputComponent->BindAction(mapping.Action, ETriggerEvent::Triggered, this, &ASubwaySurfManager::Right).GetHandle()); inputHandlers.Add(player->inputComponent->BindAction(mapping.Action, ETriggerEvent::Triggered, this, &ASubwaySurfManager::Right).GetHandle());
} }
playerPos.SetRelativeLocation(lines[0]->GetLocationAtTime(lines[0]->Duration * 0.2f, ESplineCoordinateSpace::Local)); playerPos->SetRelativeLocation(lines[1]->GetLocationAtTime(lines[1]->Duration * 0.01f, ESplineCoordinateSpace::Local));
player->SetActorLocation(playerPos.GetComponentLocation()); mannequin->SetWorldLocationAndRotation(playerPos->GetComponentLocation(), playerPos->GetComponentRotation());
player->Controller->SetControlRotation(GetActorRotation());
PrimaryActorTick.bCanEverTick = true; PrimaryActorTick.SetTickFunctionEnable(true);
} }
void ASubwaySurfManager::End() void ASubwaySurfManager::End()
{ {
PrimaryActorTick.bCanEverTick = false; PrimaryActorTick.SetTickFunctionEnable(false);
for(int32 handler : inputHandlers) for(int32 handler : inputHandlers)
player->inputComponent->RemoveActionBindingForHandle(handler); player->inputComponent->RemoveActionBindingForHandle(handler);
AMainGameModeBase::GetWidgetsManager()->ShowInteractionHints(nullptr);
player->UnlockPlayer(FPlayerLock::All()); player->UnlockPlayer(FPlayerLock::All());
player->ReturnPlayerView();
AMinigame::End(); AMinigame::End();
} }
void ASubwaySurfManager::Hit() void ASubwaySurfManager::Hit()
{ {
if(ended)
return;
ended = true;
if(score > 1000) if(score > 1000)
{ {
Finish(); Finish();
@ -98,7 +128,7 @@ void ASubwaySurfManager::Tick(float deltaTime)
obstacles[i].actor->Destroy(); obstacles[i].actor->Destroy();
obstacles.RemoveAt(i); obstacles.RemoveAt(i);
//CreateObstacle(); //CreateObstacle();
speed += 0.1; speed += 0.15;
score += 100 * speed; score += 100 * speed;
} }
else else
@ -108,7 +138,22 @@ void ASubwaySurfManager::Tick(float deltaTime)
} }
} }
player->SetActorLocation(FMath::VInterpTo(player->GetActorLocation(), playerPos.GetComponentLocation(), deltaTime, 1)); FVector targetpos = playerPos->GetComponentLocation();
FVector actualpos = mannequin->GetComponentLocation();
FVector newpos{
FMath::FInterpTo(actualpos.X, targetpos.X, deltaTime, 20),
FMath::FInterpTo(actualpos.Y, targetpos.Y, deltaTime, 20),
FMath::FInterpTo(actualpos.Z, targetpos.Z, deltaTime, (FMath::Abs(actualpos.Z - targetpos.Z) < 20 ? 2.5f : 5.0f) * (speed / 2))
};
mannequin->SetWorldLocation(newpos, false, nullptr, ETeleportType::ResetPhysics);
if(vertical != 1 && FMath::IsNearlyEqual(actualpos.Z, targetpos.Z, 1.0))
{
if(vertical == 0)
Up();
else
Down();
}
} }
void ASubwaySurfManager::CreateObstacle(int32 index) void ASubwaySurfManager::CreateObstacle(int32 index)
@ -130,7 +175,6 @@ void ASubwaySurfManager::CreateObstacle(int32 index)
lastSpawnedLine = lineId; lastSpawnedLine = lineId;
auto obstacle = GetWorld()->SpawnActor<ASubwaySurfObstacle>(*obstacleClass, spline->GetComponentLocation(), GetActorRotation(), spawnParams); auto obstacle = GetWorld()->SpawnActor<ASubwaySurfObstacle>(*obstacleClass, spline->GetComponentLocation(), GetActorRotation(), spawnParams);
obstacle->subwaySurf = this; obstacle->subwaySurf = this;
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Yellow, FString::Printf(TEXT("v: %f, %f, %f"), obstacle->GetActorLocation().X, obstacle->GetActorLocation().Y, obstacle->GetActorLocation().Z));
if(index < 0) if(index < 0)
{ {
@ -147,40 +191,40 @@ void ASubwaySurfManager::CreateObstacle(int32 index)
void ASubwaySurfManager::Up() void ASubwaySurfManager::Up()
{ {
if(playerUp) if(vertical == 2)
return; return;
playerUp = true; ++vertical;
playerPos.AddLocalOffset(FVector::UpVector * 300); playerPos->AddLocalOffset(FVector::UpVector * 150);
} }
void ASubwaySurfManager::Down() void ASubwaySurfManager::Down()
{ {
if(!playerUp) if(vertical == 0)
return; return;
playerUp = false; --vertical;
playerPos.AddLocalOffset(FVector::DownVector * 300); playerPos->AddLocalOffset(FVector::DownVector * 150);
} }
void ASubwaySurfManager::Left() void ASubwaySurfManager::Left()
{ {
if(playerLine == 0) if(horizontal == 0)
return; return;
--playerLine; --horizontal;
playerPos.AddLocalOffset(FVector::LeftVector * 300); playerPos->AddLocalOffset(FVector::LeftVector * 200);
} }
void ASubwaySurfManager::Right() void ASubwaySurfManager::Right()
{ {
if(playerLine == lines.Num() - 1) if(horizontal == 2)
return; return;
++playerLine; ++horizontal;
playerPos.AddLocalOffset(FVector::RightVector * 300); playerPos->AddLocalOffset(FVector::RightVector * 200);
} }

View File

@ -41,6 +41,12 @@ protected:
UPROPERTY(EditDefaultsOnly) UPROPERTY(EditDefaultsOnly)
TSet<TSubclassOf<class ASubwaySurfObstacle>> obstacleClasses; TSet<TSubclassOf<class ASubwaySurfObstacle>> obstacleClasses;
UPROPERTY(EditAnywhere)
class UCameraComponent* camera;
UPROPERTY(EditAnywhere)
class USkeletalMeshComponent* mannequin;
UPROPERTY(EditDefaultsOnly) UPROPERTY(EditDefaultsOnly)
float speed = 2; float speed = 2;
@ -48,11 +54,13 @@ protected:
float spawnDelay = 3; float spawnDelay = 3;
float time = spawnDelay; float time = spawnDelay;
UPROPERTY(EditDefaultsOnly)
TArray<class USplineComponent*> lines; TArray<class USplineComponent*> lines;
TArray<ObstacleData> obstacles; TArray<ObstacleData> obstacles;
int32 lastSpawnedLine = -1; int32 lastSpawnedLine = -1;
TArray<int32> inputHandlers; TArray<int32> inputHandlers;
class USceneComponent playerPos; class USceneComponent* playerPos;
bool playerUp = false; int32 vertical = 1;
int32 playerLine = 0; int32 horizontal = 1;
}; };

View File

@ -20,20 +20,25 @@
#include "MainGameModeBase.h" #include "MainGameModeBase.h"
#include "Widgets/WidgetsManager.h" #include "Widgets/WidgetsManager.h"
namespace
{
const FVector cameraLocation = { 10, 0, 70 };
}
APlayerBase::APlayerBase() APlayerBase::APlayerBase()
: ACharacter() : ACharacter()
{ {
PrimaryActorTick.bCanEverTick = true; PrimaryActorTick.bCanEverTick = true;
camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera")); camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
camera->SetRelativeLocation(FVector{ 10, 0, 70 }); camera->SetRelativeLocation(cameraLocation);
camera->SetRelativeScale3D(FVector{ 0.25, 0.25, 0.25 }); camera->SetRelativeScale3D(FVector{ 0.25, 0.25, 0.25 });
camera->bUsePawnControlRotation = true; camera->bUsePawnControlRotation = true;
camera->SetupAttachment(RootComponent); camera->SetupAttachment(RootComponent);
cameraSpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraSpringArm")); itemDropSpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("ItemDropSpringArm"));
cameraSpringArm->TargetArmLength = -200; itemDropSpringArm->TargetArmLength = -200;
cameraSpringArm->SetupAttachment(camera); itemDropSpringArm->SetupAttachment(camera);
} }
void APlayerBase::Tick(float DeltaTime) void APlayerBase::Tick(float DeltaTime)
@ -130,6 +135,11 @@ void APlayerBase::UnlockPlayer(FPlayerLock lock)
inventoryLocked -= lock.inventory; inventoryLocked -= lock.inventory;
} }
void APlayerBase::FlyMode(bool on)
{
GetCharacterMovement()->GravityScale = on ? 0.0f : 1.0f;
}
FVector APlayerBase::GetCameraDirection() FVector APlayerBase::GetCameraDirection()
{ {
return camera->GetForwardVector(); return camera->GetForwardVector();
@ -150,6 +160,16 @@ void APlayerBase::SwitchToCameraPawn()
} }
} }
void APlayerBase::SwitchToView(AActor* target)
{
((APlayerController*)Controller)->SetViewTargetWithBlend(target, 0.3f);
}
void APlayerBase::ReturnPlayerView()
{
((APlayerController*)Controller)->SetViewTargetWithBlend(this, 0.3f);
}
void APlayerBase::MoveCamera(FVector2D value) void APlayerBase::MoveCamera(FVector2D value)
{ {
if(cameraLocked) if(cameraLocked)
@ -261,7 +281,7 @@ void APlayerBase::TakeToInventory(AActor* actor)
actor->SetActorHiddenInGame(true); actor->SetActorHiddenInGame(true);
actor->SetActorEnableCollision(false); actor->SetActorEnableCollision(false);
actor->SetActorTickEnabled(false); actor->SetActorTickEnabled(false);
actor->AttachToComponent(cameraSpringArm, FAttachmentTransformRules::SnapToTargetNotIncludingScale); actor->AttachToComponent(itemDropSpringArm, FAttachmentTransformRules::SnapToTargetNotIncludingScale);
} }
void APlayerBase::TakeItemToLeftHand(AActor* actor) void APlayerBase::TakeItemToLeftHand(AActor* actor)
@ -270,7 +290,7 @@ void APlayerBase::TakeItemToLeftHand(AActor* actor)
return; return;
TakeToInventory(actor); TakeToInventory(actor);
cameraSpringArm->TickComponent(0, ELevelTick::LEVELTICK_All, nullptr); itemDropSpringArm->TickComponent(0, ELevelTick::LEVELTICK_All, nullptr);
DropLeftHandItem(); DropLeftHandItem();
leftPocketItem = actor; leftPocketItem = actor;
itemDropLocked = true; itemDropLocked = true;
@ -283,7 +303,7 @@ void APlayerBase::TakeItemToRightHand(AActor* actor)
return; return;
TakeToInventory(actor); TakeToInventory(actor);
cameraSpringArm->TickComponent(0, ELevelTick::LEVELTICK_All, nullptr); itemDropSpringArm->TickComponent(0, ELevelTick::LEVELTICK_All, nullptr);
DropRightHandItem(); DropRightHandItem();
rightPocketItem = actor; rightPocketItem = actor;
itemDropLocked = true; itemDropLocked = true;
@ -340,6 +360,6 @@ void APlayerBase::ShowJournal()
FPlayerLock FPlayerLock::All() FPlayerLock FPlayerLock::All()
{ {
FPlayerLock lock; FPlayerLock lock;
std::memset(&lock, 1, sizeof(FPlayerLock)); std::memset(&lock, 0xFF, sizeof(FPlayerLock));
return std::move(lock); return std::move(lock);
} }

View File

@ -45,6 +45,12 @@ public:
FVector GetCameraDirection(); FVector GetCameraDirection();
void LockPlayer(const FPlayerLock lock); void LockPlayer(const FPlayerLock lock);
void UnlockPlayer(const FPlayerLock lock); void UnlockPlayer(const FPlayerLock lock);
void FlyMode(bool on);
UFUNCTION(BlueprintCallable, Category = Character)
void SwitchToView(class AActor* target);
UFUNCTION(BlueprintCallable, Category = Character)
void ReturnPlayerView();
UFUNCTION(BlueprintCallable, Category = Character) UFUNCTION(BlueprintCallable, Category = Character)
void TakeItemToLeftHand(class AActor* actor); void TakeItemToLeftHand(class AActor* actor);
@ -118,7 +124,7 @@ protected:
bool bIsMoving = false; bool bIsMoving = false;
class AInteractable* lastInteractable = nullptr; class AInteractable* lastInteractable = nullptr;
class USpringArmComponent* cameraSpringArm; class USpringArmComponent* itemDropSpringArm;
private: private:
void LoadInteractablesActivators(); void LoadInteractablesActivators();

View File

@ -21,8 +21,10 @@ public:
void HideWidgets(); void HideWidgets();
void UpdateWidgetsOwner(); void UpdateWidgetsOwner();
void ShowInteractionHints(const class UInteractableModificator* modificator); UFUNCTION(BlueprintCallable, Category = WidgetsManager)
void HideInteractionHints(const class UInteractableModificator* modificator); void ShowInteractionHints(const class UInteractableModificator* modificator = nullptr);
UFUNCTION(BlueprintCallable, Category = WidgetsManager)
void HideInteractionHints(const class UInteractableModificator* modificator = nullptr);
void AnimateInteractionHint(const class UInteractableModificator* modificator, const int32 index, const EInputAnimatedWidgetAnimation animation); void AnimateInteractionHint(const class UInteractableModificator* modificator, const int32 index, const EInputAnimatedWidgetAnimation animation);
void EnableCutsceneWidget(class FSkipCutsceneDelegate& skipCutsceneDelegate); void EnableCutsceneWidget(class FSkipCutsceneDelegate& skipCutsceneDelegate);