Initial Commit - Lesson 31 (Commit #1)

This commit is contained in:
Norman Lansing
2026-02-24 22:39:26 -05:00
commit 9591e7f503
4631 changed files with 1019212 additions and 0 deletions

View File

@@ -0,0 +1,149 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "GameplayTagContainer.h"
#include "Interfaces/PlayerInterface.h"
#include "ShooterTypes/ShooterTypes.h"
#include "ShooterCharacter.generated.h"
class UEliminationComponent;
class UShooterHealthComponent;
class UShooterOverlay;
class UShooterHUDComponent;
class USpringArmComponent;
class UCameraComponent;
class UWeaponData;
class AWeapon;
class UCombatComponent;
class UInputAction;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FWeaponFirstReplicated, AWeapon*, Weapon);
UCLASS()
class FPSTEMPLATE_API AShooterCharacter : public ACharacter, public IPlayerInterface
{
GENERATED_BODY()
public:
AShooterCharacter();
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
virtual void PossessedBy(AController* NewController) override;
virtual void Tick(float DeltaTime) override;
virtual void OnRep_PlayerState() override;
virtual void BeginDestroy() override;
virtual void UnPossessed() override;
FRotator StartingAimRotation;
UPROPERTY(BlueprintReadOnly)
float AO_Yaw;
float InterpAO_Yaw;
UPROPERTY(BlueprintReadOnly)
float MovementOffsetYaw;
UPROPERTY(BlueprintReadOnly)
FTransform FABRIK_SocketTransform;
UPROPERTY(BlueprintReadOnly)
ETurningInPlace TurningStatus;
void TurnInPlace(float DeltaTime);
/** PlayerInterface */
virtual FName GetWeaponAttachPoint_Implementation(const FGameplayTag& WeaponType) const override;
virtual USkeletalMeshComponent* GetSpecifcPawnMesh_Implementation(bool WantFirstPerson) const override;
virtual USkeletalMeshComponent* GetPawnMesh_Implementation() const override;
virtual bool IsFirstPerson_Implementation() const override;
virtual bool DoDamage_Implementation(float DamageAmount, AActor* DamageInstigator) override;
virtual void AddAmmo_Implementation(const FGameplayTag& WeaponType, int32 AmmoAmount) override;
virtual AWeapon* GetCurrentWeapon_Implementation() override;
virtual int32 GetCarriedAmmo_Implementation() override;
virtual void InitializeWidgets_Implementation() override;
virtual void Notify_CycleWeapon_Implementation() override;
virtual void Notify_ReloadWeapon_Implementation() override;
virtual void Initiate_Crouch_Implementation() override;
virtual void Initiate_Jump_Implementation() override;
virtual bool IsDeadOrDying_Implementation() override;
virtual void WeaponReplicated_Implementation() override;
/** <end> PlayerInterface */
UFUNCTION(BlueprintCallable)
FRotator GetFixedAimRotation() const;
bool bWeaponFirstReplicated;
UPROPERTY(BlueprintAssignable)
FWeaponFirstReplicated OnWeaponFirstReplicated;
protected:
virtual void BeginPlay() override;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Aiming")
float DefaultFieldOfView;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Death")
TArray<TObjectPtr<UAnimMontage>> DeathMontages;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "HitReact")
TArray<TObjectPtr<UAnimMontage>> HitReacts;
UFUNCTION(BlueprintImplementableEvent)
void OnAim(bool bIsAiming);
UFUNCTION(BlueprintImplementableEvent)
void DeathEffects(AActor* DeathInstigator, UAnimMontage* DeathMontage);
UFUNCTION(NetMulticast, Reliable)
void Multicast_HitReact(int32 MontageIndex);
private:
void Input_CycleWeapon();
void Input_FireWeapon_Pressed();
void Input_FireWeapon_Released();
void Input_ReloadWeapon();
void Input_Aim_Pressed();
void Input_Aim_Released();
bool IsLocalFirstPerson() const;
UFUNCTION()
void OnDeathStarted(AActor* DyingActor, AActor* DeathInstigator);
/** 1st person view */
UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = Mesh, meta = (AllowPrivateAccess = "true"))
TObjectPtr<USkeletalMeshComponent> Mesh1P;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
TObjectPtr<UCombatComponent> Combat;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
TObjectPtr<UShooterHealthComponent> HealthComponent;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
TObjectPtr<UEliminationComponent> EliminationComponent;
UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
TObjectPtr<USpringArmComponent> SpringArm;
UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
TObjectPtr<UCameraComponent> FirstPersonCamera;
UPROPERTY(EditAnywhere, Category="Input")
TObjectPtr<UInputAction> CycleWeaponAction;
UPROPERTY(EditAnywhere, Category="Input")
TObjectPtr<UInputAction> FireWeaponAction;
UPROPERTY(EditAnywhere, Category="Input")
TObjectPtr<UInputAction> ReloadWeaponAction;
UPROPERTY(EditAnywhere, Category="Input")
TObjectPtr<UInputAction> AimAction;
FTimerHandle InitiializeWidgets_Timer;
};

View File

