Implemented a Gadget Base and Manager

Tested using test gadgets without any behaviour beyond uelogs
This commit is contained in:
Rafal Swierczek 2023-09-29 20:00:25 +01:00
parent fa3e28f075
commit fa8c6f681c
26 changed files with 553 additions and 11 deletions

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:d567687e62b21f8c8c96c320928de71d9c2de143c13ae51aa7484f74e0abe0bc oid sha256:3192f3e53f9cde4484a9e8fd75184a71bf9ea1da5876fee94ceded15c274685a
size 25589 size 26191

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e321d507454cc656ecee8ffaa8ce7a439b7bc824731e2932c160289609e6fe14
size 22647

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:83a5888b61a03cd032e12e5ed42b2aa5f13ca709b06b50ed9726e7404419cfea
size 29907

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:9c379fa13b284e76785e0bca667577f04256220a612899c64cdfbbbaaf5b7c47 oid sha256:5187272f65c655c1bbca4f6a814ab42219fcb74a566fb68d72cc23cfa8b92999
size 99918 size 101262

Binary file not shown.

View File

@ -50,7 +50,11 @@ void AEndlessVendettaCharacter::BeginPlay()
Subsystem->AddMappingContext(DefaultMappingContext, 0); Subsystem->AddMappingContext(DefaultMappingContext, 0);
} }
} }
AActor* GadgetManagerActor = GetWorld()->SpawnActor<AActor>(GadgetManagerClass, GetActorLocation(), GetActorRotation());
GadgetManager = Cast<AGadgetManager>(GadgetManagerActor);
FAttachmentTransformRules AttachmentRules(EAttachmentRule::SnapToTarget, true);
GadgetManagerActor->AttachToComponent(GetRootComponent(), AttachmentRules);
GadgetManager->SpawnGadgets(GetRootComponent());
} }
//////////////////////////////////////////////////////////////////////////// Input //////////////////////////////////////////////////////////////////////////// Input
@ -70,6 +74,10 @@ void AEndlessVendettaCharacter::SetupPlayerInputComponent(class UInputComponent*
//Looking //Looking
EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &AEndlessVendettaCharacter::Look); EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &AEndlessVendettaCharacter::Look);
// Gadget Toggling
EnhancedInputComponent->BindAction(ReconAction, ETriggerEvent::Started, this, &AEndlessVendettaCharacter::ToggleRecon);
EnhancedInputComponent->BindAction(CombatAction, ETriggerEvent::Started, this, &AEndlessVendettaCharacter::ToggleCombat);
//Weapon Switching //Weapon Switching
EnhancedInputComponent->BindAction(EquipPrimaryWeapon, ETriggerEvent::Triggered, this, &AEndlessVendettaCharacter::EquipPrimary); EnhancedInputComponent->BindAction(EquipPrimaryWeapon, ETriggerEvent::Triggered, this, &AEndlessVendettaCharacter::EquipPrimary);
EnhancedInputComponent->BindAction(EquipSecondaryWeapon, ETriggerEvent::Triggered, this, &AEndlessVendettaCharacter::EquipSecondary); EnhancedInputComponent->BindAction(EquipSecondaryWeapon, ETriggerEvent::Triggered, this, &AEndlessVendettaCharacter::EquipSecondary);
@ -79,6 +87,47 @@ void AEndlessVendettaCharacter::SetupPlayerInputComponent(class UInputComponent*
} }
} }
void AEndlessVendettaCharacter::ToggleRecon()
{
if (IsValid(PrimaryWeapon)) EquipPrimary();
if (IsValid(SecondaryWeapon)) EquipSecondary();
if (GadgetManager->IsReconEquipped())
{
GadgetManager->TryToUnequipRecon();
return;
}
if (GadgetManager->IsCombatEquipped() && !GadgetManager->TryToUnequipCombat())
{
// Do nothing if combat is equipped and can't be unequipped at this moment
return;
}
GadgetManager->EquipRecon();
}
void AEndlessVendettaCharacter::ToggleCombat()
{
if (IsValid(PrimaryWeapon)) EquipPrimary();
if (IsValid(SecondaryWeapon)) EquipSecondary();
if (GadgetManager->IsCombatEquipped())
{
GadgetManager->TryToUnequipCombat();
return;
}
if (GadgetManager->IsReconEquipped() && !GadgetManager->TryToUnequipRecon())
{
// Do nothing if recon is equipped and can't be unequipped at the moment
return;
}
GadgetManager->EquipCombat();
}
//When 1 is pressed it calls EquipPrimary //When 1 is pressed it calls EquipPrimary
void AEndlessVendettaCharacter::EquipPrimary() void AEndlessVendettaCharacter::EquipPrimary()
{ {

View File

@ -7,6 +7,7 @@
#include "GameFramework/Character.h" #include "GameFramework/Character.h"
#include "InputActionValue.h" #include "InputActionValue.h"
#include "Components/ArrowComponent.h" #include "Components/ArrowComponent.h"
#include "GadgetSystem/GadgetManager.h"
#include "EndlessVendettaCharacter.generated.h" #include "EndlessVendettaCharacter.generated.h"
class UWeaponInventory; class UWeaponInventory;
@ -42,6 +43,12 @@ class AEndlessVendettaCharacter : public ACharacter
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Input, meta=(AllowPrivateAccess = "true")) UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Input, meta=(AllowPrivateAccess = "true"))
class UInputAction* MoveAction; class UInputAction* MoveAction;
// Gadget Actions
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Input, meta=(AllowPrivateAccess = "true"))
UInputAction* ReconAction;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Input, meta=(AllowPrivateAccess = "true"))
UInputAction* CombatAction;
/** Weapon Equip Action */ /** Weapon Equip Action */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Input, meta=(AllowPrivateAccess = "true")) UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Input, meta=(AllowPrivateAccess = "true"))
class UInputAction* EquipPrimaryWeapon; class UInputAction* EquipPrimaryWeapon;
@ -61,6 +68,10 @@ public:
protected: protected:
virtual void BeginPlay(); virtual void BeginPlay();
UPROPERTY(EditDefaultsOnly, Category = "Gadget")
TSubclassOf<AGadgetManager> GadgetManagerClass;
AGadgetManager* GadgetManager;
public: public:
/** Look Input Action */ /** Look Input Action */
@ -99,6 +110,10 @@ protected:
/** Called for looking input */ /** Called for looking input */
void Look(const FInputActionValue& Value); void Look(const FInputActionValue& Value);
void ToggleRecon();
void ToggleCombat();
void EquipPrimary(); void EquipPrimary();

