Make projectiles pooled and use DataAssets

This commit is contained in:
baz 2025-01-13 20:57:08 +00:00
parent 9436d16875
commit 741a41ddfa
36 changed files with 480 additions and 133 deletions

BIN
Content/Gamemode/BP_DefaultGamemode.uasset (Stored with Git LFS)

Binary file not shown.

BIN
Content/Levels/Level.umap (Stored with Git LFS)

Binary file not shown.

BIN
Content/Pickups/C_Pickup.uasset (Stored with Git LFS)

Binary file not shown.

BIN
Content/Pickups/DA_ExamplePickup.uasset (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Content/Player/BP_PlayerCharacter.uasset (Stored with Git LFS)

Binary file not shown.

BIN
Content/Weapons/BP_ExampleWeapon.uasset (Stored with Git LFS)

Binary file not shown.

BIN
Content/Weapons/DA_ExampleWeapon.uasset (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Content/Weapons/TestProjectileDataAsset.uasset (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,7 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "Pools.h"
// Add default functionality here for any IPools functions that are not pure virtual.

View File

@ -0,0 +1,31 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "Pools.generated.h"
class AObjectPoolManager;
// This class does not need to be modified.
UINTERFACE()
class UPools : public UInterface
{
GENERATED_BODY()
};
/**
*
*/
class VAMPIRES_API IPools
{
GENERATED_BODY()
// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
UFUNCTION(BlueprintNativeEvent)
AObjectPoolManager* GetEnemyObjectPoolManager();
UFUNCTION(BlueprintNativeEvent)
AObjectPoolManager* GetProjectileObjectPoolManager();
};

View File

@ -0,0 +1,7 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "Projectilable.h"
// Add default functionality here for any IProjectilable functions that are not pure virtual.

View File

@ -0,0 +1,34 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "Projectilable.generated.h"
class UProjectileDataAsset;
// This class does not need to be modified.
UINTERFACE()
class UProjectilable : public UInterface
{
GENERATED_BODY()
};
/**
*
*/
class VAMPIRES_API IProjectilable
{
GENERATED_BODY()
// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
UFUNCTION(BlueprintNativeEvent)
void LoadDataFromDataAsset(UProjectileDataAsset* projectileDataAsset);
UFUNCTION(BlueprintNativeEvent)
void ResetData();
UFUNCTION(BlueprintNativeEvent)
void SetTargetDirection(FVector direction);
};

View File

@ -7,6 +7,7 @@
#include "GameFramework/Actor.h"
#include "Pickup.generated.h"
class UPickupDataAsset;
class UTimelineComponent;
class USphereComponent;
class UPaperSpriteComponent;
@ -17,19 +18,21 @@ class VAMPIRES_API APickup : public AActor
GENERATED_BODY()
public:
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
TObjectPtr<UPickupDataAsset> PickupDataAsset;
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
double PickupMovementRange = 500;
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
double PickupMovementSpeed = 1000;
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
USphereComponent* InnerSphereComponent = nullptr;
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
USphereComponent* OuterSphereComponent = nullptr;
UPROPERTY(EditAnywhere)
UPaperSpriteComponent* SpriteComponent = nullptr;
@ -47,8 +50,8 @@ private:
FOnTimelineEventStatic onTimelineFinishedCallback;
FVector PickupLocation;
public:
public:
// Sets default values for this actor's properties
APickup();
@ -58,13 +61,13 @@ protected:
UFUNCTION()
virtual void OnInnerBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep,
const FHitResult& SweepResult);
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep,
const FHitResult& SweepResult);
UFUNCTION()
virtual void OnOuterBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep,
const FHitResult& SweepResult);
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep,
const FHitResult& SweepResult);
UFUNCTION()
void TimelineCallback(float val);

View File

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

View File

@ -0,0 +1,37 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataAsset.h"
#include "PickupDataAsset.generated.h"
class UTimelineComponent;
class UPaperSprite;
/**
*
*/
UCLASS(BlueprintType)
class VAMPIRES_API UPickupDataAsset : public UDataAsset
{
GENERATED_BODY()
public:
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Pickup Properties")
int PickupValue = 1;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Pickup Properties")
double PickupMovementRange = 500;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Pickup Properties")
double PickupMovementSpeed = 1000;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Pickup Properties")
TObjectPtr<UPaperSprite> WeaponSprite = nullptr;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Pickup Properties")
TObjectPtr<USoundBase> PickupSoundBase = nullptr;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Pickup Properties")
TObjectPtr<UCurveFloat> CurveFloat = nullptr;
};