@@ -0,0 +1,113 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "ShooterHealthComponent.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FShooterHealth_DeathEvent, AActor*, OwningActor, AActor*, Instigator);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_FourParams(FShooterHealth_AttributeChanged, UShooterHealthComponent*, HealthComponent, float, OldValue, float, NewValue, AActor*, Instigator);
/**
* EDeathState
*
* Defines current state of death.
*/
UENUM(BlueprintType)
enum class EDeathState : uint8
{
NotDead = 0,
DeathStarted,
DeathFinished
};
/**
* UShooterHealthComponent
*
* An actor component used to handle anything related to health.
*/
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class FPSTEMPLATE_API UShooterHealthComponent : public UActorComponent
{
GENERATED_BODY()
public:
UShooterHealthComponent();
// Returns the health component if one exists on the specified actor.
UFUNCTION(BlueprintPure, Category = "Shooter|Health")
static UShooterHealthComponent* FindHealthComponent(const AActor* Actor) { return (Actor ? Actor->FindComponentByClass<UShooterHealthComponent>() : nullptr); }
// Returns the current health value.
UFUNCTION(BlueprintCallable, Category = "Shooter|Health")
float GetHealth() const { return Health; };
// Returns the current maximum health value.
UFUNCTION(BlueprintCallable, Category = "Shooter|Health")
float GetMaxHealth() const { return MaxHealth; };
// Returns the current health in the range [0.0, 1.0].
UFUNCTION(BlueprintCallable, Category = "Shooter|Health")
float GetHealthNormalized() const;
UFUNCTION(BlueprintCallable, Category = "Shooter|Health")
EDeathState GetDeathState() const { return DeathState; }
UFUNCTION(BlueprintCallable, BlueprintPure = false, Category = "Shooter|Health", Meta = (ExpandBoolAsExecs = "ReturnValue"))
bool IsDeadOrDying() const { return (DeathState > EDeathState::NotDead); }
// Begins the death sequence for the owner.
virtual void StartDeath(AActor* Instigator);
// Ends the death sequence for the owner.
virtual void FinishDeath(AActor* Instigator);
public:
// Delegate fired when the health value has changed. This is called on the client but the instigator may not be valid
UPROPERTY(BlueprintAssignable)
FShooterHealth_AttributeChanged OnHealthChanged;
// Delegate fired when the max health value has changed. This is called on the client but the instigator may not be valid
UPROPERTY(BlueprintAssignable)
FShooterHealth_AttributeChanged OnMaxHealthChanged;
// Delegate fired when the death sequence has started.
UPROPERTY(BlueprintAssignable)
FShooterHealth_DeathEvent OnDeathStarted;
// Delegate fired when the death sequence has finished.
UPROPERTY(BlueprintAssignable)
FShooterHealth_DeathEvent OnDeathFinished;
// return true if lethal
virtual bool ChangeHealthByAmount(float Amount, AActor* Instigator);
virtual void ChangeMaxHealthByAmount(float Amount, AActor* Instigator);
protected:
virtual void BeginPlay() override;
virtual void HandleOutOfHealth();
UFUNCTION()
virtual void OnRep_DeathState(EDeathState OldDeathState);
// Replicated state used to handle dying.
UPROPERTY(ReplicatedUsing = OnRep_DeathState)
EDeathState DeathState;
UPROPERTY(ReplicatedUsing=OnRep_Health)
float Health;
UPROPERTY(ReplicatedUsing=OnRep_MaxHealth)
float MaxHealth;
UFUNCTION()
void OnRep_Health(float OldValue);
UFUNCTION()
void OnRep_MaxHealth(float OldValue);
};

View File

@@ -0,0 +1,155 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "GameplayTagContainer.h"
#include "ShooterTypes/ShooterTypes.h"
#include "CombatComponent.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FReticleChangedDelegate, UMaterialInstanceDynamic*, ReticleDynMatInst, const FReticleParams&, ReticleParams, bool, bCurrentlyTargetingPlayer);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FAmmoCounterChangedDelegate, UMaterialInstanceDynamic*, AmmoCounterDynMatInst, int32, RoundsCurrent, int32, RoundsMax);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FTargetingPlayerStatusChangedDelegate, bool, bIsTargetingPlayer);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FRoundFiredDelegate, int32, RoundsCurrent, int32, RoundsMax, int32, RoundsCarried);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FAimingStatusChangedDelegate, bool, bIsAiming);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FCarriedAmmoChangedDelegate, UMaterialInstanceDynamic*, WeaponIconDynMatInst, int32, InCarriedAmmo, int32, RoundsInWeapon);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_FiveParams(FRoundReportedDelegate, AActor*, Attacker, AActor*, Victim, bool, bHit, bool, bHeadShot, bool, bLethal);
class UShooterOverlay;
class UWeaponData;
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class FPSTEMPLATE_API UCombatComponent : public UActorComponent
{
GENERATED_BODY()
public:
UCombatComponent();
void Initiate_CycleWeapon();
void Notify_CycleWeapon();
void Notify_ReloadWeapon();
void Initiate_FireWeapon_Pressed();
void Initiate_FireWeapon_Released();
void Initiate_ReloadWeapon();
void Initiate_AimPressed();
void Initiate_AimReleased();
UFUNCTION(BlueprintImplementableEvent)
void OnAim(bool bIsAiming);
UFUNCTION(BlueprintPure, Category = "Shooter|Health")
static UCombatComponent* FindCombatComponent(const AActor* Actor) { return (Actor ? Actor->FindComponentByClass<UCombatComponent>() : nullptr); }
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
void AddAmmo(FGameplayTag WeaponType, int32 AmmoAmount);
void InitializeWeaponWidgets() const;
void SpawnDefaultInventory();
void DestroyInventory();
UFUNCTION(Reliable, Server)
void ServerEquipWeapon(AWeapon* NewWeapon);
UPROPERTY(BlueprintReadOnly, Replicated)
bool bAiming;
UPROPERTY(BlueprintAssignable, Category=Combat)
FReticleChangedDelegate OnReticleChanged;
UPROPERTY(BlueprintAssignable, Category=Combat)
FAmmoCounterChangedDelegate OnAmmoCounterChanged;
UPROPERTY(BlueprintAssignable, Category=Combat)
FTargetingPlayerStatusChangedDelegate OnTargetingPlayerStatusChanged;
UPROPERTY(BlueprintAssignable, Category=Combat)
FRoundFiredDelegate OnRoundFired;
UPROPERTY(BlueprintAssignable, Category=Combat)
FAimingStatusChangedDelegate OnAimingStatusChanged;
UPROPERTY(BlueprintAssignable, Category=Combat)
FCarriedAmmoChangedDelegate OnCarriedAmmoChanged;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Weapon")
TObjectPtr<UWeaponData> WeaponData;
UPROPERTY(ReplicatedUsing = OnRep_CarriedAmmo)
int32 CarriedAmmo;
TMap<FGameplayTag, int32> CarriedAmmoMap;
UPROPERTY(EditDefaultsOnly, Category = Inventory)
TArray<TSubclassOf<AWeapon>> DefaultInventoryClasses;
UPROPERTY(Transient, Replicated)
TArray<AWeapon*> Inventory;
UPROPERTY(Transient, ReplicatedUsing = OnRep_CurrentWeapon, BlueprintReadOnly)
TObjectPtr<AWeapon> CurrentWeapon;
UPROPERTY(EditDefaultsOnly)
float TraceLength;
UPROPERTY(BlueprintReadOnly)
FPlayerHitResult Local_PlayerHitResult;
UPROPERTY(BlueprintAssignable)
FRoundReportedDelegate OnRoundReported;
protected:
virtual void BeginPlay() override;
private:
void SetCurrentWeapon(AWeapon* NewWeapon, AWeapon* LastWeapon = nullptr);
void AddWeapon(AWeapon* Weapon);
void EquipWeapon(AWeapon* Weapon);
void Local_CycleWeapon(const int32 WeaponIndex);
void FireTimerFinished();
int32 AdvanceWeaponIndex();
void Local_ReloadWeapon();
void Local_Aim(bool bPressed);
FVector HitScanTrace(float SweepRadius, FHitResult& OutHit);
UFUNCTION(Server, Reliable)
void Server_CycleWeapon(const int32 WeaponIndex);
UFUNCTION(NetMulticast, Reliable)
void Multicast_CycleWeapon(const int32 WeaponIndex);
UFUNCTION()
void BlendOut_CycleWeapon(UAnimMontage* Montage, bool bInterrupted);
void Local_FireWeapon();
UFUNCTION(Server, Reliable)
void Server_FireWeapon(const FVector_NetQuantize& TraceStart, const FHitResult& Impact, bool bScoredHit, bool bHeadShot);
UFUNCTION(NetMulticast, Reliable)
void Multicast_FireWeapon(const FHitResult& Impact, int32 AuthAmmo);
UFUNCTION(Server, Reliable)
void Server_ReloadWeapon(bool bLocalOwnerReload = false);
UFUNCTION(NetMulticast, Reliable)
void Multicast_ReloadWeapon(int32 NewWeaponAmmo, int32 NewCarriedAmmo, bool bLocalOwnerReload = false);
UFUNCTION(Client, Reliable)
void Client_ReloadWeapon(int32 NewWeaponAmmo, int32 NewCarriedAmmo);
UFUNCTION(Server, Reliable)
void Server_Aim(bool bPressed);
UFUNCTION()
void OnRep_CurrentWeapon(AWeapon* LastWeapon);
UFUNCTION()
void OnRep_CarriedAmmo();
int32 Local_WeaponIndex;
bool bTriggerPressed;
FTimerHandle FireTimer;
};

View File

@@ -0,0 +1,42 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataAsset.h"
#include "ShooterTypes/ShooterTypes.h"
#include "SpecialElimData.generated.h"
USTRUCT(BlueprintType)
struct FSpecialElimInfo
{
GENERATED_BODY()
UPROPERTY(BlueprintReadOnly)
ESpecialElimType ElimType = ESpecialElimType::None;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
FString ElimMessage = FString();
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
TObjectPtr<UTexture2D> ElimIcon = nullptr;
UPROPERTY(BlueprintReadOnly)
int32 SequentialElimCount = 0;
UPROPERTY(BlueprintReadOnly)
int32 StreakCount = 0;
};
/**
*
*/
UCLASS()
class FPSTEMPLATE_API USpecialElimData : public UDataAsset
{
GENERATED_BODY()
public:
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "SpecialEliminations")
TMap<ESpecialElimType, FSpecialElimInfo> SpecialElimInfo;
};

View File

@@ -0,0 +1,78 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameplayTagContainer.h"
#include "Engine/DataAsset.h"
#include "WeaponData.generated.h"
USTRUCT(BlueprintType)
struct FPlayerAnims
{
GENERATED_BODY()
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
TObjectPtr<UAnimSequence> IdleAnim = nullptr;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
TObjectPtr<UAnimSequence> AimIdleAnim = nullptr;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
TObjectPtr<UAnimSequence> CrouchIdleAnim = nullptr;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
TObjectPtr<UAnimSequence> SprintAnim = nullptr;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
TObjectPtr<UBlendSpace> AimOffset_Hip = nullptr;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
TObjectPtr<UBlendSpace> AimOffset_Aim = nullptr;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
TObjectPtr<UBlendSpace> Strafe_Standing = nullptr;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
TObjectPtr<UBlendSpace> Strafe_Crouching = nullptr;
};
USTRUCT(BlueprintType)
struct FMontageData
{
GENERATED_BODY()
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
TObjectPtr<UAnimMontage> EquipMontage = nullptr;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
TObjectPtr<UAnimMontage> ReloadMontage = nullptr;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
TObjectPtr<UAnimMontage> FireMontage = nullptr;
};
UCLASS()
class FPSTEMPLATE_API UWeaponData : public UDataAsset
{
GENERATED_BODY()
public:
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "WeaponData|FirstPerson")
TMap<FGameplayTag, FPlayerAnims> FirstPersonAnims;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "WeaponData|ThirdPerson")
TMap<FGameplayTag, FPlayerAnims> ThirdPersonAnims;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "WeaponData|Weapons")
TMap<FGameplayTag, FMontageData> WeaponMontages;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "WeaponData|Weapons")
TMap<FGameplayTag, FName> GripPoints;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "WeaponData|FirstPerson")
TMap<FGameplayTag, FMontageData> FirstPersonMontages;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "WeaponData|ThirdPerson")
TMap<FGameplayTag, FMontageData> ThirdPersonMontages;
};

View File

@@ -0,0 +1,47 @@
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "ShooterTypes/ShooterTypes.h"
#include "EliminationComponent.generated.h"
class AMatchPlayerState;
class AMatchGameState;
UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent))
class FPSTEMPLATE_API UEliminationComponent : public UActorComponent
{
GENERATED_BODY()
public:
UEliminationComponent();
UFUNCTION()
void OnRoundReported(AActor* Attacker, AActor* Victim, bool bHit, bool bHeadShot, bool bLethal);
protected:
virtual void BeginPlay() override;
private:
// Time frame to determine sequential elims
UPROPERTY(EditDefaultsOnly, Category = Elimination)
float SequentialElimInterval;
UPROPERTY(EditDefaultsOnly, Category = Elimination)
int32 ElimsNeededForStreak;
float LastElimTime;
int32 SequentialElims;
int32 Streak;
AMatchPlayerState* GetPlayerStateFromActor(AActor* Actor);
void ProcessHitOrMiss(bool bHit, AMatchPlayerState* AttackerPS);
void ProcessElimination(bool bHeadShot, AMatchPlayerState* AttackerPS, AMatchPlayerState* VictimPS);
void ProcessHeadshot(bool bHeadShot, ESpecialElimType& SpecialElimType, AMatchPlayerState* AttackerPS);
void ProcessSequentialEliminations(AMatchPlayerState* AttackerPS, ESpecialElimType& SpecialElimType);
void ProcessStreaks(AMatchPlayerState* AttackerPS, AMatchPlayerState* VictimPS, ESpecialElimType& SpecialElimType);
void HandleFirstBlood(AMatchGameState* GameState, ESpecialElimType& SpecialElimType, AMatchPlayerState* AttackerPS);
void UpdateLeaderStatus(AMatchGameState* GameState, ESpecialElimType& SpecialElimType, AMatchPlayerState* AttackerPS, AMatchPlayerState* VictimPS);
bool HasSpecialElimTypes(const ESpecialElimType& SpecialElimType);
};

View File

@@ -0,0 +1,37 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/GameState.h"
#include "MatchGameState.generated.h"
class AMatchPlayerState;
/**
*
*/
UCLASS()
class FPSTEMPLATE_API AMatchGameState : public AGameState
{
GENERATED_BODY()
public:
AMatchGameState();
AMatchPlayerState* GetLeader() const;
void UpdateLeader();
bool HasFirstBloodBeenHad() const { return bHasFirstBloodBeenHad; }
bool IsTiedForTheLead(AMatchPlayerState* PlayerState);
protected:
virtual void BeginPlay() override;
private:
UPROPERTY()
TArray<TObjectPtr<AMatchPlayerState>> Leaders;
UPROPERTY()
TArray<TObjectPtr<AMatchPlayerState>> SortedPlayerStates;
bool bHasFirstBloodBeenHad;
};

View File

