Section 5 - The Weapon - Course 65

Hide Widget
This commit is contained in:
charnet3d 2022-07-09 03:56:12 +01:00
parent 402ede1696
commit ec9991e77c
9 changed files with 207 additions and 57 deletions

3
.gitignore vendored
View File

@ -72,3 +72,6 @@ Plugins/*/Intermediate/*
# Cache files for the editor to use
DerivedDataCache/*
/Content/ModSci_Engineer/
/Content/ModSci_EngiProps/
/Content/ModSciInteriors/

View File

@ -1,8 +1,8 @@
[/Script/EngineSettings.GameMapsSettings]
GameDefaultMap=/Game/_Game/Maps/Factory.Factory
EditorStartupMap=/Game/_Game/Maps/Factory.Factory
GameDefaultMap=/Game/ModSciInteriors/Maps/Example_2_Dynamic.Example_2_Dynamic
EditorStartupMap=/Game/ModSciInteriors/Maps/Example_2_Dynamic.Example_2_Dynamic
GlobalDefaultGameMode=/Game/_Game/GameMode/ShooterGameModeBaseBP.ShooterGameModeBaseBP_C
[/Script/HardwareTargeting.HardwareTargetingSettings]

BIN
Content/_Game/HUD/PickupWidgetBP.uasset (Stored with Git LFS)

Binary file not shown.

BIN
Content/_Game/Maps/Factory.umap (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

View File

@ -2,7 +2,11 @@
#include "Item.h"
#include "ShooterCharacter.h"
#include "Components/BoxComponent.h"
#include "Components/SphereComponent.h"
#include "Components/WidgetComponent.h"
// Sets default values
AItem::AItem()
@ -15,6 +19,14 @@ AItem::AItem()
CollisionBox = CreateDefaultSubobject<UBoxComponent>(TEXT("CollisionBox"));
CollisionBox->SetupAttachment(ItemMesh);
CollisionBox->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);
CollisionBox->SetCollisionResponseToChannel(ECollisionChannel::ECC_Visibility, ECollisionResponse::ECR_Block);
PickupWidget = CreateDefaultSubobject<UWidgetComponent>(TEXT("PickupWidget"));
PickupWidget->SetupAttachment(GetRootComponent());
AreaSphere = CreateDefaultSubobject<USphereComponent>(TEXT("AreaSphere"));
AreaSphere->SetupAttachment(GetRootComponent());
}
// Called when the game starts or when spawned
@ -22,6 +34,12 @@ void AItem::BeginPlay()
{
Super::BeginPlay();
// Hide Pickup Widget
PickupWidget->SetVisibility(false);
// Setup overlap for AreaSphere
AreaSphere->OnComponentBeginOverlap.AddDynamic(this, &AItem::OnSphereOverlap);
AreaSphere->OnComponentEndOverlap.AddDynamic(this, &AItem::OnSphereEndOverlap);
}
// Called every frame
@ -31,3 +49,31 @@ void AItem::Tick(float DeltaTime)
}
void AItem::OnSphereOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp,
int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
if (OtherActor)
{
AShooterCharacter* ShooterCharacter = Cast<AShooterCharacter>(OtherActor);
if (ShooterCharacter)
{
ShooterCharacter->IncrementOverlappedItemCount(1);
}
}
}
void AItem::OnSphereEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
if (OtherActor)
{
AShooterCharacter* ShooterCharacter = Cast<AShooterCharacter>(OtherActor);
if (ShooterCharacter)
{
ShooterCharacter->IncrementOverlappedItemCount(-1);
}
}
}

View File

@ -8,6 +8,7 @@
class UBoxComponent;
class UWidgetComponent;
class USphereComponent;
UCLASS()
class SHOOTER_API AItem : public AActor
@ -26,6 +27,17 @@ public:
// Called every frame
virtual void Tick(float DeltaTime) override;
/* Called when overlapping AreaSphere */
UFUNCTION()
void OnSphereOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep,
const FHitResult& SweepResult);
/* Called when end overlapping AreaSphere */
UFUNCTION()
void OnSphereEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
private:
/* Skeletal mesh for the item */
@ -40,6 +52,10 @@ private:
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item Properties", meta = (AllowPrivateAccess = true))
UWidgetComponent* PickupWidget;
public:
/* Enables item tracing when overlapped */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item Properties", meta = (AllowPrivateAccess = true))
USphereComponent* AreaSphere;
public:
FORCEINLINE UWidgetComponent* GetPickupWidget() const { return PickupWidget; }
};