View File

@ -4,8 +4,13 @@
#include "Projectile.h"
#include "EnemyCharacter.h"
#include "ObjectPoolManager.h"
#include "ProjectileDataAsset.h"
#include "Components/SphereComponent.h"
#include "GameFramework/GameModeBase.h"
#include "GameFramework/ProjectileMovementComponent.h"
#include "Interfaces/Pools.h"
#include "Kismet/GameplayStatics.h"
#include "Weapons/ProjectileWeapon.h"
// Sets default values
@ -19,22 +24,55 @@ AProjectile::AProjectile()
ProjectileMovement->ProjectileGravityScale = 0.0f;
ProjectileMovement->Friction = 0.0f;
ProjectileMovement->bIsSliding = true;
ProjectileMovement->InitialSpeed = 0;
ProjectileMovement->MaxSpeed = 0;
StaticMeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Static Mesh Component"));
StaticMeshComponent->AttachToComponent(SphereComponent, FAttachmentTransformRules::KeepRelativeTransform);
StaticMeshComponent->SetEnableGravity(false);
StaticMeshComponent->SetGenerateOverlapEvents(false);
StaticMeshComponent->SetCollisionProfileName(TEXT("NoCollision"));
}
// Called when the game starts or when spawned
void AProjectile::BeginPlay()
{
Super::BeginPlay();
SphereComponent->OnComponentBeginOverlap.AddDynamic(this, &AProjectile::OnProjectileBeginOverlap);
}
void AProjectile::SetActorHiddenInGame(bool bNewHidden)
{
Super::SetActorHiddenInGame(bNewHidden);
if (bNewHidden)
{
ResetData_Implementation();
}
}
void AProjectile::SetTargetDirection_Implementation(FVector direction)
{
SetActorLocation(UGameplayStatics::GetPlayerController(GetWorld(), 0)->GetCharacter()->GetActorLocation());
SetActorRotation(FRotator(0, 0, 0));
TargetDirection = direction;
ProjectileMovement->SetVelocityInLocalSpace(TargetDirection * ProjectileSpeed);
}
void AProjectile::LoadDataFromDataAsset_Implementation(UProjectileDataAsset* projectileDataAsset)
{
ProjectileSpeed = projectileDataAsset->ProjectileSpeed;
StaticMeshComponent->SetStaticMesh(projectileDataAsset->StaticMesh);
ProjectileSpeed = projectileDataAsset->ProjectileSpeed;
ProjectileMovement->InitialSpeed = ProjectileSpeed;
ProjectileMovement->MaxSpeed = ProjectileSpeed;
}
void AProjectile::SetTargetDirection(FVector direction)
void AProjectile::ResetData_Implementation()
{
TargetDirection = direction;
ProjectileMovement->SetVelocityInLocalSpace(TargetDirection * ProjectileSpeed);
ProjectileSpeed = NULL;
StaticMeshComponent->SetStaticMesh(nullptr);
}
void AProjectile::OnProjectileBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
@ -52,11 +90,19 @@ void AProjectile::OnProjectileBeginOverlap(UPrimitiveComponent* OverlappedCompon
{
ownerController = character->GetController();
}
AProjectileWeapon* ownerWeapon = Cast<AProjectileWeapon>(GetOwner());
EnemyHealthComponent->TakeDamage(Enemy, ownerWeapon->Damage, nullptr, ownerController, this);
OverlappedComponent->GetAttachmentRootActor()->Destroy();
AGameModeBase* gamemode = UGameplayStatics::GetGameMode(GetWorld());
if (UKismetSystemLibrary::DoesImplementInterface(gamemode, UPools::StaticClass()))
{
if (AObjectPoolManager* objectPoolManager = IPools::Execute_GetProjectileObjectPoolManager(gamemode))
{
objectPoolManager->ReturnObject(this);
}
}
}
}
}

View File