@@ -0,0 +1,44 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "ShooterGameModeBase.h"
#if WITH_GAMELIFT
#include "GameLiftServerSDK.h"
#endif
#include "ShooterGameMode.generated.h"
struct FProcessParameters;
DECLARE_LOG_CATEGORY_EXTERN(LogShooterGameMode, Log, All);
/**
*
*/
UCLASS()
class FPSTEMPLATE_API AShooterGameMode : public AShooterGameModeBase
{
GENERATED_BODY()
public:
AShooterGameMode();
protected:
virtual void BeginPlay() override;
private:
void InitGameLift();
#if WITH_GAMELIFT
void SetServerParameters(TSharedPtr<FServerParameters> OutServerParameters);
void LogServerParameters(TSharedPtr<FServerParameters> ServerParameters);
#endif
void ParseCommandLinePort(int32& OutPort);
TSharedPtr<FProcessParameters> ProcessParameters;
};

View File

@@ -0,0 +1,30 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/GameMode.h"
#include "ShooterGameModeBase.generated.h"
/**
*
*/
UCLASS()
class FPSTEMPLATE_API AShooterGameModeBase : public AGameMode
{
GENERATED_BODY()
public:
AShooterGameModeBase();
virtual void Tick(float DeltaTime) override;
virtual void StartPlayerElimination(float ElimTime, ACharacter* ElimmedCharacter, class APlayerController* VictimController, APlayerController* AttackerController);
UPROPERTY()
TMap<APlayerController*, FTimerHandle> Timers;
virtual void PlayerEliminated(ACharacter* ElimmedCharacter, class APlayerController* VictimController, APlayerController* AttackerController);
virtual void RequestRespawn(ACharacter* ElimmedCharacter, AController* ElimmedController);
UPROPERTY(EditDefaultsOnly, Category="Respawning")
float RespawnTime;
};

View File

@@ -0,0 +1,90 @@
#pragma once
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "PlayerInterface.generated.h"
class UShooterOverlay;
struct FGameplayTag;
class AWeapon;
// This class does not need to be modified.
UINTERFACE(MinimalAPI)
class UPlayerInterface : public UInterface
{
GENERATED_BODY()
};
class FPSTEMPLATE_API IPlayerInterface
{
GENERATED_BODY()
// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
FName GetWeaponAttachPoint(const FGameplayTag& WeaponType) const;
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
USkeletalMeshComponent* GetSpecifcPawnMesh(bool WantFirstPerson) const;
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
USkeletalMeshComponent* GetPawnMesh() const;
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
bool IsFirstPerson() const;
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
void Initiate_CycleWeapon();
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
void Notify_CycleWeapon();
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
void Notify_ReloadWeapon();
UFUNCTION(BlueprintNativeEvent)
void Initiate_FireWeapon_Pressed();
UFUNCTION(BlueprintNativeEvent)
void Initiate_FireWeapon_Released();
UFUNCTION(BlueprintNativeEvent)
void Initiate_ReloadWeapon();
UFUNCTION(BlueprintNativeEvent)
void Initiate_Aim_Pressed();
UFUNCTION(BlueprintNativeEvent)
void Initiate_Aim_Released();
UFUNCTION(BlueprintNativeEvent)
void Initiate_Crouch();
UFUNCTION(BlueprintNativeEvent)
void Initiate_Jump();
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
bool DoDamage(float DamageAmount, AActor* DamageInstigator);
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
void AddAmmo(const FGameplayTag& WeaponType, int32 AmmoAmount);
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
AWeapon* GetCurrentWeapon();
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
int32 GetCarriedAmmo();
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
void InitializeWidgets();
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
bool IsDeadOrDying();
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
void WeaponReplicated();
};

View File

@@ -0,0 +1,92 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/PlayerState.h"
#include "Data/SpecialElimData.h"
#include "MatchPlayerState.generated.h"
enum class ESpecialElimType : uint16;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnScoreChanged, int32, NewScore);
/**
*
*/
UCLASS()
class FPSTEMPLATE_API AMatchPlayerState : public APlayerState
{
GENERATED_BODY()
public:
AMatchPlayerState();
void AddScoredElim();
void AddDefeat();
void AddHit();
void AddMiss();
APlayerState* GetLastAttacker() const { return LastAttacker; }
void SetLastAttacker(APlayerState* Attacker) { LastAttacker = Attacker; }
bool IsOnStreak() const { return bOnStreak; }
void SetOnStreak(bool bIsOnStreak) { bOnStreak = bIsOnStreak; }
int32 GetScoredElims() const { return ScoredElims; }
void AddHeadShotElim();
void AddSequentialElim(int32 SequenceCount);
void UpdateHighestStreak(int32 StreakCount);
void AddRevengeElim();
void AddDethroneElim();
void AddShowStopperElim();
void GotFirstBlood();
void IsTheWinner();
UFUNCTION(Client, Reliable)
void Client_SpecialElim(const ESpecialElimType& SpecialElim, int32 SequentialElimCount, int32 StreakCount, int32 ElimScore);
UFUNCTION(Client, Reliable)
void Client_ScoredElim(int32 ElimScore);
UFUNCTION(Client, Reliable)
void Client_LostTheLead();
UPROPERTY(BlueprintAssignable)
FOnScoreChanged OnScoreChanged;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
TObjectPtr<USpecialElimData> SpecialElimData;
TArray<ESpecialElimType> DecodeElimBitmask(ESpecialElimType ElimTypeBitmask);
protected:
UPROPERTY(EditDefaultsOnly, Category = "UI")
TSubclassOf<UUserWidget> SpecialElimWidgetClass;
private:
int32 ScoredElims;
int32 Defeats;
int32 Hits;
int32 Misses;
bool bOnStreak;
int32 HeadShotElims;
TMap<int32, int32> SequentialElims;
int32 HighestStreak;
int32 RevengeElims;
int32 DethroneElims;
int32 ShowStopperElims;
bool bFirstBlood;
bool bWinner;
UPROPERTY()
TObjectPtr<APlayerState> LastAttacker;
TQueue<FSpecialElimInfo> SpecialElimQueue;
bool bIsProcessingQueue;
void ProcessNextSpecialElim();
void ShowSpecialElim(const FSpecialElimInfo& ElimMessageInfo);
};

