İlk yürütme

This commit is contained in:
2026-08-02 22:34:52 +03:00
commit 26bde15faa
601 changed files with 4420 additions and 0 deletions
@@ -0,0 +1,143 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#include "Variant_Horror/HorrorCharacter.h"
#include "Engine/World.h"
#include "TimerManager.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "Camera/CameraComponent.h"
#include "Components/SpotLightComponent.h"
#include "EnhancedInputComponent.h"
#include "InputAction.h"
AHorrorCharacter::AHorrorCharacter()
{
// create the spotlight
SpotLight = CreateDefaultSubobject<USpotLightComponent>(TEXT("SpotLight"));
SpotLight->SetupAttachment(GetFirstPersonCameraComponent());
SpotLight->SetRelativeLocationAndRotation(FVector(30.0f, 17.5f, -5.0f), FRotator(-18.6f, -1.3f, 5.26f));
SpotLight->Intensity = 0.5;
SpotLight->SetIntensityUnits(ELightUnits::Lumens);
SpotLight->AttenuationRadius = 1050.0f;
SpotLight->InnerConeAngle = 18.7f;
SpotLight->OuterConeAngle = 45.24f;
}
void AHorrorCharacter::BeginPlay()
{
Super::BeginPlay();
// initialize sprint meter to max
SprintMeter = SprintTime;
// Initialize the walk speed
GetCharacterMovement()->MaxWalkSpeed = WalkSpeed;
// start the sprint tick timer
GetWorld()->GetTimerManager().SetTimer(SprintTimer, this, &AHorrorCharacter::SprintFixedTick, SprintFixedTickTime, true);
}
void AHorrorCharacter::EndPlay(EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
// clear the sprint timer
GetWorld()->GetTimerManager().ClearTimer(SprintTimer);
}
void AHorrorCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
{
// Set up action bindings
if (UEnhancedInputComponent* EnhancedInputComponent = Cast<UEnhancedInputComponent>(PlayerInputComponent))
{
// Sprinting
EnhancedInputComponent->BindAction(SprintAction, ETriggerEvent::Started, this, &AHorrorCharacter::DoStartSprint);
EnhancedInputComponent->BindAction(SprintAction, ETriggerEvent::Completed, this, &AHorrorCharacter::DoEndSprint);
}
}
}
void AHorrorCharacter::DoStartSprint()
{
// set the sprinting flag
bSprinting = true;
// are we out of recovery mode?
if (!bRecovering)
{
// set the sprint walk speed
GetCharacterMovement()->MaxWalkSpeed = SprintSpeed;
// call the sprint state changed delegate
OnSprintStateChanged.Broadcast(true);
}
}
void AHorrorCharacter::DoEndSprint()
{
// set the sprinting flag
bSprinting = false;
// are we out of recovery mode?
if (!bRecovering)
{
// set the default walk speed
GetCharacterMovement()->MaxWalkSpeed = WalkSpeed;
// call the sprint state changed delegate
OnSprintStateChanged.Broadcast(false);
}
}
void AHorrorCharacter::SprintFixedTick()
{
// are we out of recovery, still have stamina and are moving faster than our walk speed?
if (bSprinting && !bRecovering && GetVelocity().Length() > WalkSpeed)
{
// do we still have meter to burn?
if (SprintMeter > 0.0f)
{
// update the sprint meter
SprintMeter = FMath::Max(SprintMeter - SprintFixedTickTime, 0.0f);
// have we run out of stamina?
if (SprintMeter <= 0.0f)
{
// raise the recovering flag
bRecovering = true;
// set the recovering walk speed
GetCharacterMovement()->MaxWalkSpeed = RecoveringWalkSpeed;
}
}
} else {
// recover stamina
SprintMeter = FMath::Min(SprintMeter + SprintFixedTickTime, SprintTime);
if (SprintMeter >= SprintTime)
{
// lower the recovering flag
bRecovering = false;
// set the walk or sprint speed depending on whether the sprint button is down
GetCharacterMovement()->MaxWalkSpeed = bSprinting ? SprintSpeed : WalkSpeed;
// update the sprint state depending on whether the button is down or not
OnSprintStateChanged.Broadcast(bSprinting);
}
}
// broadcast the sprint meter updated delegate
OnSprintMeterUpdated.Broadcast(SprintMeter / SprintTime);
}
@@ -0,0 +1,104 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "firstCharacter.h"
#include "HorrorCharacter.generated.h"
class USpotLightComponent;
class UInputAction;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FUpdateSprintMeterDelegate, float, Percentage);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FSprintStateChangedDelegate, bool, bSprinting);
/**
* Simple first person horror character
* Provides stamina-based sprinting
*/
UCLASS(abstract)
class FIRST_API AHorrorCharacter : public AfirstCharacter
{
GENERATED_BODY()
/** Player light source */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Components", meta = (AllowPrivateAccess = "true"))
USpotLightComponent* SpotLight;
protected:
/** Fire weapon input action */
UPROPERTY(EditAnywhere, Category ="Input")
UInputAction* SprintAction;
/** If true, we're sprinting */
bool bSprinting = false;
/** If true, we're recovering stamina */
bool bRecovering = false;
/** Default walk speed when not sprinting or recovering */
UPROPERTY(EditAnywhere, Category="Walk")
float WalkSpeed = 250.0f;
/** Time interval for sprinting stamina ticks */
UPROPERTY(EditAnywhere, Category="Sprint", meta = (ClampMin = 0, ClampMax = 1, Units = "s"))
float SprintFixedTickTime = 0.03333f;
/** Sprint stamina amount. Maxes at SprintTime */
float SprintMeter = 0.0f;
/** How long we can sprint for, in seconds */
UPROPERTY(EditAnywhere, Category="Sprint", meta = (ClampMin = 0, ClampMax = 10, Units = "s"))
float SprintTime = 3.0f;
/** Walk speed while sprinting */
UPROPERTY(EditAnywhere, Category="Sprint", meta = (ClampMin = 0, ClampMax = 10, Units = "cm/s"))
float SprintSpeed = 600.0f;
/** Walk speed while recovering stamina */
UPROPERTY(EditAnywhere, Category="Recovery", meta = (ClampMin = 0, ClampMax = 10, Units = "cm/s"))
float RecoveringWalkSpeed = 150.0f;
/** Time it takes for the sprint meter to recover */
UPROPERTY(EditAnywhere, Category="Recovery", meta = (ClampMin = 0, ClampMax = 10, Units = "s"))
float RecoveryTime = 0.0f;
/** Sprint tick timer */
FTimerHandle SprintTimer;
public:
/** Delegate called when the sprint meter should be updated */
FUpdateSprintMeterDelegate OnSprintMeterUpdated;
/** Delegate called when we start and stop sprinting */
FSprintStateChangedDelegate OnSprintStateChanged;
protected:
/** Constructor */
AHorrorCharacter();
/** Gameplay initialization */
virtual void BeginPlay() override;
/** Gameplay cleanup */
virtual void EndPlay(EEndPlayReason::Type EndPlayReason) override;
/** Set up input action bindings */
virtual void SetupPlayerInputComponent(UInputComponent* InputComponent) override;
protected:
/** Starts sprinting behavior */
UFUNCTION(BlueprintCallable, Category = "Input")
void DoStartSprint();
/** Stops sprinting behavior */
UFUNCTION(BlueprintCallable, Category="Input")
void DoEndSprint();
/** Called while sprinting at a fixed time interval */
void SprintFixedTick();
};
@@ -0,0 +1,9 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#include "Variant_Horror/HorrorGameMode.h"
AHorrorGameMode::AHorrorGameMode()
{
// stub
}
@@ -0,0 +1,21 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "HorrorGameMode.generated.h"
/**
* Simple GameMode for a first person horror game
*/
UCLASS(abstract)
class FIRST_API AHorrorGameMode : public AGameModeBase
{
GENERATED_BODY()
public:
/** Constructor */
AHorrorGameMode();
};
@@ -0,0 +1,92 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#include "Variant_Horror/HorrorPlayerController.h"
#include "EnhancedInputSubsystems.h"
#include "Engine/LocalPlayer.h"
#include "InputMappingContext.h"
#include "firstCameraManager.h"
#include "HorrorCharacter.h"
#include "HorrorUI.h"
#include "first.h"
#include "Widgets/Input/SVirtualJoystick.h"
AHorrorPlayerController::AHorrorPlayerController()
{
// set the player camera manager class
PlayerCameraManagerClass = AfirstCameraManager::StaticClass();
}
void AHorrorPlayerController::BeginPlay()
{
Super::BeginPlay();
// only spawn touch controls on local player controllers
if (SVirtualJoystick::ShouldDisplayTouchInterface() && IsLocalPlayerController())
{
// spawn the mobile controls widget
MobileControlsWidget = CreateWidget<UUserWidget>(this, MobileControlsWidgetClass);
if (MobileControlsWidget)
{
// add the controls to the player screen
MobileControlsWidget->AddToPlayerScreen(0);
} else {
UE_LOG(Logfirst, Error, TEXT("Could not spawn mobile controls widget."));
}
}
}
void AHorrorPlayerController::OnPossess(APawn* aPawn)
{
Super::OnPossess(aPawn);
// only spawn UI on local player controllers
if (IsLocalPlayerController())
{
// set up the UI for the character
if (AHorrorCharacter* HorrorCharacter = Cast<AHorrorCharacter>(aPawn))
{
// create the UI
if (!HorrorUI)
{
HorrorUI = CreateWidget<UHorrorUI>(this, HorrorUIClass);
HorrorUI->AddToViewport(0);
}
HorrorUI->SetupCharacter(HorrorCharacter);
}
}
}
void AHorrorPlayerController::SetupInputComponent()
{
Super::SetupInputComponent();
// only add IMCs for local player controllers
if (IsLocalPlayerController())
{
// Add Input Mapping Contexts
if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer()))
{
for (UInputMappingContext* CurrentContext : DefaultMappingContexts)
{
Subsystem->AddMappingContext(CurrentContext, 0);
}
// only add these IMCs if we're not using mobile touch input
if (!SVirtualJoystick::ShouldDisplayTouchInterface())
{
for (UInputMappingContext* CurrentContext : MobileExcludedMappingContexts)
{
Subsystem->AddMappingContext(CurrentContext, 0);
}
}
}
}
}
@@ -0,0 +1,62 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "HorrorPlayerController.generated.h"
class UInputMappingContext;
class UHorrorUI;
/**
* Player Controller for a first person horror game
* Manages input mappings
* Manages UI
*/
UCLASS(abstract)
class FIRST_API AHorrorPlayerController : public APlayerController
{
GENERATED_BODY()
protected:
/** Type of UI widget to spawn */
UPROPERTY(EditAnywhere, Category="Horror|UI")
TSubclassOf<UHorrorUI> HorrorUIClass;
/** Pointer to the UI widget */
TObjectPtr<UHorrorUI> HorrorUI;
public:
/** Constructor */
AHorrorPlayerController();
protected:
/** Input Mapping Contexts */
UPROPERTY(EditAnywhere, Category ="Input|Input Mappings")
TArray<UInputMappingContext*> DefaultMappingContexts;
/** Input Mapping Contexts */
UPROPERTY(EditAnywhere, Category="Input|Input Mappings")
TArray<UInputMappingContext*> MobileExcludedMappingContexts;
/** Mobile controls widget to spawn */
UPROPERTY(EditAnywhere, Category="Input|Touch Controls")
TSubclassOf<UUserWidget> MobileControlsWidgetClass;
/** Pointer to the mobile controls widget */
TObjectPtr<UUserWidget> MobileControlsWidget;
/** Gameplay Initialization */
virtual void BeginPlay() override;
/** Possessed pawn initialization */
virtual void OnPossess(APawn* aPawn) override;
/** Input mapping context setup */
virtual void SetupInputComponent() override;
};
@@ -0,0 +1,23 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#include "HorrorUI.h"
#include "HorrorCharacter.h"
void UHorrorUI::SetupCharacter(AHorrorCharacter* HorrorCharacter)
{
HorrorCharacter->OnSprintMeterUpdated.AddDynamic(this, &UHorrorUI::OnSprintMeterUpdated);
HorrorCharacter->OnSprintStateChanged.AddDynamic(this, &UHorrorUI::OnSprintStateChanged);
}
void UHorrorUI::OnSprintMeterUpdated(float Percent)
{
// call the BP handler
BP_SprintMeterUpdated(Percent);
}
void UHorrorUI::OnSprintStateChanged(bool bSprinting)
{
// call the BP handler
BP_SprintStateChanged(bSprinting);
}
+42
View File
@@ -0,0 +1,42 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "HorrorUI.generated.h"
class AHorrorCharacter;
/**
* Simple UI for a first person horror game
* Manages character sprint meter display
*/
UCLASS(abstract)
class FIRST_API UHorrorUI : public UUserWidget
{
GENERATED_BODY()
public:
/** Sets up delegate listeners for the passed character */
void SetupCharacter(AHorrorCharacter* HorrorCharacter);
/** Called when the character's sprint meter is updated */
UFUNCTION()
void OnSprintMeterUpdated(float Percent);
/** Called when the character's sprint state changes */
UFUNCTION()
void OnSprintStateChanged(bool bSprinting);
protected:
/** Passes control to Blueprint to update the sprint meter widgets */
UFUNCTION(BlueprintImplementableEvent, Category="Horror", meta = (DisplayName = "Sprint Meter Updated"))
void BP_SprintMeterUpdated(float Percent);
/** Passes control to Blueprint to update the sprint meter status */
UFUNCTION(BlueprintImplementableEvent, Category="Horror", meta = (DisplayName = "Sprint State Changed"))
void BP_SprintStateChanged(bool bSprinting);
};