View File

@ -3,7 +3,9 @@
#include "ShooterCharacter.h"
#include "Item.h"
#include "Camera/CameraComponent.h"
#include "Components/WidgetComponent.h"
#include "Engine/SkeletalMeshSocket.h"
#include "GameFramework/SpringArmComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
@ -45,7 +47,9 @@ AShooterCharacter::AShooterCharacter() :
// Automatic fire
bShouldFire(true),
bFireButtonPressed(false),
AutomaticFireRate(0.1f)
AutomaticFireRate(0.1f),
// Item trace variables
bShouldTraceForItems(false)
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
@ -215,56 +219,24 @@ void AShooterCharacter::FireWeapon()
bool AShooterCharacter::GetBeamEndLocation(const FVector& MuzzleSocketLocation, FVector& OutBeamLocation)
{
// Get current size of the viewport
FVector2D ViewportSize;
// Check for crosshair trace hit
FHitResult CrosshairHitResult;
bool bCrosshairHit = TraceUnderCrosshairs(CrosshairHitResult, OutBeamLocation);
if (GEngine && GEngine->GameViewport)
// Perform a second trace, this time from the gun barrel
FHitResult WeaponTraceHit;
const FVector WeaponTraceStart{ MuzzleSocketLocation };
const FVector StartToEnd{ OutBeamLocation - MuzzleSocketLocation };
const FVector WeaponTraceEnd{ MuzzleSocketLocation + StartToEnd * 1.25f };
GetWorld()->LineTraceSingleByChannel(WeaponTraceHit, WeaponTraceStart, WeaponTraceEnd,
ECollisionChannel::ECC_Visibility);
if (WeaponTraceHit.bBlockingHit) // Object between barrel and BeamEndPoint ?
{
GEngine->GameViewport->GetViewportSize(ViewportSize);
}
// Get screen space location of crosshairs
FVector2D CrosshairLocation{ ViewportSize.X / 2.f, ViewportSize.Y / 2.f };
// Get world position and direction of crosshairs
FVector CrosshairWorldPosition;
FVector CrosshairWorldDirection;
bool bScreenToWorld = UGameplayStatics::DeprojectScreenToWorld(
UGameplayStatics::GetPlayerController(this, 0),
CrosshairLocation, CrosshairWorldPosition, CrosshairWorldDirection);
if (bScreenToWorld) // Was deprojection successful
{
FHitResult ScreenTraceHit;
const FVector Start{ CrosshairWorldPosition };
const FVector End{ CrosshairWorldPosition + CrosshairWorldDirection * 50'000.f };
// Set beam end point to line trace end point
OutBeamLocation = End;
// Trace outward from crosshairs world location
GetWorld()->LineTraceSingleByChannel(ScreenTraceHit, Start, End, ECollisionChannel::ECC_Visibility);
if (ScreenTraceHit.bBlockingHit) // was there a trace hit ?
{
// Beam end point is now trace hit location
OutBeamLocation = ScreenTraceHit.Location;
}
FHitResult WeaponTraceHit;
const FVector WeaponTraceStart{ MuzzleSocketLocation };
const FVector WeaponTraceEnd{ OutBeamLocation };
GetWorld()->LineTraceSingleByChannel(WeaponTraceHit, WeaponTraceStart, WeaponTraceEnd,
ECollisionChannel::ECC_Visibility);
if (WeaponTraceHit.bBlockingHit) // Object between barrel and BeamEndPoint ?
{
OutBeamLocation = WeaponTraceHit.Location;
}
OutBeamLocation = WeaponTraceHit.Location;
return true;
}
return false;
}
@ -417,6 +389,83 @@ void AShooterCharacter::AutoFireReset()
}
}
bool AShooterCharacter::TraceUnderCrosshairs(FHitResult& OutHitResult, FVector& OutHitLocation)
{
// Get Viewport Size
FVector2D ViewportSize;
if (GEngine && GEngine->GameViewport)
{
GEngine->GameViewport->GetViewportSize(ViewportSize);
}
// Get screen space location of crosshairs
FVector2D CrosshairLocation{ ViewportSize.X / 2.f, ViewportSize.Y / 2.f };
// Get world position and direction of crosshairs
FVector CrosshairWorldPosition;
FVector CrosshairWorldDirection;
bool bScreenToWorld = UGameplayStatics::DeprojectScreenToWorld(
UGameplayStatics::GetPlayerController(this, 0),
CrosshairLocation, CrosshairWorldPosition, CrosshairWorldDirection);
if (bScreenToWorld)
{
// Trace from Crosshair world location outward
const FVector Start{ CrosshairWorldPosition };
const FVector End{ Start + CrosshairWorldDirection * 50'000.f };
OutHitLocation = End;
GetWorld()->LineTraceSingleByChannel(OutHitResult, Start, End, ECollisionChannel::ECC_Visibility);
if (OutHitResult.bBlockingHit)
{
OutHitLocation = OutHitResult.Location;
return true;
}
}
return false;
}
void AShooterCharacter::TraceForItems()
{
static AItem* HitItem;
if (bShouldTraceForItems)
{
FHitResult ItemTraceResult;
FVector HitLocation;
TraceUnderCrosshairs(ItemTraceResult, HitLocation);
if (ItemTraceResult.bBlockingHit)
{
// If an item was being looked at from last frame, we should hide its widget
SetItemPickupWidgetVisibility(HitItem, false);
// Show the new item's widget
HitItem = Cast<AItem>(ItemTraceResult.GetActor());
SetItemPickupWidgetVisibility(HitItem, true);
}
else if (HitItem) // Hide widget for the item from last frame
{
SetItemPickupWidgetVisibility(HitItem, false);
HitItem = nullptr;
}
}
else if (HitItem) // Hide widget for the item from last frame
{
SetItemPickupWidgetVisibility(HitItem, false);
HitItem = nullptr;
}
}
void AShooterCharacter::SetItemPickupWidgetVisibility(AItem* Item, bool visibility)
{
if (Item && Item->GetPickupWidget())
{
Item->GetPickupWidget()->SetVisibility(visibility);
}
}
// Called every frame
void AShooterCharacter::Tick(float DeltaTime)
{
@ -430,6 +479,8 @@ void AShooterCharacter::Tick(float DeltaTime)
// Calculate crosshair spread multiplier
CalculateCrosshairSpread(DeltaTime);
TraceForItems();
}
// Called to bind functionality to input
@ -466,3 +517,17 @@ float AShooterCharacter::GetCrosshairSpreadMultiplier() const
return CrosshairSpreadMultiplier;
}
void AShooterCharacter::IncrementOverlappedItemCount(int8 Amount)
{
if (OverlappedItemCount + Amount <= 0)
{
OverlappedItemCount = 0;
bShouldTraceForItems = false;
}
else
{
OverlappedItemCount += Amount;
bShouldTraceForItems = true;
}
}