View File

@@ -0,0 +1,58 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "ShooterPlayerController.generated.h"
struct FInputActionValue;
class UInputMappingContext;
class UInputAction;
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnPlayerStateReplicated);
/**
*
*/
UCLASS()
class FPSTEMPLATE_API AShooterPlayerController : public APlayerController
{
GENERATED_BODY()
public:
AShooterPlayerController();
bool bPawnAlive;
virtual void OnPossess(APawn* InPawn) override;
virtual void OnRep_PlayerState() override;
UPROPERTY(BlueprintAssignable)
FOnPlayerStateReplicated OnPlayerStateReplicated;
protected:
virtual void BeginPlay() override;
virtual void SetupInputComponent() override;
private:
UPROPERTY(EditAnywhere, Category="Input")
TObjectPtr<UInputMappingContext> ShooterIMC;
UPROPERTY(EditAnywhere, Category="Input")
TObjectPtr<UInputAction> MoveAction;
UPROPERTY(EditAnywhere, Category="Input")
TObjectPtr<UInputAction> LookAction;
UPROPERTY(EditAnywhere, Category="Input")
TObjectPtr<UInputAction> CrouchAction;
UPROPERTY(EditAnywhere, Category="Input")
TObjectPtr<UInputAction> JumpAction;
void Input_Move(const FInputActionValue& InputActionValue);
void Input_Look(const FInputActionValue& InputActionValue);
void Input_Crouch();
void Input_Jump();
};

View File

@@ -0,0 +1,89 @@
#pragma once
#include "ShooterTypes.generated.h"
USTRUCT(BlueprintType)
struct FPlayerHitResult
{
GENERATED_BODY()
UPROPERTY(BlueprintReadWrite)
FVector_NetQuantize Start = FVector_NetQuantize::ZeroVector;
UPROPERTY(BlueprintReadWrite)
FVector_NetQuantize End = FVector_NetQuantize::ZeroVector;
UPROPERTY(BlueprintReadWrite)
bool bHitPlayer = false;
UPROPERTY(BlueprintReadWrite)
bool bHitPlayerLastFrame = false;
UPROPERTY(BlueprintReadWrite)
bool bHeadShot = false;
};
USTRUCT(BlueprintType)
struct FReticleParams
{
GENERATED_BODY()
UPROPERTY(BlueprintReadWrite, EditAnywhere)
float ScaleFactor_Targeting = 0.f;
UPROPERTY(BlueprintReadWrite, EditAnywhere)
float ScaleFactor_NotTargeting = 0.f;
UPROPERTY(BlueprintReadWrite, EditAnywhere)
float ScaleFactor_Aiming = 0.f;
UPROPERTY(BlueprintReadWrite, EditAnywhere)
float ScaleFactor_NotAiming = 0.f;
UPROPERTY(BlueprintReadWrite, EditAnywhere)
float ShapeCutFactor_Aiming = 0.f;
UPROPERTY(BlueprintReadWrite, EditAnywhere)
float ShapeCutFactor_NotAiming = 0.f;
UPROPERTY(BlueprintReadWrite, EditAnywhere)
float ShapeCutFactor_RoundFired = 0.f;
UPROPERTY(BlueprintReadWrite, EditAnywhere)
float ScaleFactor_RoundFired = 0.f;
UPROPERTY(BlueprintReadWrite, EditAnywhere)
float AimingInterpSpeed = 15.f;
UPROPERTY(BlueprintReadWrite, EditAnywhere)
float TargetingPlayerInterpSpeed = 10.f;
UPROPERTY(BlueprintReadWrite, EditAnywhere)
float RoundFiredInterpSpeed = 20.f;
};
UENUM(BlueprintType)
enum class ETurningInPlace : uint8
{
Left UMETA(DisplayName = "TurningLeft"),
Right UMETA(DisplayName = "TurningRight"),
NotTurning UMETA(DisplayName = "NotTurning")
};
UENUM(meta = (Bitflags))
enum class ESpecialElimType : uint16
{
None = 0,
Headshot = 1 << 0, // 00000000 00000001
Sequential = 1 << 1, // 00000000 00000010
Streak = 1 << 2, // 00000000 00000100
Revenge = 1 << 3, // 00000000 00001000
Dethrone = 1 << 4, // 00000000 00010000
Showstopper = 1 << 5, // 00000000 00100000
FirstBlood = 1 << 6, // 00000000 01000000
GainedTheLead = 1 << 7, // 00000000 10000000
TiedTheLeader = 1 << 8, // 00000001 00000000
LostTheLead = 1 << 9 // 00000010 00000000
};
ENUM_CLASS_FLAGS(ESpecialElimType)

View File

