// Copyright 2025 https://yuewu.dev/en All Rights Reserved. #pragma once #include "Kismet/BlueprintFunctionLibrary.h" #include "GMS_Vector.generated.h" UCLASS(Meta = (BlueprintThreadSafe)) class GENERICMOVEMENTSYSTEM_API UGMS_Vector : public UBlueprintFunctionLibrary { GENERATED_BODY() public: UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GMS|Vector Utility", Meta = (AutoCreateRefTerm = "Vector", ReturnDisplayName = "Vector")) static FVector ClampMagnitude01(const FVector& Vector); static FVector3f ClampMagnitude01(const FVector3f& Vector); UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GMS|Vector Utility", DisplayName = "Clamp Magnitude 01 2D", Meta = (AutoCreateRefTerm = "Vector", ReturnDisplayName = "Vector")) static FVector2D ClampMagnitude012D(const FVector2D& Vector); UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GMS|Vector Utility", Meta = (ReturnDisplayName = "Direction")) static FVector2D RadianToDirection(float Radian); UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GMS|Vector Utility", Meta = (ReturnDisplayName = "Direction")) static FVector RadianToDirectionXY(float Radian); UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GMS|Vector Utility", Meta = (ReturnDisplayName = "Direction")) static FVector2D AngleToDirection(float Angle); UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GMS|Vector Utility", Meta = (ReturnDisplayName = "Direction")) static FVector AngleToDirectionXY(float Angle); UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GMS|Vector Utility", Meta = (AutoCreateRefTerm = "Direction", ReturnDisplayName = "Angle")) static double DirectionToAngle(const FVector2D& Direction); UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GMS|Vector Utility", Meta = (AutoCreateRefTerm = "Direction", ReturnDisplayName = "Angle")) static double DirectionToAngleXY(const FVector& Direction); UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GMS|Vector Utility", Meta = (AutoCreateRefTerm = "Vector", ReturnDisplayName = "Vector")) static FVector PerpendicularClockwiseXY(const FVector& Vector); UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GMS|Vector Utility", Meta = (AutoCreateRefTerm = "Vector", ReturnDisplayName = "Vector")) static FVector PerpendicularCounterClockwiseXY(const FVector& Vector); UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GMS|Vector Utility", DisplayName = "Angle Between (Skip Normalization)", Meta = (AutoCreateRefTerm = "From, To", ReturnDisplayName = "Angle")) static double AngleBetweenSkipNormalization(const FVector& From, const FVector& To); UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GMS|Vector Utility", Meta = (AutoCreateRefTerm = "From, To", ReturnDisplayName = "Angle")) static float AngleBetweenSignedXY(const FVector3f& From, const FVector3f& To); UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GMS|Vector Utility", DisplayName = "Slerp (Skip Normalization)", Meta = (AutoCreateRefTerm = "From, To", ReturnDisplayName = "Direction")) static FVector SlerpSkipNormalization(const FVector& From, const FVector& To, float Ratio); }; inline FVector UGMS_Vector::ClampMagnitude01(const FVector& Vector) { const auto MagnitudeSquared{Vector.SizeSquared()}; if (MagnitudeSquared <= 1.0f) { return Vector; } const auto Scale{FMath::InvSqrt(MagnitudeSquared)}; return {Vector.X * Scale, Vector.Y * Scale, Vector.Z * Scale}; } inline FVector3f UGMS_Vector::ClampMagnitude01(const FVector3f& Vector) { const auto MagnitudeSquared{Vector.SizeSquared()}; if (MagnitudeSquared <= 1.0f) { return Vector; } const auto Scale{FMath::InvSqrt(MagnitudeSquared)}; return {Vector.X * Scale, Vector.Y * Scale, Vector.Z * Scale}; } inline FVector2D UGMS_Vector::ClampMagnitude012D(const FVector2D& Vector) { const auto MagnitudeSquared{Vector.SizeSquared()}; if (MagnitudeSquared <= 1.0f) { return Vector; } const auto Scale{FMath::InvSqrt(MagnitudeSquared)}; return {Vector.X * Scale, Vector.Y * Scale}; } inline FVector2D UGMS_Vector::RadianToDirection(const float Radian) { float Sin, Cos; FMath::SinCos(&Sin, &Cos, Radian); return {Cos, Sin}; } inline FVector UGMS_Vector::RadianToDirectionXY(const float Radian) { float Sin, Cos; FMath::SinCos(&Sin, &Cos, Radian); return {Cos, Sin, 0.0f}; } inline FVector2D UGMS_Vector::AngleToDirection(const float Angle) { return RadianToDirection(FMath::DegreesToRadians(Angle)); } inline FVector UGMS_Vector::AngleToDirectionXY(const float Angle) { return RadianToDirectionXY(FMath::DegreesToRadians(Angle)); } inline double UGMS_Vector::DirectionToAngle(const FVector2D& Direction) { return FMath::RadiansToDegrees(FMath::Atan2(Direction.Y, Direction.X)); } inline double UGMS_Vector::DirectionToAngleXY(const FVector& Direction) { return FMath::RadiansToDegrees(FMath::Atan2(Direction.Y, Direction.X)); } inline FVector UGMS_Vector::PerpendicularClockwiseXY(const FVector& Vector) { return {Vector.Y, -Vector.X, Vector.Z}; } inline FVector UGMS_Vector::PerpendicularCounterClockwiseXY(const FVector& Vector) { return {-Vector.Y, Vector.X, Vector.Z}; } inline double UGMS_Vector::AngleBetweenSkipNormalization(const FVector& From, const FVector& To) { return FMath::RadiansToDegrees(FMath::Acos(From | To)); } inline float UGMS_Vector::AngleBetweenSignedXY(const FVector3f& From, const FVector3f& To) { FVector2f FromXY{From}; FromXY.Normalize(); FVector2f ToXY{To}; ToXY.Normalize(); // return FMath::RadiansToDegrees(FMath::Atan2(FromXY ^ ToXY, FromXY | ToXY)); return FMath::RadiansToDegrees(FMath::Acos(FromXY | ToXY)) * FMath::Sign(FromXY ^ ToXY); }