View File

@ -0,0 +1,5 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "CombatGadget.h"

View File

@ -0,0 +1,17 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GadgetBase.h"
#include "CombatGadget.generated.h"
/**
*
*/
UCLASS()
class ENDLESSVENDETTA_API ACombatGadget : public AGadgetBase
{
GENERATED_BODY()
};

View File

@ -0,0 +1,92 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "GadgetBase.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
// Sets default values
AGadgetBase::AGadgetBase()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
// Called when the game starts or when spawned
void AGadgetBase::BeginPlay()
{
Super::BeginPlay();
PlayerController = GetWorld()->GetFirstPlayerController();
}
// Called every frame
void AGadgetBase::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void AGadgetBase::Equip()
{
SetActorRelativeLocation(EquippedOffset);
Equipped = true;
UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer());
Subsystem->AddMappingContext(GadgetMappingContext, 2);
UEnhancedInputComponent* EnhancedInputComponent = Cast<UEnhancedInputComponent>(PlayerController->InputComponent);
EnhancedInputComponent->BindAction(ActivateAction, ETriggerEvent::Started, this, &AGadgetBase::Activate);
}
bool AGadgetBase::Unequip()
{
if (GadgetInUse) return false;
SetActorRelativeLocation(UnequippedOffset);
Equipped = false;
UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer());
Subsystem->RemoveMappingContext(GadgetMappingContext);
UEnhancedInputComponent* EnhancedInputComponent = Cast<UEnhancedInputComponent>(PlayerController->InputComponent);
EnhancedInputComponent->ClearActionBindings();
return true;
}
void AGadgetBase::Activate()
{
StartInUseTimer();
}
void AGadgetBase::FinishedUsing()
{
UE_LOG(LogTemp, Warning, TEXT("Gadget is no longer being used"));
GadgetInUse = false;
InUseHandle.Invalidate();
StartGadgetCooldown();
}
// -------------- Timers --------------
void AGadgetBase::StartGadgetCooldown()
{
GadgetOnCooldown = true;
GetWorld()->GetTimerManager().SetTimer(CooldownHandle, this, &AGadgetBase::ReadyGadget, CooldownTime, false);
}
void AGadgetBase::StartInUseTimer()
{
UE_LOG(LogTemp, Warning, TEXT("Gadget In Use Timer Started"));
GadgetInUse = true;
GetWorld()->GetTimerManager().SetTimer(InUseHandle, this, &AGadgetBase::FinishedUsing, GadgetMaxUptime, false);
}

