100 lines
3.2 KiB
C++
100 lines
3.2 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "LyraReticleWidgetBase.h"
|
|
|
|
#include "Camera/PlayerCameraManager.h"
|
|
#include "GameFramework/PlayerController.h"
|
|
#include "Inventory/LyraInventoryItemInstance.h"
|
|
#include "Math/Rotator.h"
|
|
#include "Math/UnrealMathSSE.h"
|
|
#include "Math/Vector.h"
|
|
#include "Math/Vector2D.h"
|
|
#include "Templates/Casts.h"
|
|
#include "Weapons/LyraRangedWeaponInstance.h"
|
|
#include "Weapons/LyraWeaponInstance.h"
|
|
|
|
ULyraReticleWidgetBase::ULyraReticleWidgetBase(const FObjectInitializer& ObjectInitializer)
|
|
: Super(ObjectInitializer)
|
|
{
|
|
}
|
|
|
|
void ULyraReticleWidgetBase::InitializeFromWeapon(ULyraWeaponInstance* InWeapon)
|
|
{
|
|
WeaponInstance = InWeapon;
|
|
InventoryInstance = nullptr;
|
|
if (WeaponInstance)
|
|
{
|
|
InventoryInstance = Cast<ULyraInventoryItemInstance>(WeaponInstance->GetInstigator());
|
|
}
|
|
OnWeaponInitialized();
|
|
}
|
|
|
|
|
|
float ULyraReticleWidgetBase::ComputeSpreadAngle() const
|
|
{
|
|
if (const ULyraRangedWeaponInstance* RangedWeapon = Cast<const ULyraRangedWeaponInstance>(WeaponInstance))
|
|
{
|
|
const float BaseSpreadAngle = RangedWeapon->GetCalculatedSpreadAngle();
|
|
const float SpreadAngleMultiplier = RangedWeapon->GetCalculatedSpreadAngleMultiplier();
|
|
const float ActualSpreadAngle = BaseSpreadAngle * SpreadAngleMultiplier;
|
|
|
|
return ActualSpreadAngle;
|
|
}
|
|
else
|
|
{
|
|
return 0.0f;
|
|
}
|
|
}
|
|
|
|
bool ULyraReticleWidgetBase::HasFirstShotAccuracy() const
|
|
{
|
|
if (const ULyraRangedWeaponInstance* RangedWeapon = Cast<const ULyraRangedWeaponInstance>(WeaponInstance))
|
|
{
|
|
return RangedWeapon->HasFirstShotAccuracy();
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
float ULyraReticleWidgetBase::ComputeMaxScreenspaceSpreadRadius() const
|
|
{
|
|
const float LongShotDistance = 10000.f;
|
|
|
|
APlayerController* PC = GetOwningPlayer();
|
|
if (PC && PC->PlayerCameraManager)
|
|
{
|
|
// A weapon's spread can be thought of as a cone shape. To find the screenspace spread for reticle visualization,
|
|
// we create a line on the edge of the cone at a long distance. The end of that point is on the edge of the cone's circle.
|
|
// We then project it back onto the screen. Its distance from screen center is the spread radius.
|
|
|
|
// This isn't perfect, due to there being some distance between the camera location and the gun muzzle.
|
|
|
|
const float SpreadRadiusRads = FMath::DegreesToRadians(ComputeSpreadAngle() * 0.5f);
|
|
const float SpreadRadiusAtDistance = FMath::Tan(SpreadRadiusRads) * LongShotDistance;
|
|
|
|
FVector CamPos;
|
|
FRotator CamOrient;
|
|
PC->PlayerCameraManager->GetCameraViewPoint(CamPos, CamOrient);
|
|
|
|
FVector CamForwDir = CamOrient.RotateVector(FVector::ForwardVector);
|
|
FVector CamUpDir = CamOrient.RotateVector(FVector::UpVector);
|
|
|
|
FVector OffsetTargetAtDistance = CamPos + (CamForwDir * LongShotDistance) + (CamUpDir * SpreadRadiusAtDistance);
|
|
|
|
FVector2D OffsetTargetInScreenspace;
|
|
|
|
if (PC->ProjectWorldLocationToScreen(OffsetTargetAtDistance, OffsetTargetInScreenspace, true))
|
|
{
|
|
int32 ViewportSizeX(0), ViewportSizeY(0);
|
|
PC->GetViewportSize(ViewportSizeX, ViewportSizeY);
|
|
|
|
const FVector2D ScreenSpaceCenter(FVector::FReal(ViewportSizeX) * 0.5f, FVector::FReal(ViewportSizeY) * 0.5f);
|
|
|
|
return (OffsetTargetInScreenspace - ScreenSpaceCenter).Length();
|
|
}
|
|
}
|
|
|
|
return 0.0f;
|
|
} |