super-duper-spoon/Source/Shooter/Item.cpp

317 lines
9.5 KiB
C++

// Fill out your copyright notice in the Description page of Project Settings.
#include "Item.h"
#include "ShooterCharacter.h"
#include "Components/BoxComponent.h"
#include "Components/SphereComponent.h"
#include "Components/WidgetComponent.h"
#include "Camera/CameraComponent.h"
// Sets default values
AItem::AItem() :
ItemName(FString("Default")),
ItemCount(0),
ItemRarity(EItemRarity::EIR_Common),
ItemState(EItemState::EIS_Pickup),
// Item interp variables
ItemInterpStartLocation(FVector(0.f)),
CameraTargetLocation(FVector(0.f)),
bInterping(false),
ZCurveTime(0.7f),
ItemIntepX(0.f),
ItemIntepY(0.f),
InterpInitialYawOffset(0.f)
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
ItemMesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("ItemMesh"));
SetRootComponent(ItemMesh);
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
if (PickupWidget)
PickupWidget->SetVisibility(false);
// Set ActiveStars array based on item rarity
setActiveStars();
// Setup overlap for AreaSphere
AreaSphere->OnComponentBeginOverlap.AddDynamic(this, &AItem::OnSphereOverlap);
AreaSphere->OnComponentEndOverlap.AddDynamic(this, &AItem::OnSphereEndOverlap);
//Set Item properties based on ItemState
SetItemProperties(ItemState);
}
void AItem::setActiveStars()
{
// The 0 element isn't used
for (int32 i = 0; i <= 5; ++i)
{
ActiveStars.Add(false);
}
switch (ItemRarity)
{
case EItemRarity::EIR_Damaged:
ActiveStars[1] = true;
break;
case EItemRarity::EIR_Common:
ActiveStars[1] = true;
ActiveStars[2] = true;
break;
case EItemRarity::EIR_Uncommon:
ActiveStars[1] = true;
ActiveStars[2] = true;
ActiveStars[3] = true;
break;
case EItemRarity::EIR_Rare:
ActiveStars[1] = true;
ActiveStars[2] = true;
ActiveStars[3] = true;
ActiveStars[4] = true;
break;
case EItemRarity::EIR_Legendary:
ActiveStars[1] = true;
ActiveStars[2] = true;
ActiveStars[3] = true;
ActiveStars[4] = true;
ActiveStars[5] = true;
break;
}
}
// Called every frame
void AItem::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// Handle Item interping when in the EquipInterping state
ItemInterp(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);
}
}
}
void AItem::ItemInterp(float DeltaTime)
{
if (!bInterping) return;
if (Character && ItemZCurve)
{
// Elapsed time since we started ItemInterpTimer
const float ElapsedTime = GetWorldTimerManager().GetTimerElapsed(ItemInterpTimer);
// Get curve value corresponding to ElapsedTime
const float CurveValue = ItemZCurve->GetFloatValue(ElapsedTime);
// Get the item's initial location when the curve started
FVector ItemLocation = ItemInterpStartLocation;
// Get location in front of the camera
const FVector CameraInterpLocation{ Character->GetCameraInterpLocation() };
// Vector from Item to Camera Interp Location, X and Y are zeroed out
const FVector ItemToCamera{ FVector(0.f, 0.f, (CameraInterpLocation - ItemLocation).Z) };
// SCale factor to multiply with CurveValue
const float DeltaZ = ItemToCamera.Size();
const FVector CurrentLocation{ GetActorLocation() };
// Interpolated X Value
const float InterpXValue = FMath::FInterpTo(CurrentLocation.X,
CameraInterpLocation.X,
DeltaTime, 30.f);
// Interpolated Y Value
const float InterpYValue = FMath::FInterpTo(CurrentLocation.Y,
CameraInterpLocation.Y,
DeltaTime, 30.f);
// Set X and Y of ItemLocation to Interped values
ItemLocation.X = InterpXValue;
ItemLocation.Y = InterpYValue;
// Adding curve value to the Z component of the Initial Location (Scaled by DeltaZ)
ItemLocation.Z += CurveValue * DeltaZ;
SetActorLocation(ItemLocation, true,
nullptr, ETeleportType::TeleportPhysics);
// Camera rotation this frame
const FRotator CameraRotation{Character->GetFollowCamera()->GetComponentRotation()};
// Camera rotation plus initial Yaw Offset
const FRotator ItemRotation{0.f, CameraRotation.Yaw + InterpInitialYawOffset, 0.f};
SetActorRotation(ItemRotation, ETeleportType::TeleportPhysics);
if (ItemScaleCurve)
{
const float ScaleCurveValue = ItemScaleCurve->GetFloatValue(ElapsedTime);
SetActorScale3D(FVector(ScaleCurveValue, ScaleCurveValue, ScaleCurveValue));
}
}
}
void AItem::SetItemState(EItemState State)
{
ItemState = State;
SetItemProperties(State);
}
void AItem::SetItemProperties(EItemState State)
{
switch (State)
{
case EItemState::EIS_Pickup:
// Set Mesh properties
ItemMesh->SetSimulatePhysics(false);
ItemMesh->SetEnableGravity(false);
ItemMesh->SetVisibility(true);
ItemMesh->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);
ItemMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
// Set AreaSphere properties
AreaSphere->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Overlap);
AreaSphere->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
// Set CollisionBox properties
CollisionBox->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);
CollisionBox->SetCollisionResponseToChannel(ECollisionChannel::ECC_Visibility, ECollisionResponse::ECR_Block);
CollisionBox->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
break;
case EItemState::EIS_Equipped:
// Set Mesh properties
ItemMesh->SetSimulatePhysics(false);
ItemMesh->SetEnableGravity(false);
ItemMesh->SetVisibility(true);
ItemMesh->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);
ItemMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
// Set AreaSphere properties
AreaSphere->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);
AreaSphere->SetCollisionEnabled(ECollisionEnabled::NoCollision);
// Set CollisionBox properties
CollisionBox->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);
CollisionBox->SetCollisionEnabled(ECollisionEnabled::NoCollision);
break;
case EItemState::EIS_Falling:
// Set Mesh properties
ItemMesh->SetSimulatePhysics(true);
ItemMesh->SetEnableGravity(true);
ItemMesh->SetVisibility(true);
ItemMesh->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);
ItemMesh->SetCollisionResponseToChannel(ECollisionChannel::ECC_WorldStatic, ECollisionResponse::ECR_Block);
ItemMesh->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
// Set AreaSphere properties
AreaSphere->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);
AreaSphere->SetCollisionEnabled(ECollisionEnabled::NoCollision);
// Set CollisionBox properties
CollisionBox->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);
CollisionBox->SetCollisionEnabled(ECollisionEnabled::NoCollision);
break;
case EItemState::EIS_EquipInterping:
PickupWidget->SetVisibility(false);
// Set Mesh properties
ItemMesh->SetSimulatePhysics(false);
ItemMesh->SetEnableGravity(false);
ItemMesh->SetVisibility(true);
ItemMesh->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);
ItemMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
// Set AreaSphere properties
AreaSphere->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);
AreaSphere->SetCollisionEnabled(ECollisionEnabled::NoCollision);
// Set CollisionBox properties
CollisionBox->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);
CollisionBox->SetCollisionEnabled(ECollisionEnabled::NoCollision);
break;
}
}
void AItem::StartItemCurve(AShooterCharacter* Char)
{
// Store a handle to the Character
Character = Char;
// Store the initial locatino of the Item
ItemInterpStartLocation = GetActorLocation();
bInterping = true;
SetItemState(EItemState::EIS_EquipInterping);
GetWorldTimerManager().SetTimer(ItemInterpTimer, this,
&AItem::FinishInterping, ZCurveTime);
// Get initial Yaw of the Camera
const float CameraRotationYaw{
static_cast<float>(Character->GetFollowCamera()->GetComponentRotation().Yaw)
};
// Get initial Yaw of the Item
const float ItemRotationYaw{ static_cast<float>(GetActorRotation().Yaw) };
// Initial Yaw Offset between Camera and Item
InterpInitialYawOffset = ItemRotationYaw - CameraRotationYaw;
}
void AItem::FinishInterping()
{
bInterping = false;
if (Character)
{
Character->GetPickupItem(this);
}
// Set scale back to normal
SetActorScale3D(FVector(1.f));
}