parent
402ede1696
commit
ec9991e77c
|
@ -72,3 +72,6 @@ Plugins/*/Intermediate/*
|
|||
|
||||
# Cache files for the editor to use
|
||||
DerivedDataCache/*
|
||||
/Content/ModSci_Engineer/
|
||||
/Content/ModSci_EngiProps/
|
||||
/Content/ModSciInteriors/
|
||||
|
|
|
@ -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)
BIN
Content/_Game/HUD/PickupWidgetBP.uasset (Stored with Git LFS)
Binary file not shown.
BIN
Content/_Game/Maps/Factory.umap (Stored with Git LFS)
BIN
Content/_Game/Maps/Factory.umap (Stored with Git LFS)
Binary file not shown.
BIN
Content/_Game/Weapons/BaseWeapon/BaseWeaponBP.uasset (Stored with Git LFS)
BIN
Content/_Game/Weapons/BaseWeapon/BaseWeaponBP.uasset (Stored with Git LFS)
Binary file not shown.
|
@ -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,13 +19,27 @@ 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
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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; }
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
||||
// 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 };
|
||||
|
||||
if (GEngine && GEngine->GameViewport)
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue