feat: add grenade pickup, throw, and drop mechanics
Implemented basic grenade interaction: - Player can pick up, throw, and drop grenades. To-do: - Refine throwing mechanics (e.g. direction, force). - Clean up and refactor related code.
This commit is contained in:
parent
c372d9e8d5
commit
2b6bdf9f80
BIN
Content/Blueprints/Items/BP_GranadeBase.uasset
Normal file
BIN
Content/Blueprints/Items/BP_GranadeBase.uasset
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Content/Blueprints/Player/Inputs/Inputs/AI_Throw.uasset
Normal file
BIN
Content/Blueprints/Player/Inputs/Inputs/AI_Throw.uasset
Normal file
Binary file not shown.
Binary file not shown.
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include "Characters/Components/ShootingComponent.h"
|
#include "Characters/Components/ShootingComponent.h"
|
||||||
|
|
||||||
|
#include "Items/ThrowableBase.h"
|
||||||
|
|
||||||
// Sets default values for this component's properties
|
// Sets default values for this component's properties
|
||||||
UShootingComponent::UShootingComponent()
|
UShootingComponent::UShootingComponent()
|
||||||
{
|
{
|
||||||
|
|
@ -96,7 +98,7 @@ void UShootingComponent::Reload()
|
||||||
CurrentGun->CurrentAmmo = CurrentGun->MaxAmmo;
|
CurrentGun->CurrentAmmo = CurrentGun->MaxAmmo;
|
||||||
PlayerCharacter->GetWorldTimerManager().SetTimer(ReloadTimer, this, &UShootingComponent::ReloadCompleted, CurrentGun->ReloadTime, false);
|
PlayerCharacter->GetWorldTimerManager().SetTimer(ReloadTimer, this, &UShootingComponent::ReloadCompleted, CurrentGun->ReloadTime, false);
|
||||||
|
|
||||||
UE_LOG(LogTemp, Display, TEXT("Reloaded. Ammo: %d/%d"), CurrentGun->CurrentAmmo, CurrentGun->MaxAmmo); // Docelowo tutaj wywo<77>anie UI aktualizuj<75>ce stan ammo
|
UE_LOG(LogTemp, Display, TEXT("Reloaded. Ammo: %d/%d"), CurrentGun->CurrentAmmo, CurrentGun->MaxAmmo); // Docelowo tutaj wywo<77>anie UI aktualizuj<75>ce stan ammo
|
||||||
}
|
}
|
||||||
|
|
||||||
void UShootingComponent::PickUpGun(AGunBase* gunItem)
|
void UShootingComponent::PickUpGun(AGunBase* gunItem)
|
||||||
|
|
@ -121,6 +123,38 @@ void UShootingComponent::PickUpGun(AGunBase* gunItem)
|
||||||
CurrentGun = NewGun;
|
CurrentGun = NewGun;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool UShootingComponent::PickUpThrow(AThrowableBase* ThrowItem)
|
||||||
|
{
|
||||||
|
AThrowableBase* NewThrowable = NewObject<AThrowableBase>();
|
||||||
|
|
||||||
|
if (IsValid(ThrowableItem))
|
||||||
|
{
|
||||||
|
if (ThrowableItem->GetClass() == NewThrowable->GetClass())
|
||||||
|
{
|
||||||
|
if (ThrowableItem->Quantity + ThrowItem->Quantity >= ThrowableItem->MaxQuantity)
|
||||||
|
{
|
||||||
|
ThrowableItem->Quantity = ThrowableItem->MaxQuantity;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowableItem->Quantity += ThrowItem->Quantity;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
DropThrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
NewThrowable->Damage = ThrowItem->Damage;
|
||||||
|
NewThrowable->Quantity = ThrowItem->Quantity;
|
||||||
|
NewThrowable->Radius = ThrowItem->Radius;
|
||||||
|
NewThrowable->ThrowableType = ThrowItem->ThrowableType;
|
||||||
|
NewThrowable->SceneItemClass = ThrowItem->GetClass();
|
||||||
|
|
||||||
|
ThrowableItem = NewThrowable;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void UShootingComponent::DropGun()
|
void UShootingComponent::DropGun()
|
||||||
{
|
{
|
||||||
if (!IsValid(CurrentGun)) return;
|
if (!IsValid(CurrentGun)) return;
|
||||||
|
|
@ -151,6 +185,30 @@ void UShootingComponent::DropGun()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UShootingComponent::DropThrow()
|
||||||
|
{
|
||||||
|
if (!IsValid(ThrowableItem)) return;
|
||||||
|
|
||||||
|
FVector ForwardVector = PlayerCharacter->GetActorForwardVector();
|
||||||
|
FVector DroppedPos = PlayerCharacter->GetActorLocation() + (ForwardVector * 100.f);
|
||||||
|
|
||||||
|
FTransform DroppedTransform = PlayerCharacter->GetActorTransform();
|
||||||
|
DroppedTransform.SetLocation(DroppedPos);
|
||||||
|
|
||||||
|
AThrowableBase* DropedItem = GetWorld()->SpawnActor<AThrowableBase>(ThrowableItem->SceneItemClass, DroppedTransform);
|
||||||
|
|
||||||
|
if (DropedItem)
|
||||||
|
{
|
||||||
|
ThrowableItem->Quantity--;
|
||||||
|
DropedItem->Damage = ThrowableItem->Damage;
|
||||||
|
DropedItem->Radius = ThrowableItem->Radius;
|
||||||
|
DropedItem->Quantity = ThrowableItem->Quantity;
|
||||||
|
DropedItem->ThrowableType = ThrowableItem->ThrowableType;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void UShootingComponent::ResetFireCooldown()
|
void UShootingComponent::ResetFireCooldown()
|
||||||
{
|
{
|
||||||
bCanShoot = true;
|
bCanShoot = true;
|
||||||
|
|
@ -206,6 +264,40 @@ void UShootingComponent::StopAiming()
|
||||||
TargetFOV = DefaultFOV;
|
TargetFOV = DefaultFOV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UShootingComponent::Throw() // Wymaga dopracowania
|
||||||
|
{
|
||||||
|
if (IsValid(ThrowableItem))
|
||||||
|
{
|
||||||
|
FVector ForwardVector = PlayerCharacter->GetActorForwardVector();
|
||||||
|
FVector DroppedPos = PlayerCharacter->GetActorLocation() + (ForwardVector * 100.f);
|
||||||
|
|
||||||
|
FTransform DroppedTransform = PlayerCharacter->GetActorTransform();
|
||||||
|
DroppedTransform.SetLocation(DroppedPos);
|
||||||
|
|
||||||
|
AThrowableBase* ThrowedItem = GetWorld()->SpawnActor<AThrowableBase>(ThrowableItem->SceneItemClass, DroppedTransform);
|
||||||
|
|
||||||
|
if (ThrowedItem)
|
||||||
|
{
|
||||||
|
ThrowableItem->Quantity--;
|
||||||
|
ThrowedItem->Damage = ThrowableItem->Damage;
|
||||||
|
ThrowedItem->Radius = ThrowableItem->Radius;
|
||||||
|
ThrowedItem->Quantity = 1;
|
||||||
|
ThrowedItem->ThrowableType = ThrowableItem->ThrowableType;
|
||||||
|
|
||||||
|
FVector ThrowVector = (ThrowedItem->GetActorLocation() - PlayerCharacter->GetActorLocation()).GetSafeNormal();
|
||||||
|
ThrowedItem->Mesh->SetPhysicsLinearVelocity(ThrowVector * 800.f);
|
||||||
|
|
||||||
|
if (ThrowableItem->Quantity <= 0)
|
||||||
|
{
|
||||||
|
ThrowableItem->Destroy();
|
||||||
|
ThrowableItem = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Called every frame
|
// Called every frame
|
||||||
void UShootingComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
|
void UShootingComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
45
Source/Exo/Private/Items/ThrowableBase.cpp
Normal file
45
Source/Exo/Private/Items/ThrowableBase.cpp
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
// Fill out your copyright notice in the Description page of Project Settings.
|
||||||
|
|
||||||
|
|
||||||
|
#include "Items/ThrowableBase.h"
|
||||||
|
|
||||||
|
#include "Characters/Components/ShootingComponent.h"
|
||||||
|
|
||||||
|
AThrowableBase::AThrowableBase()
|
||||||
|
{
|
||||||
|
PrimaryActorTick.bCanEverTick = true;
|
||||||
|
|
||||||
|
RootSceneComponent = CreateDefaultSubobject<USceneComponent>(TEXT("Root"));
|
||||||
|
SetRootComponent(RootSceneComponent);
|
||||||
|
Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
|
||||||
|
Mesh->SetupAttachment(GetRootComponent());
|
||||||
|
Mesh->SetSimulatePhysics(true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void AThrowableBase::Interact_Implementation(AExoPlayerCharacter* PlayerCharacter)
|
||||||
|
{
|
||||||
|
if (PlayerCharacter->ShootingComponent->PickUpThrow(this))
|
||||||
|
{
|
||||||
|
Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void AThrowableBase::EffectActivate()
|
||||||
|
{
|
||||||
|
if (ThrowableType == ThrowableType::Hit)
|
||||||
|
{
|
||||||
|
UE_LOG(LogTemp, Display, TEXT("Throwable Hit"));
|
||||||
|
}
|
||||||
|
if (ThrowableType == ThrowableType::Explode)
|
||||||
|
{
|
||||||
|
UE_LOG(LogTemp, Display, TEXT("Throwable Explode"));
|
||||||
|
}
|
||||||
|
if (ThrowableType == ThrowableType::Area)
|
||||||
|
{
|
||||||
|
UE_LOG(LogTemp, Display, TEXT("Throwable Area"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -57,6 +57,7 @@ void AExoPlayerController::SetupInputComponent()
|
||||||
EnhancedInputComponent->BindAction(SprintAction, ETriggerEvent::Started, this, &AExoPlayerController::PlayerStartSprint);
|
EnhancedInputComponent->BindAction(SprintAction, ETriggerEvent::Started, this, &AExoPlayerController::PlayerStartSprint);
|
||||||
EnhancedInputComponent->BindAction(SprintAction, ETriggerEvent::Completed, this, &AExoPlayerController::PlayerStopSprint);
|
EnhancedInputComponent->BindAction(SprintAction, ETriggerEvent::Completed, this, &AExoPlayerController::PlayerStopSprint);
|
||||||
EnhancedInputComponent->BindAction(ShootAction, ETriggerEvent::Started, this, &AExoPlayerController::PlayerShoot);
|
EnhancedInputComponent->BindAction(ShootAction, ETriggerEvent::Started, this, &AExoPlayerController::PlayerShoot);
|
||||||
|
EnhancedInputComponent->BindAction(ThrowAction, ETriggerEvent::Completed, this, &AExoPlayerController::PlayerThrow);
|
||||||
EnhancedInputComponent->BindAction(AimAction, ETriggerEvent::Started, this, &AExoPlayerController::PlayerStartAim);
|
EnhancedInputComponent->BindAction(AimAction, ETriggerEvent::Started, this, &AExoPlayerController::PlayerStartAim);
|
||||||
EnhancedInputComponent->BindAction(AimAction, ETriggerEvent::Completed, this, &AExoPlayerController::PlayerStopAim);
|
EnhancedInputComponent->BindAction(AimAction, ETriggerEvent::Completed, this, &AExoPlayerController::PlayerStopAim);
|
||||||
EnhancedInputComponent->BindAction(MeleAction, ETriggerEvent::Started, this, &AExoPlayerController::PlayerMeleAttack);
|
EnhancedInputComponent->BindAction(MeleAction, ETriggerEvent::Started, this, &AExoPlayerController::PlayerMeleAttack);
|
||||||
|
|
@ -166,6 +167,11 @@ void AExoPlayerController::PlayerShoot()
|
||||||
ShootingComponent->Shoot();
|
ShootingComponent->Shoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AExoPlayerController::PlayerThrow()
|
||||||
|
{
|
||||||
|
ShootingComponent->Throw();
|
||||||
|
}
|
||||||
|
|
||||||
void AExoPlayerController::PlayerStartAim()
|
void AExoPlayerController::PlayerStartAim()
|
||||||
{
|
{
|
||||||
ShootingComponent->StartAiming();
|
ShootingComponent->StartAiming();
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@
|
||||||
#include "ShootingComponent.generated.h"
|
#include "ShootingComponent.generated.h"
|
||||||
|
|
||||||
|
|
||||||
|
class AThrowableBase;
|
||||||
|
|
||||||
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
|
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
|
||||||
class EXO_API UShootingComponent : public UActorComponent
|
class EXO_API UShootingComponent : public UActorComponent
|
||||||
{
|
{
|
||||||
|
|
@ -49,9 +51,15 @@ public:
|
||||||
UFUNCTION(BlueprintCallable, Category = "Shooting")
|
UFUNCTION(BlueprintCallable, Category = "Shooting")
|
||||||
void PickUpGun(AGunBase* gunItem);
|
void PickUpGun(AGunBase* gunItem);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Shooting")
|
||||||
|
bool PickUpThrow(AThrowableBase* ThrowItem);
|
||||||
|
|
||||||
UFUNCTION(Category = "Shooting")
|
UFUNCTION(Category = "Shooting")
|
||||||
void DropGun();
|
void DropGun();
|
||||||
|
|
||||||
|
UFUNCTION(Category = "Shooting")
|
||||||
|
void DropThrow();
|
||||||
|
|
||||||
UFUNCTION(Category = "Shooting")
|
UFUNCTION(Category = "Shooting")
|
||||||
void SwitchGun();
|
void SwitchGun();
|
||||||
|
|
||||||
|
|
@ -64,6 +72,9 @@ public:
|
||||||
UFUNCTION(Category = "Shooting")
|
UFUNCTION(Category = "Shooting")
|
||||||
void StopAiming();
|
void StopAiming();
|
||||||
|
|
||||||
|
UFUNCTION(Category = "Shooting")
|
||||||
|
void Throw();
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Aiming")
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Aiming")
|
||||||
float AimingAnimationSpeed = 30.0f;
|
float AimingAnimationSpeed = 30.0f;
|
||||||
|
|
||||||
|
|
@ -76,6 +87,9 @@ public:
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mele Attack")
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mele Attack")
|
||||||
float MeleRange = 75.f;
|
float MeleRange = 75.f;
|
||||||
|
|
||||||
|
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Shooting")
|
||||||
|
AThrowableBase* ThrowableItem = nullptr;
|
||||||
|
|
||||||
AGunBase* CurrentGun = nullptr;
|
AGunBase* CurrentGun = nullptr;
|
||||||
AGunBase* SecondaryGun = nullptr;
|
AGunBase* SecondaryGun = nullptr;
|
||||||
|
|
||||||
|
|
|
||||||
59
Source/Exo/Public/Items/ThrowableBase.h
Normal file
59
Source/Exo/Public/Items/ThrowableBase.h
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
// Fill out your copyright notice in the Description page of Project Settings.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "GameFramework/Actor.h"
|
||||||
|
#include "Interfaces/Interactable.h"
|
||||||
|
#include "ThrowableBase.generated.h"
|
||||||
|
|
||||||
|
UENUM()
|
||||||
|
enum class ThrowableType : uint8
|
||||||
|
{
|
||||||
|
Hit UMETA(DisplayName = "Hit"),
|
||||||
|
Explode UMETA(DisplayName = "Explode"),
|
||||||
|
Area UMETA(DisplayName = "Area")
|
||||||
|
};
|
||||||
|
|
||||||
|
UCLASS()
|
||||||
|
class EXO_API AThrowableBase : public AActor, public IInteractable
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
AThrowableBase();
|
||||||
|
|
||||||
|
virtual void Interact_Implementation(AExoPlayerCharacter* PlayerCharacter) override;
|
||||||
|
|
||||||
|
TSubclassOf<AActor> SceneItemClass;
|
||||||
|
|
||||||
|
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Throw")
|
||||||
|
TObjectPtr<USceneComponent> RootSceneComponent;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Throw")
|
||||||
|
TObjectPtr<UStaticMeshComponent> Mesh;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Throw Details")
|
||||||
|
int Quantity = 1;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Throw Details")
|
||||||
|
int MaxQuantity = 6;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Throw Details")
|
||||||
|
int NumberOfBounces = 0;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Effect")
|
||||||
|
ThrowableType ThrowableType = ThrowableType::Hit;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Effect")
|
||||||
|
float Damage = 100.f;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Effect")
|
||||||
|
float Radius = 0.f;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Effect")
|
||||||
|
virtual void EffectActivate();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
@ -62,6 +62,9 @@ protected:
|
||||||
UFUNCTION(BlueprintCallable, Category = "Input")
|
UFUNCTION(BlueprintCallable, Category = "Input")
|
||||||
void PlayerShoot(); // LPM
|
void PlayerShoot(); // LPM
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Input")
|
||||||
|
void PlayerThrow(); // G
|
||||||
|
|
||||||
UFUNCTION(BlueprintCallable, Category = "Input")
|
UFUNCTION(BlueprintCallable, Category = "Input")
|
||||||
void PlayerStartAim(); // PPM (pressed)
|
void PlayerStartAim(); // PPM (pressed)
|
||||||
|
|
||||||
|
|
@ -119,7 +122,10 @@ protected:
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, Category = "Input")
|
UPROPERTY(EditAnywhere, Category = "Input")
|
||||||
TObjectPtr<UInputAction> ShootAction;
|
TObjectPtr<UInputAction> ShootAction;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, Category = "Input")
|
||||||
|
TObjectPtr<UInputAction> ThrowAction;
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, Category = "Input")
|
UPROPERTY(EditAnywhere, Category = "Input")
|
||||||
TObjectPtr<UInputAction> ReloadAction;
|
TObjectPtr<UInputAction> ReloadAction;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user