Skip to content

Commit

Permalink
#121 Added weapon spawner with VFX
Browse files Browse the repository at this point in the history
  • Loading branch information
xthebat committed Jan 28, 2024
1 parent d2d9a2e commit 5906bc8
Show file tree
Hide file tree
Showing 32 changed files with 334 additions and 9 deletions.
Binary file not shown.
Binary file modified Content/Blueprints/Weapons/FirearmWeaponsTable.uasset
Binary file not shown.
Binary file modified Content/Blueprints/Weapons/GrenadeWeaponTable.uasset
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified Content/Blueprints/Weapons/MeleeWeaponTable.uasset
Binary file not shown.
Binary file added Content/Panorama/Icons/Equipment/ak47.uasset
Binary file not shown.
Binary file added Content/Panorama/Icons/Equipment/armor.uasset
Binary file not shown.
Binary file not shown.
Binary file added Content/Panorama/Icons/Equipment/awp.uasset
Binary file not shown.
Binary file added Content/Panorama/Icons/Equipment/c4.uasset
Binary file not shown.
Binary file added Content/Panorama/Icons/Equipment/deagle.uasset
Binary file not shown.
Binary file added Content/Panorama/Icons/Equipment/flashbang.uasset
Binary file not shown.
Binary file added Content/Panorama/Icons/Equipment/hegrenade.uasset
Binary file not shown.
Binary file added Content/Panorama/Icons/Equipment/helmet.uasset
Binary file not shown.
Binary file added Content/Panorama/Icons/Equipment/hkp2000.uasset
Binary file not shown.
Binary file not shown.
Binary file added Content/Panorama/Icons/Equipment/inferno.uasset
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added Content/Panorama/Icons/Equipment/mp9.uasset
Binary file not shown.
Binary file added Content/Panorama/Icons/Equipment/nova.uasset
Binary file not shown.
Binary file not shown.
26 changes: 25 additions & 1 deletion Source/Cloud9/Game/Cloud9AssetManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,31 @@

#include "Cloud9AssetManager.h"

UObject* UCloud9AssetManager::GetOrLoadAssetSync(FPrimaryAssetId PrimaryAssetId)
#include "Cloud9/Weapon/Assets/WeaponDefinitionsAsset.h"

UObject* UCloud9AssetManager::GetOrLoadAssetSync(
FPrimaryAssetId PrimaryAssetId,
const FString& Path,
UClass* BaseClass,
bool bHasBlueprintClasses,
bool bIsEditorOnly)
{
static var& Manager = Get();

// Required to scan when using in OnConstruction method
Manager.ScanPathForPrimaryAssets(
PrimaryAssetId.PrimaryAssetType,
Path,
BaseClass,
bHasBlueprintClasses,
bIsEditorOnly,
true
);

return GetOrLoadScannedAssetSync(PrimaryAssetId);
}

UObject* UCloud9AssetManager::GetOrLoadScannedAssetSync(FPrimaryAssetId PrimaryAssetId)
{
static var& Manager = Get();

Expand Down
65 changes: 62 additions & 3 deletions Source/Cloud9/Game/Cloud9AssetManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,71 @@ class CLOUD9_API UCloud9AssetManager : public UAssetManager
GENERATED_BODY()

public:
/**
* Scans a path and reads asset data for all primary assets of a specific type.
* If done in the editor it will load the data off disk, in cooked games it will
* load out of the asset registry cache.
*
* Then loads primary asset and adds loaded asset to root (AddToRoot) to prevent it from destroy by GC.
*
* @param PrimaryAssetId Asset Id to load
* @param Path Path to scan of assets
* @param BaseClass
* @param bHasBlueprintClasses
* @param bIsEditorOnly
* @return
*/
UFUNCTION(BlueprintCallable)
static UObject* GetOrLoadAssetSync(FPrimaryAssetId PrimaryAssetId);
static UObject* GetOrLoadAssetSync(
FPrimaryAssetId PrimaryAssetId,
const FString& Path,
UClass* BaseClass,
bool bHasBlueprintClasses = false,
bool bIsEditorOnly = false);

/**
* Template functions wrapper for GetOrLoadAssetSync
*
* @tparam ClassType Class type of asset to look for
* @param bHasBlueprintClasses If true, the assets are blueprints that subclass BaseClass.
* If false they are base UObject assets
* @param bIsEditorOnly If true, assets will only be scanned in editor builds,
* and will not be stored into the asset registry
* @return Object of loaded asset
*/
template <typename ClassType>
static ClassType* GetOrLoadAssetSync(FPrimaryAssetId PrimaryAssetId = ClassType::PrimaryAssetId)
static ClassType* GetOrLoadAssetSync(bool bHasBlueprintClasses = false, bool bIsEditorOnly = false)
{
return Cast<ClassType>(GetOrLoadAssetSync(PrimaryAssetId));
let Asset = GetOrLoadAssetSync(
ClassType::PrimaryAssetId,
ClassType::Path,
ClassType::StaticClass(),
bHasBlueprintClasses,
bIsEditorOnly
);

return Cast<ClassType>(Asset);
}

/**
* Functions loads primary asset only if it was scanned (e.g. won't work for PIE start OnConstruction method).
* Also function adds loaded asset to root (AddToRoot) to prevent it from destroy by GC.
*
* @param PrimaryAssetId Asset Id to load
* @return Object of loaded asset
*/
UFUNCTION(BlueprintCallable)
static UObject* GetOrLoadScannedAssetSync(FPrimaryAssetId PrimaryAssetId);

/**
* Template functions wrapper for GetOrLoadScannedAssetSync
*
* @param PrimaryAssetId Asset Id to load
* @return Object of loaded asset
*/
template <typename ClassType>
static ClassType* GetOrLoadScannedAssetSync(FPrimaryAssetId PrimaryAssetId = ClassType::PrimaryAssetId)
{
return Cast<ClassType>(GetOrLoadScannedAssetSync(PrimaryAssetId));
}
};
1 change: 1 addition & 0 deletions Source/Cloud9/Weapon/Assets/WeaponDefinitionsAsset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "Cloud9/Weapon/Extensions/EWeaponId.h"

