diff --git a/Source/LegumeMix/Private/Player/LMBulletInfo.h b/Source/LegumeMix/Private/Player/LMBulletInfo.h new file mode 100644 index 0000000..2cac23d --- /dev/null +++ b/Source/LegumeMix/Private/Player/LMBulletInfo.h @@ -0,0 +1,33 @@ +#pragma once +#include "Weapon/LMAmmoType.h" +#include "LMBulletInfo.generated.h" + +USTRUCT(BlueprintType) +struct FLMBulletInfo +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + int BulletCount; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + FVector Origin; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + FVector Direction; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + FVector Spread; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + float MaxDistance; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + FFloatCurve Falloff; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + EAmmoType AmmoType; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + float Damage; +}; diff --git a/Source/LegumeMix/Private/Player/LMPlayer.cpp b/Source/LegumeMix/Private/Player/LMPlayer.cpp index b32b23e..9396841 100644 --- a/Source/LegumeMix/Private/Player/LMPlayer.cpp +++ b/Source/LegumeMix/Private/Player/LMPlayer.cpp @@ -3,6 +3,8 @@ #include "Player/LMPlayer.h" +#include "KismetTraceUtils.h" +#include "LMBulletInfo.h" #include "Camera/CameraComponent.h" #include "Weapon/LMAmmo.h" #include "Weapon/LMWeaponManager.h" @@ -51,6 +53,16 @@ void ALMPlayer::SetWeaponManager(ULMWeaponManager* Manager) WeaponManager->Initialize(ArmsMesh); } +void ALMPlayer::PlayAnimation(UAnimMontage* Animation) +{ +} + +void ALMPlayer::FireBullets(const FLMBulletInfo Settings) +{ + FVector EndLocation = Settings.Origin + (Settings.Direction * Settings.MaxDistance); + TArray Hits; + DrawDebugLineTraceMulti(GetWorld(), Settings.Origin, EndLocation, EDrawDebugTrace::ForDuration, true, Hits, FColor::Green, FColor::Red, 10.f); +} void ALMPlayer::Tick(float DeltaTime) { diff --git a/Source/LegumeMix/Private/Weapon/LMShotgun.cpp b/Source/LegumeMix/Private/Weapon/LMShotgun.cpp new file mode 100644 index 0000000..f379187 --- /dev/null +++ b/Source/LegumeMix/Private/Weapon/LMShotgun.cpp @@ -0,0 +1,39 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Weapon/LMShotgun.h" + +#include "Player/LMBulletInfo.h" +#include "Player/LMPlayer.h" + + +ALMShotgun::ALMShotgun() +{ + PrimaryActorTick.bCanEverTick = true; +} + + +void ALMShotgun::PrimaryFire() +{ + ALMPlayer* Player = Cast(GetOuter()); + if (!Player) + return; + + PlaySound(Data.FireSound); + PlayAnimation(PrimaryFireAnimation); + + FVector Origin = Player->GetWeaponFiringOrigin(); + FVector Direction = Player->GetAimVector(); + + ClipAmmo--; + + FLMBulletInfo ShotInfo = FLMBulletInfo(PelletCount, Origin, Direction, WeaponSpread, MaxDistance, DamageFalloff, AmmoType, Damage); + + Player->FireBullets(ShotInfo); +} + +void ALMShotgun::Tick(float DeltaTime) +{ + Super::Tick(DeltaTime); +} + diff --git a/Source/LegumeMix/Private/Weapon/LMWeaponBase.cpp b/Source/LegumeMix/Private/Weapon/LMWeaponBase.cpp new file mode 100644 index 0000000..3f8abb4 --- /dev/null +++ b/Source/LegumeMix/Private/Weapon/LMWeaponBase.cpp @@ -0,0 +1,56 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Weapon/LMWeaponBase.h" + +#include "Components/AudioComponent.h" + + +ALMWeaponBase::ALMWeaponBase() +{ + PrimaryActorTick.bCanEverTick = true; + + RootComponent = CreateDefaultSubobject(TEXT("Root")); + + AudioComponent = CreateDefaultSubobject(TEXT("Audio")); + AudioComponent->SetupAttachment(RootComponent); + + WeaponMesh = CreateDefaultSubobject(TEXT("Mesh")); + WeaponMesh->SetupAttachment(RootComponent); + + WeaponSocket = FName(); +} + +void ALMWeaponBase::BeginPlay() +{ + Super::BeginPlay(); + +} + +void ALMWeaponBase::Reload() +{ +} + +void ALMWeaponBase::PrimaryFire() +{ +} + +void ALMWeaponBase::PlaySound(USoundWave* Sound, const bool Replacing) +{ + if (AudioComponent->IsPlaying() && !Replacing) + return; + + AudioComponent->Stop(); + AudioComponent->SetSound(Sound); + AudioComponent->Play(); +} + +void ALMWeaponBase::PlayAnimation(UAnimMontage* Animation) +{ + UAnimInstance* AnimInstance = WeaponMesh->GetAnimInstance(); + + if (Animation && AnimInstance) + { + AnimInstance->Montage_Play(Animation); + } +} \ No newline at end of file diff --git a/Source/LegumeMix/Private/Weapon/LMWeaponManager.cpp b/Source/LegumeMix/Private/Weapon/LMWeaponManager.cpp index fcea7aa..d2ea688 100644 --- a/Source/LegumeMix/Private/Weapon/LMWeaponManager.cpp +++ b/Source/LegumeMix/Private/Weapon/LMWeaponManager.cpp @@ -3,7 +3,7 @@ #include "Weapon/LMWeaponManager.h" -#include "Weapon/LMWeapon.h" +#include "Weapon/LMWeaponBase.h" ULMWeaponManager::ULMWeaponManager() @@ -18,17 +18,25 @@ void ULMWeaponManager::BeginPlay() void ULMWeaponManager::Initialize(USkeletalMeshComponent* Mesh) { - SetWeaponMeshComponent(Mesh); - - for (auto Weapon : StartingWeapons) - { - if (Weapon) - { - ULMWeapon* Instance = NewObject(this, Weapon); - Weapons.Add(Instance); + ArmsMesh = Mesh; - Instance->Initialize(Mesh->GetRelativeLocation()); - } + for (auto WeaponTemplate : StartingWeapons) + { + if (!WeaponTemplate) + continue; + + ALMWeaponBase* Instance = GetWorld()->SpawnActor(WeaponTemplate); + GEngine->AddOnScreenDebugMessage(INDEX_NONE, 2.f, FColor::Blue, TEXT("Spawing")); + Instance->SetActorHiddenInGame(true); + + Weapons.Add(Instance); + + FAttachmentTransformRules Rules = FAttachmentTransformRules(EAttachmentRule::SnapToTarget, + EAttachmentRule::KeepRelative, + EAttachmentRule::KeepRelative, + false); + + Instance->AttachToComponent(ArmsMesh, Rules); } if (!Weapons.IsEmpty()) @@ -41,29 +49,23 @@ void ULMWeaponManager::AddAmmoType(EAmmoType AmmoType, int AmmoCount) { FString Debug = FString::Printf(TEXT("Adding %i ammo of type %i"), AmmoCount, AmmoType); GEngine->AddOnScreenDebugMessage(1, 1.f, FColor::Cyan, Debug); - - for (const auto Weapon : Weapons) - { - if (Weapon->WeaponDataStructure.AmmoType != AmmoType) - continue; - Weapon->AddAmmo(AmmoCount); - } + } void ULMWeaponManager::Fire() { - ULMWeapon* Weapon = GetCurrentWeapon(); + ALMWeaponBase* Weapon = GetCurrentWeapon(); GEngine->AddOnScreenDebugMessage(2, 1.f, FColor::Cyan, "Fire"); - Weapon->Fire(); + Weapon->PrimaryFire(); } void ULMWeaponManager::Reload() { GEngine->AddOnScreenDebugMessage(3, 1.f, FColor::Cyan, "Reloading"); - ULMWeapon* Weapon = GetCurrentWeapon(); + ALMWeaponBase* Weapon = GetCurrentWeapon(); Weapon->Reload(); } @@ -91,13 +93,8 @@ void ULMWeaponManager::SetWeapon(const int Index) return; } + GetCurrentWeapon()->SetActorHiddenInGame(true); CurrentWeaponIndex = Index; - - if (WeaponMeshComponent) - { - GEngine->AddOnScreenDebugMessage(INDEX_NONE, 5, FColor::Red, "Has Mesh"); - - WeaponMeshComponent->SetSkeletalMeshAsset(GetCurrentWeapon()->WeaponDataStructure.MeshWeapon); - } + GetCurrentWeapon()->SetActorHiddenInGame(false); } diff --git a/Source/LegumeMix/Public/Player/LMPlayer.h b/Source/LegumeMix/Public/Player/LMPlayer.h index 510b8c2..78c74f7 100644 --- a/Source/LegumeMix/Public/Player/LMPlayer.h +++ b/Source/LegumeMix/Public/Player/LMPlayer.h @@ -3,6 +3,7 @@ #pragma once #include "CoreMinimal.h" +#include "Camera/CameraComponent.h" #include "GameFramework/Character.h" #include "LMPlayer.generated.h" @@ -36,6 +37,18 @@ public: UFUNCTION(BlueprintCallable) void SetWeaponManager(ULMWeaponManager* Manager); + UFUNCTION(BlueprintCallable) + void PlayAnimation(UAnimMontage* Animation); + + UFUNCTION(BlueprintCallable) + void FireBullets(const FLMBulletInfo Settings); + + UFUNCTION(BlueprintCallable) + FVector GetWeaponFiringOrigin() const { return Camera->GetComponentLocation(); } + + UFUNCTION(BlueprintCallable) + FVector GetAimVector() const { return Camera->GetForwardVector(); } + private: UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Legumix, meta = (AllowPrivateAccess = true)) TObjectPtr WeaponManager; diff --git a/Source/LegumeMix/Public/Weapon/LMShotgun.h b/Source/LegumeMix/Public/Weapon/LMShotgun.h new file mode 100644 index 0000000..b067ff1 --- /dev/null +++ b/Source/LegumeMix/Public/Weapon/LMShotgun.h @@ -0,0 +1,23 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "LMWeaponBase.h" +#include "LMShotgun.generated.h" + +UCLASS() +class LEGUMEMIX_API ALMShotgun : public ALMWeaponBase +{ + GENERATED_BODY() + +public: + ALMShotgun(); + virtual void Tick(float DeltaTime) override; + virtual void PrimaryFire() override; + +private: + /** The number of pellets fired by the shotgun. */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Legumix|Weapon", meta = (AllowPrivateAccess = true)) + int PelletCount = 8; +}; diff --git a/Source/LegumeMix/Public/Weapon/LMWeaponBase.h b/Source/LegumeMix/Public/Weapon/LMWeaponBase.h new file mode 100644 index 0000000..4c1c3d5 --- /dev/null +++ b/Source/LegumeMix/Public/Weapon/LMWeaponBase.h @@ -0,0 +1,87 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "LMAmmo.h" +#include "LMWeaponDataStructure.h" +#include "GameFramework/Actor.h" +#include "GameFramework/SpringArmComponent.h" +#include "LMWeaponBase.generated.h" + + +UCLASS() +class LEGUMEMIX_API ALMWeaponBase : public AActor +{ + GENERATED_BODY() + +public: + ALMWeaponBase(); + virtual void BeginPlay() override; + +public: + UFUNCTION(BlueprintCallable) + virtual void Reload(); + + UFUNCTION(BlueprintCallable) + virtual void PrimaryFire(); + + UFUNCTION(BlueprintCallable) + void PlaySound(USoundWave* Sound, bool Replacing = false); + + UFUNCTION(BlueprintCallable) + void PlayAnimation(UAnimMontage* Animation); + + /** The socket to attach the weapon to. + * @return The socket. + */ + UFUNCTION(BlueprintCallable) + FName GetAttachmentSocketName() const { return WeaponSocket; } + +protected: /* Weapon Data */ + /** The weapon static data. */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Legumix, meta=(AllowPrivateAccess=true)) + FLMWeaponDataStructure Data; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Legumix|Animations", meta=(AllowPrivateAccess=true)) + TObjectPtr PrimaryFireAnimation; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Legumix|Animations", meta=(AllowPrivateAccess=true)) + TObjectPtr ReloadAnimation; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Legumix|Weapon", meta=(AllowPrivateAccess=true)) + float Damage = 10.f; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Legumix|Weapon", meta=(AllowPrivateAccess=true)) + FVector WeaponSpread = FVector::ZeroVector; + + /** The max distance (cm) between the origin and the target before doing minimal damage. */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Legumix|Weapon", meta=(AllowPrivateAccess=true)) + float MaxDistance = 100000.f; + + /** The damage falloff distance in a 0-1 scale. */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Legumix|Weapon", meta=(AllowPrivateAccess=true)) + FFloatCurve DamageFalloff; + + /** The type of ammo used by this weapon. */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Legumix|Weapon", meta=(AllowPrivateAccess=true)) + EAmmoType AmmoType; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Legumix|Weapon", meta=(AllowPrivateAccess=true)) + int ClipAmmo; + +private: + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Legumix, meta=(AllowPrivateAccess=true)) + FDataTableRowHandle DataTableRow; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Legumix, meta=(AllowPrivateAccess=true)) + FName WeaponSocket; + +private: /* Components */ + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Legumix, meta=(AllowPrivateAccess=true)) + TObjectPtr AudioComponent; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Legumix, meta=(AllowPrivateAccess=true)) + TObjectPtr WeaponMesh; +}; + diff --git a/Source/LegumeMix/Public/Weapon/LMWeaponManager.h b/Source/LegumeMix/Public/Weapon/LMWeaponManager.h index 7103bfb..b38b175 100644 --- a/Source/LegumeMix/Public/Weapon/LMWeaponManager.h +++ b/Source/LegumeMix/Public/Weapon/LMWeaponManager.h @@ -8,35 +8,36 @@ #include "LMWeaponManager.generated.h" +class ALMWeaponBase; class ULMWeapon; -UCLASS(Blueprintable, BlueprintType, ClassGroup="Legumix", meta=(BlueprintSpawnableComponent)) +UCLASS(Blueprintable, BlueprintType, ClassGroup=Legumix, meta=(BlueprintSpawnableComponent)) class LEGUMEMIX_API ULMWeaponManager : public UActorComponent { GENERATED_BODY() public: ULMWeaponManager(); - void SetWeaponMeshComponent(USkeletalMeshComponent* Mesh) { WeaponMeshComponent = Mesh; } + void SetArmsMesh(USkeletalMeshComponent* Mesh) { ArmsMesh = Mesh; } public: /** * Get the Weapon currently equipped. * @return The Current Weapon. */ - UFUNCTION(BlueprintCallable, Category="Legumix") - ULMWeapon* GetCurrentWeapon() { return Weapons[CurrentWeaponIndex]; } + UFUNCTION(BlueprintCallable, Category=Legumix) + ALMWeaponBase* GetCurrentWeapon() { return Weapons[CurrentWeaponIndex]; } - UFUNCTION(BlueprintCallable, Category="Legumix") + UFUNCTION(BlueprintCallable, Category=Legumix) void SetWeapon(int Index); - UFUNCTION(BlueprintCallable, Category="Legumix") + UFUNCTION(BlueprintCallable, Category=Legumix) void AddAmmoType(EAmmoType AmmoType, int AmmoCount); - UFUNCTION(BlueprintCallable, Category="Legumix") + UFUNCTION(BlueprintCallable, Category=Legumix) void Fire(); - UFUNCTION(BlueprintCallable, Category="Legumix") + UFUNCTION(BlueprintCallable, Category=Legumix) void Reload(); void SwitchWeapon(int Direction); @@ -46,16 +47,16 @@ protected: virtual void BeginPlay() override; private: - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Legumix", meta = (AllowPrivateAccess = "true")) - TObjectPtr WeaponMeshComponent; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Legumix, meta = (AllowPrivateAccess = "true")) + TObjectPtr ArmsMesh; /** The weapons the player starts with. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Legumix", meta=(AllowPrivateAccess=true)) - TArray> StartingWeapons; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Legumix, meta=(AllowPrivateAccess=true)) + TArray> StartingWeapons; - UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Legumix", meta=(AllowPrivateAccess=true)) - TArray> Weapons; + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Legumix, meta=(AllowPrivateAccess=true)) + TArray> Weapons; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Legumix", meta=(AllowPrivateAccess=true)) + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Legumix, meta=(AllowPrivateAccess=true)) int CurrentWeaponIndex = 0; };