View File

@ -11,6 +11,7 @@ class UCameraComponent;
class USoundCue;
class UParticleSystem;
class UAnimMontage;
class AItem;
UCLASS()
class SHOOTER_API AShooterCharacter : public ACharacter
@ -88,6 +89,14 @@ protected:
UFUNCTION()
void AutoFireReset();
/** Line trace for items under the crosshairs */
bool TraceUnderCrosshairs(FHitResult& OutHitResult, FVector& OutHitLocation);
/* Trace for items if OverlappedItemCount > 0 */
void TraceForItems();
void SetItemPickupWidgetVisibility(AItem* Item, bool visibility);
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
@ -218,6 +227,12 @@ private:
/* Sets a timer between gunshots */
FTimerHandle AutoFireTimer;
/* True if we should trace every frame for items */
bool bShouldTraceForItems;
/* Number of overlapped AItems */
int8 OverlappedItemCount;
public:
/* Returns CameraBoom SubObject */
FORCEINLINE USpringArmComponent* GetCameraBoom() const { return CameraBoom; }
@ -229,4 +244,9 @@ public:
UFUNCTION(BlueprintCallable)
float GetCrosshairSpreadMultiplier() const;
FORCEINLINE int8 GetOverlappedItemCount() const { return OverlappedItemCount; }
/* Adds/Subtracts to/from OverlappedItemCount and updates bShouldTraceForItems */
void IncrementOverlappedItemCount(int8 Amount);
};