const FPrimaryAssetId UWeaponDefinitionsAsset::PrimaryAssetId = FPrimaryAssetId("Weapon:Definitions");
const FString UWeaponDefinitionsAsset::Path = TEXT("/Game/Blueprints/Weapons");

template <typename WeaponIdType, typename ValidatorType>
FWeaponDefinition UWeaponDefinitionsAsset::GetWeaponDefinition(
Expand Down
1 change: 1 addition & 0 deletions Source/Cloud9/Weapon/Assets/WeaponDefinitionsAsset.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class CLOUD9_API UWeaponDefinitionsAsset : public UPrimaryDataAsset

public:
static const FPrimaryAssetId PrimaryAssetId;
static const FString Path;

public: // functions
bool GetWeaponDefinition(const FWeaponId& WeaponId, FWeaponDefinition& WeaponDefinition) const;
Expand Down
10 changes: 6 additions & 4 deletions Source/Cloud9/Weapon/Classes/Cloud9WeaponBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ class CLOUD9_API ACloud9WeaponBase : public AActor
static const FName MuzzleFlashSocketName;
static const FName CaseEjectSocketName;

public:
static UWeaponDefinitionsAsset* GetWeaponDefinitionsAsset();

public:
ACloud9WeaponBase();

Expand Down Expand Up @@ -165,6 +168,9 @@ class CLOUD9_API ACloud9WeaponBase : public AActor
virtual void SecondaryAction(bool IsReleased);
virtual void Reload(bool IsReleased);

protected:
static void ChangeMeshCollisionState(UStaticMeshComponent* Mesh, bool bIsEnabled);

protected: // functions
virtual bool OnInitialize(const FWeaponId& NewWeaponId, FName NewWeaponSkin);
virtual void Deinitialize();
Expand All @@ -181,10 +187,6 @@ class CLOUD9_API ACloud9WeaponBase : public AActor
*/
virtual void OnWeaponRemovedFromInventory();

static UWeaponDefinitionsAsset* GetWeaponDefinitionsAsset();

static void ChangeMeshCollisionState(UStaticMeshComponent* Mesh, bool bIsEnabled);

UStaticMeshComponent* CreateMeshComponent(FName ComponentName, FName SocketName = NAME_None);
UNiagaraComponent* CreateEffectComponent(FName ComponentName, FName SocketName = NAME_None);
URadialForceComponent* CreateDetonateComponent(FName ComponentName);
Expand Down
2 changes: 1 addition & 1 deletion Source/Cloud9/Weapon/Notifiers/Cloud9AnimNotifyWeapon.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class CLOUD9_API UCloud9AnimNotifyWeapon : public UAnimNotify

if (not IsValid(Inventory))
{
log(Error, "Invenotry is invalid");
log(Error, "Inventory is invalid");
return nullptr;
}

Expand Down
6 changes: 6 additions & 0 deletions Source/Cloud9/Weapon/Tables/WeaponTableBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ struct FBaseWeaponInfo : public FTableRowBase
*/
UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category=Base, AdvancedDisplay)
FText Description;

/**
* Weapon icon
*/
UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category=Icon)
UTexture2D* Icon;
};

namespace EFWeaponInfo
Expand Down
151 changes: 151 additions & 0 deletions Source/Cloud9/Weapon/Utils/WeaponSpawner.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
// Copyright (c) 2023 Alexei Gladkikh


#include "WeaponSpawner.h"

#include "NiagaraComponent.h"
#include "Components/BoxComponent.h"

#include "Cloud9/Character/Cloud9Character.h"
#include "Cloud9/Weapon/Classes/Cloud9WeaponBase.h"
#include "Components/BillboardComponent.h"