@@ -0,0 +1,11 @@
#pragma once
#include "CoreMinimal.h"
#include "NativeGameplayTags.h"
namespace ShooterTags
{
UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_WeaponType_None);
UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_WeaponType_Pistol);
UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_WeaponType_Rifle);
}

View File

@@ -0,0 +1,33 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "ScoreWidget.generated.h"
class UTextBlock;
class AMatchPlayerState;
/**
*
*/
UCLASS()
class FPSTEMPLATE_API UScoreWidget : public UUserWidget
{
GENERATED_BODY()
public:
virtual void NativeConstruct() override;
UPROPERTY(meta = (BindWidget))
UTextBlock* ScoreText;
protected:
UFUNCTION()
void OnScoreChanged(int32 NewScore);
UFUNCTION()
void OnPlayerStateInitialized();
AMatchPlayerState* GetPlayerState() const;
};

View File

@@ -0,0 +1,29 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "SpecialElimWidget.generated.h"
class UTextBlock;
class UImage;
/**
*
*/
UCLASS()
class FPSTEMPLATE_API USpecialElimWidget : public UUserWidget
{
GENERATED_BODY()
public:
UPROPERTY(meta = (BindWidget))
TObjectPtr<UTextBlock> ElimText;
UPROPERTY(meta = (BindWidget), BlueprintReadOnly, EditDefaultsOnly)
TObjectPtr<UImage> ElimImage;
void InitializeWidget(const FString& InElimMessage, UTexture2D* InElimTexture);
UFUNCTION(BlueprintCallable)
static void CenterWidget(UUserWidget* Widget, float VerticalRatio = 0.f);
};

View File

@@ -0,0 +1,49 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "ShooterAmmoCounter.generated.h"
class UImage;
class UTextBlock;
/**
*
*/
UCLASS()
class FPSTEMPLATE_API UShooterAmmoCounter : public UUserWidget
{
GENERATED_BODY()
public:
virtual void NativeConstruct() override;
UPROPERTY(meta = (BindWidget))
TObjectPtr<UImage> Image_WeaponIcon;
UPROPERTY(meta = (BindWidget))
TObjectPtr<UTextBlock> Text_Ammo;
UPROPERTY()
TObjectPtr<UMaterialInstanceDynamic> CurrentWeaponIcon_DynMatInst;
private:
int32 TotalAmmo;
UFUNCTION()
void OnPossessedPawnChanged(APawn* OldPawn, APawn* NewPawn);
UFUNCTION()
void OnCarriedAmmoChanged(UMaterialInstanceDynamic* WeaponIconDynMatInst, int32 InCarriedAmmo, int32 RoundsInWeapon);
UFUNCTION()
void OnRoundFired(int32 RoundsCurrent, int32 RoundsMax, int32 RoundsCarried);
UFUNCTION()
void OnWeaponFirstReplicated(AWeapon* Weapon);
};

View File

@@ -0,0 +1,31 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/HUD.h"
#include "ShooterHUD.generated.h"
class UUserWidget;
/**
*
*/
UCLASS()
class FPSTEMPLATE_API AShooterHUD : public AHUD
{
GENERATED_BODY()
public:
UUserWidget* GetShooterOverlay() {return Overlay;}
protected:
virtual void BeginPlay() override;
private:
UPROPERTY(EditDefaultsOnly, Category = "Overlay")
TSubclassOf<UUserWidget> ShooterOverlayClass;
UPROPERTY()
TObjectPtr<UUserWidget> Overlay;
};

View File

@@ -0,0 +1,86 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "ShooterTypes/ShooterTypes.h"
#include "ShooterReticle.generated.h"
namespace Reticle
{
extern FPSTEMPLATE_API const FName Inner_RGBA;
extern FPSTEMPLATE_API const FName RoundedCornerScale;
extern FPSTEMPLATE_API const FName ShapeCutThickness;
}
namespace Ammo
{
extern FPSTEMPLATE_API const FName Rounds_Current;
extern FPSTEMPLATE_API const FName Rounds_Max;
}
class UImage;
class AWeapon;
/**
*
*/
UCLASS()
class FPSTEMPLATE_API UShooterReticle : public UUserWidget
{
GENERATED_BODY()
public:
virtual void NativeConstruct() override;
virtual void NativeTick(const FGeometry& MyGeometry, float InDeltaTime) override;
UPROPERTY(meta = (BindWidget))
TObjectPtr<UImage> Image_Reticle;
UPROPERTY(meta = (BindWidget))
TObjectPtr<UImage> Image_AmmoCounter;
private:
UPROPERTY()
TObjectPtr<UMaterialInstanceDynamic> CurrentReticle_DynMatInst;
UPROPERTY()
TObjectPtr<UMaterialInstanceDynamic> CurrentAmmoCounter_DynMatInst;
FReticleParams CurrentReticleParams;
float BaseCornerScaleFactor;
float _BaseCornerScaleFactor_TargetingPlayer;
float _BaseCornerScaleFactor_Aiming;
float _BaseCornerScaleFactor_RoundFired;
float BaseShapeCutFactor;
float _BaseShapeCutFactor_Aiming;
float _BaseShapeCutFactor_RoundFired;
bool bTargetingPlayer;
bool bAiming;
UFUNCTION()
void OnPossessedPawnChanged(APawn* OldPawn, APawn* NewPawn);
UFUNCTION()
void OnReticleChange(UMaterialInstanceDynamic* ReticleDynMatInst, const FReticleParams& ReticleParams, bool bCurrentlyTargetingPlayer = false);
UFUNCTION()
void OnAmmoCounterChange(UMaterialInstanceDynamic* AmmoCounterDynMatInst, int32 RoundsCurrent, int32 RoundsMax);
UFUNCTION()
void OnTargetingPlayerStatusChanged(bool bIsTargetingPlayer);
UFUNCTION()
void OnRoundFired(int32 RoundsCurrent, int32 RoundsMax, int32 RoundsCarried);
UFUNCTION()
void OnAimingStatusChanged(bool bIsAiming);
UFUNCTION()
void OnWeaponFirstReplicated(AWeapon* Weapon);
};

