diff --git a/.gitignore b/.gitignore index 6582eaf9..fdcb1cf0 100644 --- a/.gitignore +++ b/.gitignore @@ -72,3 +72,6 @@ Plugins/*/Intermediate/* # Cache files for the editor to use DerivedDataCache/* +/Content/ModSci_Engineer/ +/Content/ModSci_EngiProps/ +/Content/ModSciInteriors/ diff --git a/Config/DefaultEngine.ini b/Config/DefaultEngine.ini index ef1a9d20..17dd0c65 100644 --- a/Config/DefaultEngine.ini +++ b/Config/DefaultEngine.ini @@ -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] diff --git a/Content/_Game/HUD/PickupWidgetBP.uasset b/Content/_Game/HUD/PickupWidgetBP.uasset index 5aed8fa4..1c44b88e 100644 --- a/Content/_Game/HUD/PickupWidgetBP.uasset +++ b/Content/_Game/HUD/PickupWidgetBP.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ef23705bd18109c0b1637603ac9a4af397fd29ab51405cc2d6a82fe9a12fa0e4 -size 48595 +oid sha256:6a1e25638c4587560ae459e3e3a86d5492e42c3602223284bb125a93656609fc +size 77290 diff --git a/Content/_Game/Maps/Factory.umap b/Content/_Game/Maps/Factory.umap index 215ff430..4f2c688a 100644 --- a/Content/_Game/Maps/Factory.umap +++ b/Content/_Game/Maps/Factory.umap @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:da360948f3db284863cb3c990008463db63724199338e632169b75ed28a090c1 -size 27356876 +oid sha256:eccc20e8186b19b3a1b498e57604ee569152204ebaa7584234b1f56d86ee7c7c +size 27357043 diff --git a/Content/_Game/Weapons/BaseWeapon/BaseWeaponBP.uasset b/Content/_Game/Weapons/BaseWeapon/BaseWeaponBP.uasset index 62390e7d..e441778a 100644 --- a/Content/_Game/Weapons/BaseWeapon/BaseWeaponBP.uasset +++ b/Content/_Game/Weapons/BaseWeapon/BaseWeaponBP.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4643fcf61ee7c5d9b8aa8dfa530579ba602ecc2f88f51f3d318f8875a796ed7b -size 27664 +oid sha256:e0975bf5f85836db4e06c06a75bf0b4d32e43564c0beb9d5492af9e525bf05dc +size 29349 diff --git a/Source/Shooter/Item.cpp b/Source/Shooter/Item.cpp index bc20ab40..e1c9cbde 100644 --- a/Source/Shooter/Item.cpp +++ b/Source/Shooter/Item.cpp @@ -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(TEXT("CollisionBox")); CollisionBox->SetupAttachment(ItemMesh); + CollisionBox->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore); + CollisionBox->SetCollisionResponseToChannel(ECollisionChannel::ECC_Visibility, ECollisionResponse::ECR_Block); + + PickupWidget = CreateDefaultSubobject(TEXT("PickupWidget")); + PickupWidget->SetupAttachment(GetRootComponent()); + + AreaSphere = CreateDefaultSubobject(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(OtherActor); + + if (ShooterCharacter) + { + ShooterCharacter->IncrementOverlappedItemCount(1); + } + } +} + +void AItem::OnSphereEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, + UPrimitiveComponent* OtherComp, int32 OtherBodyIndex) +{ + if (OtherActor) + { + AShooterCharacter* ShooterCharacter = Cast(OtherActor); + + if (ShooterCharacter) + { + ShooterCharacter->IncrementOverlappedItemCount(-1); + } + } +} + diff --git a/Source/Shooter/Item.h b/Source/Shooter/Item.h index bd361597..97bb5155 100644 --- a/Source/Shooter/Item.h +++ b/Source/Shooter/Item.h @@ -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; } }; diff --git a/Source/Shooter/ShooterCharacter.cpp b/Source/Shooter/ShooterCharacter.cpp index 35d2fc04..21d98dc1 100644 --- a/Source/Shooter/ShooterCharacter.cpp +++ b/Source/Shooter/ShooterCharacter.cpp @@ -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(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; + } +} + diff --git a/Source/Shooter/ShooterCharacter.h b/Source/Shooter/ShooterCharacter.h index d0051bff..9c98997a 100644 --- a/Source/Shooter/ShooterCharacter.h +++ b/Source/Shooter/ShooterCharacter.h @@ -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); };