如需转载本文,请声明作者及出处。
// 屏幕外的3d位置,在屏幕上的指向
void screen_offset_indicate(WorldLocalX, WorldLocalY, WorldLocalZ)
{
APlayerController* Player = ...;
//指向图标的角度
float RotationAngleDegrees = 0.f;
//指向图标在屏幕上的位置
FVector2D *ScreenPosition = new FVector2D();
const FVector2D ViewportSize = FVector2D(GEngine->GameViewport->Viewport->GetSizeXY()) / UWidgetLayoutLibrary::GetViewportScale(Player);
const FVector2D ViewportCenter = FVector2D(ViewportSize.X / 2, ViewportSize.Y / 2);
ACharacter *PlayerCharacter = static_cast<ACharacter*>(Player->GetPawn());
if (!PlayerCharacter)
{
return;
}
FVector Worldlocal = FVector(WorldLocalX, WorldLocalY, WorldLocalZ);
FVector Forward = PlayerCharacter->GetActorForwardVector();
FVector Offset = (Worldlocal - PlayerCharacter->GetActorLocation()).GetSafeNormal();
float EdgePercent = 0.8f; // 可调可配,贴边的百分比
float DotProduct = FVector::DotProduct(Forward, Offset);
bool IsBehindCamera = (DotProduct < 0.0);
if (IsBehindCamera)
{
//当要指向的点跟到相机后时
//取巧的做法,将相机后的位置取反,得到屏幕位置后,再用屏幕宽度来减
FVector DiffVector = Worldlocal - PlayerCharacter->GetActorLocation();
FVector Inverted = DiffVector * -1.f;
FVector NewLocal = PlayerCharacter->GetActorLocation() + Inverted;
Player->ProjectWorldLocationToScreen(NewLocal, *ScreenPosition);
ScreenPosition->Y = ViewportSize.Y - ScreenPosition->Y;
ScreenPosition->X = ViewportSize.X - ScreenPosition->X;
}
Player->ProjectWorldLocationToScreen(Worldlocal, *ScreenPosition);
if (ScreenPosition->X >= 0.f && ScreenPosition->X <= ViewportSize.X && ScreenPosition->Y >= 0.f && ScreenPosition->Y <= ViewportSize.Y)
{
//ScreenPosition在屏幕内了
return;
}
*ScreenPosition -= ViewportCenter;
float AngleRadians = FMath::Atan2(ScreenPosition->Y, ScreenPosition->X);
AngleRadians -= FMath::DegreesToRadians(90.0f);
RotationAngleDegrees = FMath::RadiansToDegrees(AngleRadians) + 180.0f;
float Cos = cosf(AngleRadians);
float Sin = -sinf(AngleRadians);
ScreenPosition = new FVector2D(ViewportCenter.X + (Sin * 150.0f), ViewportCenter.Y + (Cos * 150.0f));
float m = Cos / Sin;
FVector2D ScreenBounds = ViewportCenter * EdgePercent;
if (Cos > 0.0)
{
ScreenPosition = new FVector2D(ScreenBounds.Y / m, ScreenBounds.Y);
}
else
{
ScreenPosition = new FVector2D(-ScreenBounds.Y / m, -ScreenBounds.Y);
}
if (ScreenPosition->X > ScreenBounds.X)
{
ScreenPosition = new FVector2D(ScreenBounds.X, ScreenBounds.X*m);
}
else if (ScreenPosition->X < -ScreenBounds.X)
{
ScreenPosition = new FVector2D(-ScreenBounds.X, -ScreenBounds.X*m);
}
*ScreenPosition += ViewportCenter;
}