View File

@@ -0,0 +1,164 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "GameplayTagContainer.h"
#include "ShooterTypes/ShooterTypes.h"
#include "Weapon.generated.h"
struct FPlayerHitResult;
/** Enum used to describe what state the weapon is currently in. */
UENUM(BlueprintType)
namespace EWeaponState
{
enum Type
{
Idle,
Firing,
Reloading,
Equipping,
};
}
UENUM(BlueprintType)
namespace EFireType
{
enum Type
{
Auto,
SemiAuto
};
}
UCLASS()
class FPSTEMPLATE_API AWeapon : public AActor
{
GENERATED_BODY()
public:
AWeapon();
virtual void Tick(float DeltaTime) override;
virtual void OnRep_Instigator() override;
/** perform initial setup */
virtual void PostInitializeComponents() override;
UPROPERTY(BlueprintReadOnly, EditAnywhere)
FGameplayTag WeaponType;
//////////////////////////////////////////////////////////////////////////
// Firing the Weapon
void Local_Fire(const FVector& ImpactPoint, const FVector& ImpactNormal, TEnumAsByte<EPhysicalSurface> SurfaceType, bool bIsFirstPerson);
int32 Auth_Fire();
void Rep_Fire(int32 AuthAmmo);
UFUNCTION(BlueprintImplementableEvent)
void FireEffects(const FVector& ImpactPoint, const FVector& ImpactNormal, EPhysicalSurface SurfaceType, bool bIsFirstPerson);
//////////////////////////////////////////////////////////////////////////
// Inventory
/** [server] weapon was added to pawn's inventory */
virtual void OnEnterInventory(APawn* NewOwner);
/** weapon is holstered by owner pawn */
virtual void OnUnEquip();
/** weapon is being equipped by owner pawn */
virtual void OnEquip(const AWeapon* LastWeapon);
/** set the weapon's owning pawn */
void SetOwningPawn(APawn* NewOwningPawn);
/** get weapon mesh (needs pawn owner to determine variant) */
USkeletalMeshComponent* GetWeaponMesh() const;
/** update weapon state */
void SetWeaponState(EWeaponState::Type NewState);
EWeaponState::Type GetWeaponState() const;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
int32 MagCapacity;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
int32 Ammo;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
int32 Sequence;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
int32 StartingCarriedAmmo;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
float Damage;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
float AimFieldOfView;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
float HeadShotDamage;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
float FireTime;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
TEnumAsByte<EFireType::Type> FireType;
USkeletalMeshComponent* GetMesh1P() const;
USkeletalMeshComponent* GetMesh3P() const;
UMaterialInstanceDynamic* GetReticleDynamicMaterialInstance();
UMaterialInstanceDynamic* GetAmmoCounterDynamicMaterialInstance();
UMaterialInstanceDynamic* GetWeaponIconDynamicMaterialInstance();
UPROPERTY(EditDefaultsOnly, Category=Reticle)
FReticleParams ReticleParams;
protected:
virtual void BeginPlay() override;
//////////////////////////////////////////////////////////////////////////
// Inventory
/** attaches weapon mesh to pawn's mesh */
void AttachMeshToPawn();
/** detaches weapon mesh from pawn */
void DetachMeshFromPawn();
private:
/** weapon mesh: 1st person view */
UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category=Mesh, meta = (AllowPrivateAccess = "true"))
TObjectPtr<USkeletalMeshComponent> Mesh1P;
/** weapon mesh: 3rd person view */
UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category=Mesh, meta = (AllowPrivateAccess = "true"))
TObjectPtr<USkeletalMeshComponent> Mesh3P;
/** current weapon state */
EWeaponState::Type CurrentState;
UPROPERTY(EditDefaultsOnly, Category=Weapon)
TObjectPtr<UMaterialInterface> ReticleMaterial;
UPROPERTY()
TObjectPtr<UMaterialInstanceDynamic> DynMatInst_Reticle;
UPROPERTY(EditDefaultsOnly, Category=Weapon)
TObjectPtr<UMaterialInterface> AmmoCounterMaterial;
UPROPERTY()
TObjectPtr<UMaterialInstanceDynamic> DynMatInst_AmmoCounter;
UPROPERTY(EditDefaultsOnly, Category=Weapon)
TObjectPtr<UMaterialInterface> WeaponIconMaterial;
UPROPERTY()
TObjectPtr<UMaterialInstanceDynamic> DynMatInst_WeaponIcon;
};