@ -4,13 +4,15 @@
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Interfaces/Projectilable.h"
#include "Projectile.generated.h"
class UProjectileMovementComponent;
class USphereComponent;
class UProjectileDataAsset;
UCLASS()
class VAMPIRES_API AProjectile : public AActor
class VAMPIRES_API AProjectile : public AActor, public IProjectilable
{
GENERATED_BODY()
@ -20,13 +22,15 @@ public:
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
UProjectileMovementComponent* ProjectileMovement = nullptr;
FVector TargetDirection = FVector::ZeroVector;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float ProjectileSpeed = 500.0f;
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite)
UStaticMeshComponent* StaticMeshComponent = nullptr;
// Sets default values for this actor's properties
AProjectile();
@ -34,12 +38,18 @@ protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
public:
virtual void SetActorHiddenInGame(bool bNewHidden) override;
void SetTargetDirection(FVector direction);
virtual void SetTargetDirection_Implementation(FVector direction) override;
virtual void LoadDataFromDataAsset_Implementation(UProjectileDataAsset* projectileDataAsset) override;
virtual void ResetData_Implementation() override;
private:
UFUNCTION()
void OnProjectileBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep,
const FHitResult& SweepResult);
};

View File

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

View File

@ -0,0 +1,23 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataAsset.h"
#include "ProjectileDataAsset.generated.h"
/**
*
*/
UCLASS()
class VAMPIRES_API UProjectileDataAsset : public UDataAsset
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere)
float ProjectileSpeed = 500.0f;
UPROPERTY(EditAnywhere)
TObjectPtr<UStaticMesh> StaticMesh;
};

View File

