Added GestureAction Ruler, added TableLineActor

This commit is contained in:
DuOtto
2026-07-29 00:07:47 +02:00
parent c9e46eeb41
commit 257f045515
19 changed files with 513 additions and 332 deletions
@@ -0,0 +1,69 @@
// 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);
}
@@ -0,0 +1,161 @@
// 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));
}