FName AWeaponSpawner::RootComponentName = "RootComponent";
FName AWeaponSpawner::TriggerBoxComponentName = "TriggerBox";
FName AWeaponSpawner::WeaponSampleComponentName = "WeaponInitializer";
FName AWeaponSpawner::GlowingEffectComponentName = "GlowingEffect";
FName AWeaponSpawner::SpriteComponentName = "Sprite";

AWeaponSpawner::AWeaponSpawner()
{
PrimaryActorTick.bCanEverTick = true;

RootComponent = CreateDefaultSubobject<USceneComponent>(RootComponentName);

TriggerBoxComponent = CreateDefaultSubobject<UBoxComponent>(TriggerBoxComponentName);
WeaponSampleComponent = CreateDefaultSubobject<UChildActorComponent>(WeaponSampleComponentName);
GlowingEffectComponent = CreateDefaultSubobject<UNiagaraComponent>(GlowingEffectComponentName);

TriggerBoxComponent->SetupAttachment(RootComponent);
WeaponSampleComponent->SetupAttachment(RootComponent);
GlowingEffectComponent->SetupAttachment(RootComponent);

GlowingEffect = nullptr;
SampleScale = 1.0f;
RotationSpeedInDegree = 0.0f;
bIsRandomInitialRotation = false;
ZoneSize = {20.0f, 20.0f, 20.0f};

TriggerBoxComponent->OnComponentBeginOverlap.AddDynamic(this, &AWeaponSpawner::OnBeginOverlap);

#if WITH_EDITORONLY_DATA
// SpriteComponent = CreateEditorOnlyDefaultSubobject<UBillboardComponent>(SpriteComponentName);
// SpriteComponent->SetupAttachment(RootComponent);
//
// static ConstructorHelpers::FObjectFinderOptional<UTexture2D>
// TriggerTextureObject(TEXT("/Engine/EditorResources/S_Trigger"));
//
// SpriteComponent->Sprite = TriggerTextureObject.Get();
// SpriteComponent->SetRelativeScale3D(FVector(0.5f, 0.5f, 0.5f));
// SpriteComponent->bHiddenInGame = true;
// SpriteComponent->bIsScreenSizeScaled = true;
#endif
}

void AWeaponSpawner::OnConstruction(const FTransform& Transform)
{
Super::OnConstruction(Transform);

TriggerBoxComponent->SetBoxExtent(ZoneSize);

if (IsValid(GlowingEffect))
{
GlowingEffectComponent->SetAsset(GlowingEffect);
}

if (IsValid(WeaponConfig))
{
WeaponSampleComponent->SetChildActorClass(WeaponConfig.GetWeaponStaticClass());

var WeaponSample = WeaponSampleComponent->GetChildActor();

if (not IsValid(WeaponSample))
{
WeaponSampleComponent->CreateChildActor();
WeaponSample = WeaponSampleComponent->GetChildActor();
}

if (not WeaponConfig.Initialize(WeaponSample))
{
// WeaponSampleComponent->DestroyChildActor();
SetActorTickEnabled(false);
return;
}

if (not IsValid(WeaponSample))
{
log(Error, "WeaponSampleComponent child actor is invalid");
return;
}

WeaponSample->UpdateComponentTransforms();
WeaponSample->SetActorEnableCollision(false);
WeaponSample->SetActorScale3D({SampleScale, SampleScale, SampleScale});

if (bIsRandomInitialRotation)
{
var Rotation = WeaponSample->GetActorRotation();
Rotation.Yaw = FMath::RandRange(0.0f, 360.0f);
WeaponSample->SetActorRotation(Rotation);
}
}
}

void AWeaponSpawner::BeginPlay()
{
Super::BeginPlay();
}

void AWeaponSpawner::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);

if (IsValid(WeaponConfig))
{
let Actor = WeaponSampleComponent->GetChildActor();

if (not IsValid(Actor))
{
log(Error, "WeaponSampleComponent child actor is invalid");
return;
}

var Rotation = Actor->GetActorRotation();
Rotation.Yaw += DeltaTime * RotationSpeedInDegree;
Actor->SetActorRotation(Rotation);
}
}

void AWeaponSpawner::OnBeginOverlap(
UPrimitiveComponent* OverlappedComponent,
AActor* OtherActor,
UPrimitiveComponent* OtherComponent,
int32 OtherBodyIndex,
bool bFromSweep,
const FHitResult& Hit)
{
if (let Character = Cast<ACloud9Character>(OtherActor); IsValid(Character) and IsValid(WeaponConfig))
{
let Inventory = Character->GetInventory();

if (not IsValid(Inventory))
{
log(Error, "Inventory is invalid");
return;
}

Inventory->AddWeapon(WeaponConfig, true, true);
}
}

void AWeaponSpawner::Initialize() {}
Loading

0 comments on commit 5906bc8

Please sign in to comment.