Added LineIcon
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
@@ -33,17 +33,35 @@ void AGestureAction_Ruler::InitAction_Implementation(AHandActor* Hand, const FGe
|
|||||||
}
|
}
|
||||||
RulerPoints.Add(FVector::ZeroVector);
|
RulerPoints.Add(FVector::ZeroVector);
|
||||||
RulerPoints.Add(FVector::ZeroVector);
|
RulerPoints.Add(FVector::ZeroVector);
|
||||||
|
|
||||||
|
if (LabelIconClass)
|
||||||
|
{
|
||||||
|
LabelIcon = GetWorld()->SpawnActor<ATableIconLabelActor>(LabelIconClass, StartPoint, FRotator::ZeroRotator, SpawnParams);
|
||||||
|
|
||||||
|
if (LabelIcon)
|
||||||
|
{
|
||||||
|
LabelIcon->OwningAction = this;
|
||||||
|
LabelIcon->bPersistOnActionEnd = true;
|
||||||
|
LabelIcon->UpdateLabel(StartPoint, 0.f);
|
||||||
|
Icons.Add(LabelIcon);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AGestureAction_Ruler::UpdateAction_Implementation()
|
void AGestureAction_Ruler::UpdateAction_Implementation()
|
||||||
{
|
{
|
||||||
if (!HandA || !IsValid(LineIcon)) return;
|
if (!HandA || !IsValid(LineIcon) || !IsValid(LabelIcon)) return;
|
||||||
const FVector Current = HandA->Points[8];
|
const FVector Current = HandA->Points[8];
|
||||||
|
|
||||||
//if (FVector::DistSquared(Current, RulerPoints[RulerPoints.Num() - 1]) < FMath::Square(UEUnitsPerUnit)) return;
|
//if (FVector::DistSquared(Current, RulerPoints[RulerPoints.Num() - 1]) < FMath::Square(UEUnitsPerUnit)) return;
|
||||||
RulerPoints[RulerPoints.Num() - 1] = Current - StartPoint;
|
RulerPoints.Last() = Current - StartPoint;
|
||||||
RulerPoints[RulerPoints.Num() - 1].Z = 0;
|
RulerPoints.Last().Z = 0;
|
||||||
LineIcon->SetPoints(RulerPoints);
|
LineIcon->SetPoints(RulerPoints);
|
||||||
|
|
||||||
|
// RulerPoints are local to the line actor, so convert back to world
|
||||||
|
FVector LabelPosition = StartPoint + (RulerPoints.Last() * 0.5f);
|
||||||
|
LabelPosition.Z = 10;
|
||||||
|
LabelIcon->UpdateLabel(LabelPosition, GetSnappedUnits(GetTotalLength()));
|
||||||
}
|
}
|
||||||
|
|
||||||
float AGestureAction_Ruler::GetSnappedUnits(float RawDistance) const
|
float AGestureAction_Ruler::GetSnappedUnits(float RawDistance) const
|
||||||
|
|||||||
@@ -98,17 +98,14 @@ void ATableIconLineActor::BuildLineMesh()
|
|||||||
MeshComponent->CreateMeshSection(0, Vertices, Triangles, Normals, UVs, Colors, Tangents, false);
|
MeshComponent->CreateMeshSection(0, Vertices, Triangles, Normals, UVs, Colors, Tangents, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ATableIconWidgetActor::ATableIconWidgetActor()
|
ATableIconWidgetActor::ATableIconWidgetActor()
|
||||||
{
|
{
|
||||||
USceneComponent* Root = CreateDefaultSubobject<USceneComponent>(TEXT("Root"));
|
USceneComponent* Root = CreateDefaultSubobject<USceneComponent>(TEXT("Root"));
|
||||||
SetRootComponent(Root);
|
SetRootComponent(Root);
|
||||||
|
|
||||||
PrimaryActorTick.bCanEverTick = true;
|
PrimaryActorTick.bCanEverTick = false;
|
||||||
|
|
||||||
WidgetComponent = CreateDefaultSubobject<UWidgetComponent>(TEXT("WidgetComponent"));
|
WidgetComponent = CreateDefaultSubobject<UWidgetComponent>(TEXT("WidgetComponent"));
|
||||||
WidgetComponent->SetupAttachment(RootComponent);
|
WidgetComponent->SetupAttachment(RootComponent);
|
||||||
@@ -120,22 +117,8 @@ ATableIconWidgetActor::ATableIconWidgetActor()
|
|||||||
WidgetInteraction->SetupAttachment(RootComponent);
|
WidgetInteraction->SetupAttachment(RootComponent);
|
||||||
WidgetInteraction->InteractionSource = EWidgetInteractionSource::Custom;
|
WidgetInteraction->InteractionSource = EWidgetInteractionSource::Custom;
|
||||||
WidgetInteraction->InteractionDistance = 10.f;
|
WidgetInteraction->InteractionDistance = 10.f;
|
||||||
}
|
|
||||||
|
|
||||||
void ATableIconWidgetActor::Tick(float DeltaTime)
|
SetWidgetClass(LabelWidgetClass);
|
||||||
{
|
|
||||||
Super::Tick(DeltaTime);
|
|
||||||
|
|
||||||
APlayerCameraManager* CamManager = UGameplayStatics::GetPlayerCameraManager(this, 0);
|
|
||||||
if (!CamManager) return;
|
|
||||||
|
|
||||||
FVector CamLocation = CamManager->GetCameraLocation();
|
|
||||||
FVector ToCamera = (CamLocation - GetActorLocation()).GetSafeNormal();
|
|
||||||
|
|
||||||
// Only rotate on yaw � keeps widget flat relative to table
|
|
||||||
ToCamera.Z = 0.f;
|
|
||||||
if (!ToCamera.IsNearlyZero())
|
|
||||||
SetActorRotation(ToCamera.ToOrientationRotator());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ATableIconWidgetActor::SetWidgetClass(TSubclassOf<UUserWidget> InWidgetClass)
|
void ATableIconWidgetActor::SetWidgetClass(TSubclassOf<UUserWidget> InWidgetClass)
|
||||||
@@ -150,10 +133,10 @@ UUserWidget* ATableIconWidgetActor::GetWidget() const
|
|||||||
return WidgetComponent->GetUserWidgetObject();
|
return WidgetComponent->GetUserWidgetObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void ATableIconLabelActor::UpdateLabel(const FVector& WorldLocation, float Value)
|
||||||
void ATableIconLabelActor::SetDistance(float RealWorldUnits, const FString& UnitSuffix)
|
|
||||||
{
|
{
|
||||||
int32 Snapped = FMath::RoundToInt(RealWorldUnits);
|
SetActorLocation(WorldLocation);
|
||||||
SetLabelText(FString::Printf(TEXT("%d%s"), Snapped, *UnitSuffix));
|
SetLabelText(FString::Printf(TEXT("%.1f%s"), Value, *UnitSuffix));
|
||||||
}
|
}
|
||||||
@@ -35,7 +35,7 @@ public:
|
|||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Ruler") TSubclassOf<ATableIconLabelActor> LabelIconClass;
|
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Ruler") TSubclassOf<ATableIconLabelActor> LabelIconClass;
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Ruler") FString UnitSuffix = TEXT("\"");
|
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Ruler") FString UnitSuffix = TEXT("\"");
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Ruler") TArray<FVector> RulerPoints;
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Ruler") TArray<FVector> RulerPoints;
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Line") float DesiredHeight = -650.f;
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Ruler") float DesiredHeight = -650.f;
|
||||||
|
|
||||||
UFUNCTION(BlueprintCallable, BlueprintPure) float GetTotalLength() const;
|
UFUNCTION(BlueprintCallable, BlueprintPure) float GetTotalLength() const;
|
||||||
UFUNCTION(BlueprintCallable) void AddRulerPoint();
|
UFUNCTION(BlueprintCallable) void AddRulerPoint();
|
||||||
|
|||||||
@@ -11,15 +11,6 @@
|
|||||||
|
|
||||||
class UWidgetComponent;
|
class UWidgetComponent;
|
||||||
class UWidgetInteractionComponent;
|
class UWidgetInteractionComponent;
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
UCLASS()
|
|
||||||
class TABLE_API AMyTableIconActors : public ATableIconActor
|
|
||||||
{
|
|
||||||
GENERATED_BODY()
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
UCLASS(Blueprintable)
|
UCLASS(Blueprintable)
|
||||||
@@ -46,6 +37,7 @@ private:
|
|||||||
void BuildLineMesh();
|
void BuildLineMesh();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
UCLASS(Blueprintable)
|
UCLASS(Blueprintable)
|
||||||
@@ -58,20 +50,24 @@ public:
|
|||||||
|
|
||||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly) UWidgetComponent* WidgetComponent;
|
UPROPERTY(VisibleAnywhere, BlueprintReadOnly) UWidgetComponent* WidgetComponent;
|
||||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly) UWidgetInteractionComponent* WidgetInteraction;
|
UPROPERTY(VisibleAnywhere, BlueprintReadOnly) UWidgetInteractionComponent* WidgetInteraction;
|
||||||
|
UPROPERTY(VisibleAnywhere, BlueprintReadOnly) TSubclassOf<UUserWidget> LabelWidgetClass;
|
||||||
|
|
||||||
UFUNCTION(BlueprintCallable) void SetWidgetClass(TSubclassOf<UUserWidget> InWidgetClass);
|
UFUNCTION(BlueprintCallable) void SetWidgetClass(TSubclassOf<UUserWidget> InWidgetClass);
|
||||||
UFUNCTION(BlueprintCallable, BlueprintPure) UUserWidget* GetWidget() const;
|
UFUNCTION(BlueprintCallable, BlueprintPure) UUserWidget* GetWidget() const;
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void Tick(float DeltaTime) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
UCLASS(Blueprintable)
|
UCLASS(Blueprintable)
|
||||||
class TABLE_API ATableIconLabelActor : public ATableIconWidgetActor
|
class TABLE_API ATableIconLabelActor : public ATableIconWidgetActor
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Label") FString UnitSuffix = TEXT("\"");
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintImplementableEvent, BlueprintCallable, Category = "Label") void SetLabelText(const FString& Text);
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Label") void UpdateLabel(const FVector& WorldLocation, float Value);
|
||||||
|
|
||||||
UFUNCTION(BlueprintImplementableEvent, BlueprintCallable) void SetLabelText(const FString& Text);
|
|
||||||
UFUNCTION(BlueprintCallable) void SetDistance(float RealWorldUnits, const FString& UnitSuffix = TEXT("\""));
|
|
||||||
};
|
};
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
// Fill out your copyright notice in the Description page of Project Settings.
|
|
||||||
|
|
||||||
|
|
||||||
#include "MyGestureActions.h"
|
|
||||||
#include "HandActor.h"
|
|
||||||
#include "TableIconActor.h"
|
|
||||||
#include "MyTableIconActors.h"
|
|
||||||
|
|
||||||
|
|
||||||
void AGestureAction_Ruler::InitAction_Implementation(AHandActor* Hand, const FGestureBinding& NewBinding, float NewUEUnitsPerUnit, float TableHeight)
|
|
||||||
{
|
|
||||||
Super::InitAction_Implementation(Hand, NewBinding, NewUEUnitsPerUnit, TableHeight);
|
|
||||||
DesiredHeight = -500;
|
|
||||||
StartPoint = HandA->Points[8];
|
|
||||||
StartPoint.Z = DesiredHeight;
|
|
||||||
|
|
||||||
FActorSpawnParameters SpawnParams;
|
|
||||||
SpawnParams.Owner = this;
|
|
||||||
SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
|
|
||||||
|
|
||||||
if (LineIconClass)
|
|
||||||
{
|
|
||||||
|
|
||||||
LineIcon = GetWorld()->SpawnActor<ATableIconLineActor>(LineIconClass, StartPoint, FRotator::ZeroRotator, SpawnParams);
|
|
||||||
|
|
||||||
if (LineIcon)
|
|
||||||
{
|
|
||||||
LineIcon->OwningAction = this;
|
|
||||||
LineIcon->bPersistOnActionEnd = true;
|
|
||||||
LineIcon->LineThickness = 50;
|
|
||||||
Icons.Add(LineIcon);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RulerPoints.Add(FVector(0, 0, 0));
|
|
||||||
RulerPoints.Add(FVector(0, 0, DesiredHeight));
|
|
||||||
}
|
|
||||||
|
|
||||||
void AGestureAction_Ruler::UpdateAction_Implementation()
|
|
||||||
{
|
|
||||||
if (!HandA || !IsValid(LineIcon)) return;
|
|
||||||
const FVector Current = HandA->Points[8];
|
|
||||||
|
|
||||||
//if (FVector::DistSquared(Current, RulerPoints[RulerPoints.Num() - 1]) < FMath::Square(UEUnitsPerUnit)) return;
|
|
||||||
//RulerPoints[RulerPoints.Num() - 1] = Current;
|
|
||||||
RulerPoints[RulerPoints.Num() - 1] = Current - StartPoint;
|
|
||||||
RulerPoints[RulerPoints.Num() - 1].Z = 0;
|
|
||||||
LineIcon->SetPoints(RulerPoints);
|
|
||||||
}
|
|
||||||
|
|
||||||
float AGestureAction_Ruler::GetSnappedUnits(float RawDistance) const
|
|
||||||
{
|
|
||||||
if (UEUnitsPerUnit <= 0.f) return 0.f;
|
|
||||||
return FMath::RoundToFloat(RawDistance / UEUnitsPerUnit);
|
|
||||||
}
|
|
||||||
|
|
||||||
float AGestureAction_Ruler::GetTotalLength() const
|
|
||||||
{
|
|
||||||
float Total = 0.f;
|
|
||||||
for (int32 i = 0; i < RulerPoints.Num() - 1; i++)
|
|
||||||
Total += FVector::Dist(RulerPoints[i], RulerPoints[i + 1]);
|
|
||||||
return Total;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AGestureAction_Ruler::AddRulerPoint()
|
|
||||||
{
|
|
||||||
FVector Current = HandA->Points[8];
|
|
||||||
//Current.Z = DesiredHeight;
|
|
||||||
RulerPoints.Add(Current - StartPoint);
|
|
||||||
}
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
// Fill out your copyright notice in the Description page of Project Settings.
|
|
||||||
|
|
||||||
|
|
||||||
#include "MyTableIconActors.h"
|
|
||||||
#include "KismetProceduralMeshLibrary.h"
|
|
||||||
#include "TableIconActor.h"
|
|
||||||
|
|
||||||
#include "Kismet/GameplayStatics.h"
|
|
||||||
#include "Camera/CameraActor.h"
|
|
||||||
|
|
||||||
ATableIconLineActor::ATableIconLineActor()
|
|
||||||
{
|
|
||||||
PrimaryActorTick.bCanEverTick = false; // purely driven by SetPoints
|
|
||||||
|
|
||||||
USceneComponent* Root = CreateDefaultSubobject<USceneComponent>(TEXT("Root"));
|
|
||||||
SetRootComponent(Root);
|
|
||||||
|
|
||||||
MeshComponent = CreateDefaultSubobject<UProceduralMeshComponent>(TEXT("LineMesh"));
|
|
||||||
MeshComponent->SetupAttachment(RootComponent);
|
|
||||||
MeshComponent->SetCastShadow(false);
|
|
||||||
MeshComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ATableIconLineActor::SetPoints(const TArray<FVector>& NewPoints)
|
|
||||||
{
|
|
||||||
const FTransform& ActorTransform = GetActorTransform();
|
|
||||||
|
|
||||||
Points.Reset(NewPoints.Num());
|
|
||||||
|
|
||||||
Points = NewPoints;
|
|
||||||
|
|
||||||
MeshComponent->ClearMeshSection(0);
|
|
||||||
|
|
||||||
BuildLineMesh();
|
|
||||||
|
|
||||||
if (LineMaterial) MeshComponent->SetMaterial(0, LineMaterial);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void ATableIconLineActor::BuildLineMesh()
|
|
||||||
{
|
|
||||||
TArray<FVector> Vertices;
|
|
||||||
TArray<int32> Triangles;
|
|
||||||
TArray<FVector> Normals;
|
|
||||||
TArray<FVector2D> UVs;
|
|
||||||
TArray<FColor> Colors;
|
|
||||||
TArray<FProcMeshTangent> Tangents;
|
|
||||||
|
|
||||||
FVector Direction = FVector::ZeroVector;
|
|
||||||
const float HalfLineThickness = LineThickness * 0.5f;
|
|
||||||
|
|
||||||
for (int32 i = 0; i < Points.Num() - 1; i++) {
|
|
||||||
const FVector& PointA = Points[i];
|
|
||||||
const FVector& PointB = Points[i + 1];
|
|
||||||
|
|
||||||
Direction = (PointB - PointA).GetSafeNormal();
|
|
||||||
|
|
||||||
const FVector Right = FVector::CrossProduct(FVector::UpVector, Direction).GetSafeNormal();
|
|
||||||
|
|
||||||
const FVector Offset = Right * (LineThickness * 0.5f);
|
|
||||||
|
|
||||||
int32 Base = Vertices.Num();
|
|
||||||
|
|
||||||
Vertices.Add(PointA - Offset);
|
|
||||||
Vertices.Add(PointA + Offset);
|
|
||||||
Vertices.Add(PointB + Offset);
|
|
||||||
Vertices.Add(PointB - Offset);
|
|
||||||
|
|
||||||
Triangles.Add(Base + 0);
|
|
||||||
Triangles.Add(Base + 1);
|
|
||||||
Triangles.Add(Base + 2);
|
|
||||||
|
|
||||||
Triangles.Add(Base + 0);
|
|
||||||
Triangles.Add(Base + 2);
|
|
||||||
Triangles.Add(Base + 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
for (int i = 0; i < Vertices.Num(); i++)
|
|
||||||
{
|
|
||||||
Normals.Add(FVector::UpVector);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < Vertices.Num(); i++)
|
|
||||||
{
|
|
||||||
UVs.Add(FVector2D::ZeroVector);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < Vertices.Num(); i++)
|
|
||||||
{
|
|
||||||
Colors.Add(FColor::Red);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < Vertices.Num(); i++)
|
|
||||||
{
|
|
||||||
Tangents.Add(FProcMeshTangent(Direction, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
MeshComponent->CreateMeshSection(0, Vertices, Triangles, Normals, UVs, Colors, Tangents, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ATableIconWidgetActor::ATableIconWidgetActor()
|
|
||||||
{
|
|
||||||
USceneComponent* Root = CreateDefaultSubobject<USceneComponent>(TEXT("Root"));
|
|
||||||
SetRootComponent(Root);
|
|
||||||
|
|
||||||
PrimaryActorTick.bCanEverTick = true;
|
|
||||||
|
|
||||||
WidgetComponent = CreateDefaultSubobject<UWidgetComponent>(TEXT("WidgetComponent"));
|
|
||||||
WidgetComponent->SetupAttachment(RootComponent);
|
|
||||||
WidgetComponent->SetDrawAtDesiredSize(true);
|
|
||||||
WidgetComponent->SetWidgetSpace(EWidgetSpace::World);
|
|
||||||
WidgetComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision);
|
|
||||||
|
|
||||||
WidgetInteraction = CreateDefaultSubobject<UWidgetInteractionComponent>(TEXT("WidgetInteraction"));
|
|
||||||
WidgetInteraction->SetupAttachment(RootComponent);
|
|
||||||
WidgetInteraction->InteractionSource = EWidgetInteractionSource::Custom;
|
|
||||||
WidgetInteraction->InteractionDistance = 10.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ATableIconWidgetActor::Tick(float DeltaTime)
|
|
||||||
{
|
|
||||||
Super::Tick(DeltaTime);
|
|
||||||
|
|
||||||
APlayerCameraManager* CamManager = UGameplayStatics::GetPlayerCameraManager(this, 0);
|
|
||||||
if (!CamManager) return;
|
|
||||||
|
|
||||||
FVector CamLocation = CamManager->GetCameraLocation();
|
|
||||||
FVector ToCamera = (CamLocation - GetActorLocation()).GetSafeNormal();
|
|
||||||
|
|
||||||
// Only rotate on yaw � keeps widget flat relative to table
|
|
||||||
ToCamera.Z = 0.f;
|
|
||||||
if (!ToCamera.IsNearlyZero())
|
|
||||||
SetActorRotation(ToCamera.ToOrientationRotator());
|
|
||||||
}
|
|
||||||
|
|
||||||
void ATableIconWidgetActor::SetWidgetClass(TSubclassOf<UUserWidget> InWidgetClass)
|
|
||||||
{
|
|
||||||
if (!InWidgetClass) return;
|
|
||||||
WidgetComponent->SetWidgetClass(InWidgetClass);
|
|
||||||
WidgetComponent->InitWidget();
|
|
||||||
}
|
|
||||||
|
|
||||||
UUserWidget* ATableIconWidgetActor::GetWidget() const
|
|
||||||
{
|
|
||||||
return WidgetComponent->GetUserWidgetObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void ATableIconLabelActor::SetDistance(float RealWorldUnits, const FString& UnitSuffix)
|
|
||||||
{
|
|
||||||
int32 Snapped = FMath::RoundToInt(RealWorldUnits);
|
|
||||||
SetLabelText(FString::Printf(TEXT("%d%s"), Snapped, *UnitSuffix));
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user