View File

@ -0,0 +1,83 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "EnhancedInputSubsystemInterface.h"
#include "GameFramework/Actor.h"
#include "GadgetBase.generated.h"
UCLASS()
class ENDLESSVENDETTA_API AGadgetBase : public AActor
{
GENERATED_BODY()
APlayerController* PlayerController;
FTimerHandle CooldownHandle;
void StartGadgetCooldown();
bool GadgetOnCooldown = false;
FTimerHandle InUseHandle;
void StartInUseTimer();
bool GadgetInUse = false;
void ReadyGadget()
{
UE_LOG(LogTemp, Warning, TEXT("Gadget is now ready to be used again"));
GadgetOnCooldown = false;
}
protected:
UPROPERTY(EditDefaultsOnly, Category = "Gadget")
FVector EquippedOffset = FVector(0, 0, 0);
UPROPERTY(EditDefaultsOnly, CAtegory = "Gadget")
FVector UnequippedOffset = FVector(0, 0, -1000);
UPROPERTY(EditDefaultsOnly, cATEGORY = "Gadget")
float GadgetMaxUptime;
UPROPERTY(EditDefaultsOnly, Category = "Gadget")
float CooldownTime;
UPROPERTY(EditDefaultsOnly, Category = "Gadget")
UInputMappingContext* GadgetMappingContext;
UPROPERTY(EditDefaultsOnly, Category = "Gadget")
UInputAction* ActivateAction;
// Used by child classes to run custom gadget behaviour
virtual void Activate();
// Starts Cooldown and automatically unequips gadget, used by child classes to implement custom behaviour
virtual void FinishedUsing();
bool GadgetCantBeUsed()
{
return GadgetOnCooldown|| GadgetInUse;
}
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
bool Equipped = false;
void Equip();
// Return true if unequip succeeds
bool Unequip();
FVector GetUnequippedOffset()
{
return UnequippedOffset;
}
// Sets default values for this actor's properties
AGadgetBase();
// Called every frame
virtual void Tick(float DeltaTime) override;
};

View File

@ -0,0 +1,34 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "ExampleCombatClass.h"
void AExampleCombatClass::BeginPlay()
{
Super::BeginPlay();
SetActorTickEnabled(false);
}
void AExampleCombatClass::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
UE_LOG(LogTemp, Warning, TEXT("Example Combat is being used..."));
}
void AExampleCombatClass::Activate()
{
if (GadgetCantBeUsed()) return;
Super::Activate();
SetActorTickEnabled(true);
}
void AExampleCombatClass::FinishedUsing()
{
SetActorTickEnabled(false);
Super::FinishedUsing();
}

View File

@ -0,0 +1,24 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "EndlessVendetta/GadgetSystem/CombatGadget.h"
#include "ExampleCombatClass.generated.h"
/**
*
*/
UCLASS()
class ENDLESSVENDETTA_API AExampleCombatClass : public ACombatGadget
{
GENERATED_BODY()
virtual void BeginPlay() override;
virtual void Tick(float DeltaSeconds) override;
virtual void Activate() override;
virtual void FinishedUsing() override;
};

View File