@ -7,6 +7,7 @@
#include "HealthComponent.h"
#include "ObjectPoolManager.h"
#include "PlayerCharacter.h"
#include "Projectile.h"
#include "VampirePlayerController.h"
#include "Components/CapsuleComponent.h"
#include "Kismet/GameplayStatics.h"
@ -77,7 +78,7 @@ void AVampireGameMode::SpawnEnemy()
FActorSpawnParameters SpawnParameters;
SpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
if (AActor* object = GetEnemyObjectPoolManager()->GetObject())
if (AActor* object = GetEnemyObjectPoolManager_Implementation()->GetObject())
{
AEnemyCharacter* Actor = Cast<AEnemyCharacter>(object);
Actor->SetActorTransform(Transform);
@ -91,16 +92,15 @@ void AVampireGameMode::SpawnEnemy()
{
Actor->SpawnDefaultController();
}
if (!Actor->GetHealthComponent()->OnDeath.IsAlreadyBound(this, &AVampireGameMode::HandleOnEnemyDeath))
{
Actor->GetHealthComponent()->OnDeath.AddDynamic(this, &AVampireGameMode::HandleOnEnemyDeath);
}
}
}
AObjectPoolManager* AVampireGameMode::GetEnemyObjectPoolManager()
AObjectPoolManager* AVampireGameMode::GetEnemyObjectPoolManager_Implementation()
{
if (EnemyObjectPoolManager == nullptr)
{
@ -112,6 +112,18 @@ AObjectPoolManager* AVampireGameMode::GetEnemyObjectPoolManager()
return EnemyObjectPoolManager;
}
AObjectPoolManager* AVampireGameMode::GetProjectileObjectPoolManager_Implementation()
{
if (ProjectileObjectPoolManager == nullptr)
{
ProjectileObjectPoolManager = GetWorld()->SpawnActor<AObjectPoolManager>();
TSubclassOf<AActor> projectileTemplate = ProjectileTemplate;
ProjectileObjectPoolManager->InitializeObjectPool(projectileTemplate);
}
return ProjectileObjectPoolManager;
}
void AVampireGameMode::IncrementEnemyDeathCount()
{
EnemyDeathCount++;

View File

@ -5,8 +5,10 @@
#include "CoreMinimal.h"
#include "HealthComponent.h"
#include "GameFramework/GameMode.h"
#include "Interfaces/Pools.h"
#include "VampireGameMode.generated.h"
class AProjectile;
class AObjectPoolManager;
class AVampirePlayerController;
class APlayerCharacter;
@ -15,7 +17,7 @@ class AEnemyCharacter;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnEnemyDeathCountIncrementDelegate, int, level);
UCLASS()
class VAMPIRES_API AVampireGameMode : public AGameMode
class VAMPIRES_API AVampireGameMode : public AGameMode, public IPools
{
GENERATED_BODY()
@ -23,6 +25,9 @@ public:
UPROPERTY(EditDefaultsOnly)
TSubclassOf<AEnemyCharacter> EnemyTemplate;
UPROPERTY(EditDefaultsOnly)
TSubclassOf<AProjectile> ProjectileTemplate;
FOnEnemyDeathCountIncrementDelegate OnEnemyDeathCountIncrementDelegate;
private:
@ -36,6 +41,8 @@ private:
TObjectPtr<AObjectPoolManager> EnemyObjectPoolManager = nullptr;
TObjectPtr<AObjectPoolManager> ProjectileObjectPoolManager = nullptr;
protected:
virtual void BeginPlay() override;
@ -45,11 +52,13 @@ public:
UFUNCTION()
void HandleOnEnemyDeath(FDamageInfo damageInfo);
UFUNCTION()
void IncrementEnemyDeathCount();
AObjectPoolManager* GetEnemyObjectPoolManager();
virtual AObjectPoolManager* GetEnemyObjectPoolManager_Implementation() override;
virtual AObjectPoolManager* GetProjectileObjectPoolManager_Implementation() override;
protected:
UFUNCTION()

View File

@ -6,6 +6,8 @@
#include "GameFramework/Actor.h"
#include "Weapon.generated.h"
class UWeaponDataAsset;
UCLASS()
class VAMPIRES_API AWeapon : public AActor
{
@ -18,6 +20,9 @@ public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Weapon Properties")
float Damage;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Weapon Properties")
TObjectPtr<UWeaponDataAsset> WeaponDataAsset;
private:
FTimerHandle WeaponTimerHandle;
@ -30,7 +35,6 @@ protected:
virtual void BeginPlay() override;
public:
UFUNCTION(BlueprintNativeEvent)
void FireWeaponAction();
virtual void FireWeaponAction_Implementation();

View File

@ -3,7 +3,11 @@
#include "FireWandWeapon.h"
#include "GameFramework/GameModeBase.h"
#include "Kismet/GameplayStatics.h"
#include "Kismet/KismetMathLibrary.h"
#include "vampires/ObjectPoolManager.h"
#include "vampires/Interfaces/Pools.h"
#include "vampires/Projectile.h"
AFireWandWeapon::AFireWandWeapon()
@ -18,23 +22,31 @@ void AFireWandWeapon::BeginPlay()
void AFireWandWeapon::FireWeaponAction_Implementation()
{
Super::FireWeaponAction_Implementation();
if (IsValid(ProjectileTemplate) && OverlappedEnemies.Num() > 0)
if (ProjectileTemplate && OverlappedEnemies.Num() > 0)
{
FActorSpawnParameters actorSpawnParameters;
actorSpawnParameters.Owner = this;
actorSpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
actorSpawnParameters.TransformScaleMethod = ESpawnActorScaleMethod::MultiplyWithRoot;
AProjectile* projectile = GetWorld()->SpawnActor<AProjectile>(ProjectileTemplate, GetOwner()->GetTransform(),
actorSpawnParameters);
AGameModeBase* gamemode = UGameplayStatics::GetGameMode(GetWorld());
AActor* target = OverlappedEnemies[FMath::RandRange(0, OverlappedEnemies.Num() - 1)];
FVector direction = UKismetMathLibrary::GetDirectionUnitVector(
GetActorLocation(), target->GetActorLocation());
direction.Z = 0.0;
direction.Normalize();
if (UKismetSystemLibrary::DoesImplementInterface(gamemode, UPools::StaticClass()))
{
if (AObjectPoolManager* objectPoolManager = IPools::Execute_GetProjectileObjectPoolManager(gamemode))
{
AActor* projectile = objectPoolManager->GetObject();
projectile->SetTargetDirection(direction);
if (UKismetSystemLibrary::DoesImplementInterface(projectile, UProjectilable::StaticClass()))
{
IProjectilable::Execute_LoadDataFromDataAsset(projectile, ProjectileTemplate);
projectile->SetOwner(this);
AActor* target = OverlappedEnemies[FMath::RandRange(0, OverlappedEnemies.Num() - 1)];
FVector direction = UKismetMathLibrary::GetDirectionUnitVector(
GetActorLocation(), target->GetActorLocation());
direction.Z = 0.0;
direction.Normalize();
IProjectilable::Execute_SetTargetDirection(projectile, direction);
}
}
}
}
}

View File

@ -3,11 +3,14 @@
#include "GunWeapon.h"
#include "GameFramework/GameModeBase.h"
#include "Kismet/GameplayStatics.h"
#include "Kismet/KismetMathLibrary.h"
#include "vampires/ObjectPoolManager.h"
#include "vampires/PlayerCharacter.h"
#include "vampires/Projectile.h"
#include "vampires/VampirePlayerController.h"
#include "vampires/Interfaces/Pools.h"
AGunWeapon::AGunWeapon()
{
@ -22,50 +25,58 @@ void AGunWeapon::FireWeaponAction_Implementation()
{
Super::FireWeaponAction_Implementation();
if (IsValid(ProjectileTemplate))
if (ProjectileTemplate && OverlappedEnemies.Num() > 0)
{
FVector2d ViewportSize;
GEngine->GameViewport->GetViewportSize(ViewportSize);
AGameModeBase* gamemode = UGameplayStatics::GetGameMode(GetWorld());
APlayerCharacter* PlayerCharacter = Cast<APlayerCharacter>(UGameplayStatics::GetPlayerCharacter(GetWorld(), 0));
AVampirePlayerController* PlayerController = Cast<AVampirePlayerController>(
UGameplayStatics::GetPlayerController(PlayerCharacter, 0));
FVector TopLeft, TopLeftDir;
FVector TopRight, TopRightDir;
FVector BottomLeft, BottomLeftDir;
FVector BottomRight, BottomRightDir;
if (UKismetSystemLibrary::DoesImplementInterface(gamemode, UPools::StaticClass()))
{
if (AObjectPoolManager* objectPoolManager = IPools::Execute_GetProjectileObjectPoolManager(gamemode))
{
FVector2d ViewportSize;
GEngine->GameViewport->GetViewportSize(ViewportSize);
PlayerController->DeprojectScreenPositionToWorld(0, 0, TopLeft, TopLeftDir);
PlayerController->DeprojectScreenPositionToWorld(ViewportSize.X, 0, TopRight, TopRightDir);
PlayerController->DeprojectScreenPositionToWorld(0, ViewportSize.Y, BottomLeft, BottomLeftDir);
PlayerController->DeprojectScreenPositionToWorld(ViewportSize.X, ViewportSize.Y, BottomRight, BottomRightDir);
FVector actorLocation = GetActorLocation();
TopLeft.Z = actorLocation.Z;
TopRight.Z = actorLocation.Z;
BottomLeft.Z = actorLocation.Z;
BottomRight.Z = actorLocation.Z;
FActorSpawnParameters actorSpawnParameters;
actorSpawnParameters.Owner = this;
actorSpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
actorSpawnParameters.TransformScaleMethod = ESpawnActorScaleMethod::MultiplyWithRoot;
AProjectile* projectile = GetWorld()->SpawnActor<AProjectile>(ProjectileTemplate, GetOwner()->GetTransform(),
actorSpawnParameters);
projectile->SetTargetDirection(UKismetMathLibrary::GetDirectionUnitVector(actorLocation, TopLeft));
APlayerCharacter* PlayerCharacter = Cast<APlayerCharacter>(
UGameplayStatics::GetPlayerCharacter(GetWorld(), 0));
AVampirePlayerController* PlayerController = Cast<AVampirePlayerController>(
UGameplayStatics::GetPlayerController(PlayerCharacter, 0));
projectile = GetWorld()->SpawnActor<AProjectile>(ProjectileTemplate, GetOwner()->GetTransform(),
actorSpawnParameters);
projectile->SetTargetDirection(UKismetMathLibrary::GetDirectionUnitVector(actorLocation, TopRight));
FVector TopLeft, TopLeftDir;
FVector TopRight, TopRightDir;
FVector BottomLeft, BottomLeftDir;
FVector BottomRight, BottomRightDir;
projectile = GetWorld()->SpawnActor<AProjectile>(ProjectileTemplate, GetOwner()->GetTransform(),
actorSpawnParameters);
projectile->SetTargetDirection(UKismetMathLibrary::GetDirectionUnitVector(actorLocation, BottomLeft));
PlayerController->DeprojectScreenPositionToWorld(0, 0, TopLeft, TopLeftDir);
PlayerController->DeprojectScreenPositionToWorld(ViewportSize.X, 0, TopRight, TopRightDir);
PlayerController->DeprojectScreenPositionToWorld(0, ViewportSize.Y, BottomLeft, BottomLeftDir);
PlayerController->DeprojectScreenPositionToWorld(ViewportSize.X, ViewportSize.Y, BottomRight,
BottomRightDir);
projectile = GetWorld()->SpawnActor<AProjectile>(ProjectileTemplate, GetOwner()->GetTransform(),
actorSpawnParameters);
projectile->SetTargetDirection(UKismetMathLibrary::GetDirectionUnitVector(actorLocation, BottomRight));
FVector actorLocation = GetActorLocation();
TopLeft.Z = actorLocation.Z;
TopRight.Z = actorLocation.Z;
BottomLeft.Z = actorLocation.Z;
BottomRight.Z = actorLocation.Z;
AActor* projectile = objectPoolManager->GetObject();
SpawnProjectile(projectile, UKismetMathLibrary::GetDirectionUnitVector(actorLocation, TopLeft));
projectile = objectPoolManager->GetObject();
SpawnProjectile(projectile, UKismetMathLibrary::GetDirectionUnitVector(actorLocation, TopRight));
projectile = objectPoolManager->GetObject();
SpawnProjectile(projectile, UKismetMathLibrary::GetDirectionUnitVector(actorLocation, BottomLeft));
projectile = objectPoolManager->GetObject();
SpawnProjectile(projectile, UKismetMathLibrary::GetDirectionUnitVector(actorLocation, BottomRight));
}
}
}
}
}
void AGunWeapon::SpawnProjectile(AActor* projectile, FVector direction)
{
if (UKismetSystemLibrary::DoesImplementInterface(projectile, UProjectilable::StaticClass()))
{
IProjectilable::Execute_LoadDataFromDataAsset(projectile, ProjectileTemplate);
projectile->SetOwner(this);
IProjectilable::Execute_SetTargetDirection(projectile, direction);
}
}

View File

@ -22,4 +22,7 @@ protected:
public:
virtual void FireWeaponAction_Implementation() override;
private:
void SpawnProjectile(AActor* projectile, FVector direction);
};

View File

@ -3,9 +3,12 @@
#include "KnifeWeapon.h"
#include "GameFramework/GameModeBase.h"
#include "Kismet/GameplayStatics.h"
#include "vampires/ObjectPoolManager.h"
#include "vampires/PlayerCharacter.h"
#include "vampires/Projectile.h"
#include "vampires/Interfaces/Pools.h"
AKnifeWeapon::AKnifeWeapon()
{
@ -22,19 +25,29 @@ void AKnifeWeapon::FireWeaponAction_Implementation()
if (UKismetSystemLibrary::DoesImplementInterface(GetOwner(), UInputable::StaticClass()))
{
if (IsValid(ProjectileTemplate))
if (ProjectileTemplate && OverlappedEnemies.Num() > 0)
{
FActorSpawnParameters actorSpawnParameters;
actorSpawnParameters.Owner = this;
actorSpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
actorSpawnParameters.TransformScaleMethod = ESpawnActorScaleMethod::MultiplyWithRoot;
AGameModeBase* gamemode = UGameplayStatics::GetGameMode(GetWorld());
AProjectile* projectile = GetWorld()->SpawnActor<AProjectile>(ProjectileTemplate, GetOwner()->GetTransform(),
actorSpawnParameters);
if (UKismetSystemLibrary::DoesImplementInterface(gamemode, UPools::StaticClass()))
{
if (AObjectPoolManager* objectPoolManager = IPools::Execute_GetProjectileObjectPoolManager(gamemode))
{
AActor* projectile = objectPoolManager->GetObject();
FVector direction = FVector(IInputable::Execute_Input_GetPreviousMovementDirection(GetOwner()), 0.0);
direction.Normalize();
projectile->SetTargetDirection(direction);
if (UKismetSystemLibrary::DoesImplementInterface(projectile, UProjectilable::StaticClass()))
{
IProjectilable::Execute_LoadDataFromDataAsset(projectile, ProjectileTemplate);
projectile->SetOwner(this);
FVector direction = FVector(IInputable::Execute_Input_GetPreviousMovementDirection(GetOwner()),
0.0);
direction.Normalize();
IProjectilable::Execute_SetTargetDirection(projectile, direction);
}
}
}
}
}
}
}

View File

@ -3,9 +3,12 @@
#include "MagicWandWeapon.h"
#include "GameFramework/GameModeBase.h"
#include "Kismet/GameplayStatics.h"
#include "Kismet/KismetMathLibrary.h"
#include "vampires/ObjectPoolManager.h"
#include "vampires/Projectile.h"
#include "vampires/Interfaces/Pools.h"
AMagicWandWeapon::AMagicWandWeapon()
{
@ -20,25 +23,35 @@ void AMagicWandWeapon::FireWeaponAction_Implementation()
{
Super::FireWeaponAction_Implementation();
if (IsValid(ProjectileTemplate))
if (ProjectileTemplate && OverlappedEnemies.Num() > 0)
{
float distance = 0.0f;
AActor* nearestActor = UGameplayStatics::FindNearestActor(GetActorLocation(), OverlappedEnemies, distance);
if (nearestActor)
{
FActorSpawnParameters actorSpawnParameters;
actorSpawnParameters.Owner = this;
actorSpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
actorSpawnParameters.TransformScaleMethod = ESpawnActorScaleMethod::MultiplyWithRoot;
AProjectile* projectile = GetWorld()->SpawnActor<AProjectile>(ProjectileTemplate, GetOwner()->GetTransform(),
actorSpawnParameters);
FVector direction = UKismetMathLibrary::GetDirectionUnitVector(
GetActorLocation(), nearestActor->GetActorLocation());
direction.Z = 0.0;
direction.Normalize();
projectile->SetTargetDirection(direction);
AGameModeBase* gamemode = UGameplayStatics::GetGameMode(GetWorld());
if (UKismetSystemLibrary::DoesImplementInterface(gamemode, UPools::StaticClass()))
{
if (AObjectPoolManager* objectPoolManager = IPools::Execute_GetProjectileObjectPoolManager(gamemode))
{
AActor* projectile = objectPoolManager->GetObject();
if (UKismetSystemLibrary::DoesImplementInterface(projectile, UProjectilable::StaticClass()))
{
IProjectilable::Execute_LoadDataFromDataAsset(projectile, ProjectileTemplate);
projectile->SetOwner(this);
FVector direction = UKismetMathLibrary::GetDirectionUnitVector(
GetActorLocation(), nearestActor->GetActorLocation());
direction.Z = 0.0;
direction.Normalize();
IProjectilable::Execute_SetTargetDirection(projectile, direction);
}
}
}
}
}
}

View File

@ -6,6 +6,7 @@
#include "vampires/Weapon.h"
#include "ProjectileWeapon.generated.h"
class UProjectileDataAsset;
class AProjectile;
class UBoxComponent;
@ -22,7 +23,7 @@ public:
UBoxComponent* BoxComponent = nullptr;
UPROPERTY(EditAnywhere, Category = "Weapon Properties")
TSubclassOf<AProjectile> ProjectileTemplate = nullptr;
TObjectPtr<UProjectileDataAsset> ProjectileTemplate = nullptr;
protected:
TArray<AActor*> OverlappedEnemies = TArray<AActor*>();

View File

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

View File

@ -0,0 +1,50 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataAsset.h"
#include "WeaponDataAsset.generated.h"
class UPaperSprite;
class AProjectile;
USTRUCT(BlueprintType)
struct FWeaponLevelUpgrades
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float WeaponCooldownMultiplier;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float WeaponDamageMultiplier;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float WeaponRangeMultiplier;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FText WeaponUpgradeText;
};
/**
*
*/
UCLASS(BlueprintType)
class VAMPIRES_API UWeaponDataAsset : public UDataAsset
{
GENERATED_BODY()
public:
UPROPERTY(EditDefaultsOnly, Category = "Weapon Properties")
TSubclassOf<AProjectile> ProjectileTemplate = nullptr;
UPROPERTY(EditDefaultsOnly, Category = "Weapon Properties")
USoundBase* WeaponActivatedSoundBase = nullptr;
UPROPERTY(EditDefaultsOnly, Category = "Weapon Properties")
TObjectPtr<UPaperSprite> WeaponSprite = nullptr;
UPROPERTY(EditDefaultsOnly, Category = "Weapon Upgrades")
TArray<FWeaponLevelUpgrades> WeaponLevelUpgrades = TArray<FWeaponLevelUpgrades>();
};