@ -0,0 +1,35 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "ExampleReconClass.h"
void AExampleReconClass::BeginPlay()
{
Super::BeginPlay();
SetActorTickEnabled(false);
}
void AExampleReconClass::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
UE_LOG(LogTemp, Warning, TEXT("Example Recon is being used..."));
}
void AExampleReconClass::Activate()
{
if (GadgetCantBeUsed()) return;
Super::Activate();
SetActorTickEnabled(true);
}
void AExampleReconClass::FinishedUsing()
{
SetActorTickEnabled(false);
Super::FinishedUsing();
}

View File

@ -0,0 +1,25 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "EndlessVendetta/GadgetSystem/ReconGadget.h"
#include "ExampleReconClass.generated.h"
/**
*
*/
UCLASS()
class ENDLESSVENDETTA_API AExampleReconClass : public AReconGadget
{
GENERATED_BODY()
virtual void BeginPlay() override;
virtual void Tick(float DeltaSeconds) override;
virtual void Activate() override;
virtual void FinishedUsing() override;
};

View File

@ -0,0 +1,45 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "GadgetManager.h"
// Sets default values
AGadgetManager::AGadgetManager()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
// Called when the game starts or when spawned
void AGadgetManager::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void AGadgetManager::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void AGadgetManager::SpawnGadgets(USceneComponent* PlayersRootComponent)
{
if (!IsValid(ReconClass) || !IsValid(CombatClass)) UE_LOG(LogTemp, Fatal, TEXT("Recon or Combat class hasn't been set"));
FActorSpawnParameters SpawnParams;
SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
const FAttachmentTransformRules AttachmentRules(EAttachmentRule::SnapToTarget, true);
AActor* SpawnedActor = GetWorld()->SpawnActor<AActor>(ReconClass, GetActorLocation(), GetActorRotation(), SpawnParams);
ReconGadget = Cast<AReconGadget>(SpawnedActor);
SpawnedActor->AttachToComponent(PlayersRootComponent, AttachmentRules);
SpawnedActor->SetActorRelativeLocation(ReconGadget->GetUnequippedOffset());
SpawnedActor = GetWorld()->SpawnActor<AActor>(CombatClass, GetActorLocation(), GetActorRotation(), SpawnParams);
CombatGadget = Cast<ACombatGadget>(SpawnedActor);
SpawnedActor->AttachToComponent(PlayersRootComponent, AttachmentRules);
SpawnedActor->SetActorRelativeLocation(CombatGadget->GetUnequippedOffset());
}

View File

@ -0,0 +1,75 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "CombatGadget.h"
#include "ReconGadget.h"
#include "GameFramework/Actor.h"
#include "GadgetManager.generated.h"
UCLASS()
class ENDLESSVENDETTA_API AGadgetManager : public AActor
{
GENERATED_BODY()
AReconGadget* ReconGadget;
ACombatGadget* CombatGadget;
protected:
UPROPERTY(EditDefaultsOnly, Category = "Gadget")
TSubclassOf<AReconGadget> ReconClass;
UPROPERTY(EditDefaultsOnly, Category = "Gadget")
TSubclassOf<ACombatGadget> CombatClass;
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
void SpawnGadgets(USceneComponent* PlayersRootComponent);
// Sets default values for this actor's properties
AGadgetManager();
// Called every frame
virtual void Tick(float DeltaTime) override;
void EquipRecon()
{
ReconGadget->Equip();
}
void EquipCombat()
{
CombatGadget->Equip();
}
bool IsReconEquipped()
{
return ReconGadget->Equipped;
}
bool IsCombatEquipped()
{
return CombatGadget->Equipped;
}
bool TryToUnequipRecon()
{
if (ReconGadget->Equipped)
{
return ReconGadget->Unequip();
}
return false;
}
bool TryToUnequipCombat()
{
if (CombatGadget->Equipped)
{
return CombatGadget->Unequip();
}
return false;
}
};

View File

@ -0,0 +1,5 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "ReconGadget.h"

View File

@ -0,0 +1,17 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GadgetBase.h"
#include "ReconGadget.generated.h"
/**
*
*/
UCLASS()
class ENDLESSVENDETTA_API AReconGadget : public AGadgetBase
{
GENERATED_BODY()
};