diff --git a/Content/Luprex/Widgets/lxCrosshairWidget.uasset b/Content/Luprex/Widgets/lxCrosshairWidget.uasset index cd8af778..cc0ad4ce 100644 --- a/Content/Luprex/Widgets/lxCrosshairWidget.uasset +++ b/Content/Luprex/Widgets/lxCrosshairWidget.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6c131585704a5ec24cc11578d548d78e7229c2751f601f717decf012ac75eae0 -size 104498 +oid sha256:e0971df568f92793c9b3efa48ff9a74d8ece561811f692b167a16162e81700f9 +size 56644 diff --git a/Content/Luprex/lxGameMode.uasset b/Content/Luprex/lxGameMode.uasset index ce99ec02..cff5a124 100644 --- a/Content/Luprex/lxGameMode.uasset +++ b/Content/Luprex/lxGameMode.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:51681b12f32255ae3c4f6ab2d896e141158904c8d65ad46b7b3a935d0cef5247 -size 125604 +oid sha256:fc18fb741f71504c6cc8da211e4a7dffe9a07b03d816cf1cd04c68a6b84893f4 +size 117713 diff --git a/Content/Luprex/lxUtilityMacroLibrary.uasset b/Content/Luprex/lxUtilityMacroLibrary.uasset index 6eab6a2a..c110ed0f 100644 --- a/Content/Luprex/lxUtilityMacroLibrary.uasset +++ b/Content/Luprex/lxUtilityMacroLibrary.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:61be6856048e4253fc33c7c205e63251272941a4bb06c91e99210150dd44a5eb -size 19281 +oid sha256:967f7f152d309c6983053d7a5def2eb72eb2ecc7401249fa9ec5f5b7d4e3eb50 +size 24274 diff --git a/Source/Integration/Integration.Build.cs b/Source/Integration/Integration.Build.cs index 80dd2759..d82e62c4 100644 --- a/Source/Integration/Integration.Build.cs +++ b/Source/Integration/Integration.Build.cs @@ -24,6 +24,7 @@ public class Integration : ModuleRules "Kismet", "KismetWidgets", "BlueprintGraph", + "UMG", }); // Uncomment if you are using Slate UI diff --git a/Source/Integration/LuprexGameModeBase.cpp b/Source/Integration/LuprexGameModeBase.cpp index 46e6140a..c80b5286 100644 --- a/Source/Integration/LuprexGameModeBase.cpp +++ b/Source/Integration/LuprexGameModeBase.cpp @@ -6,6 +6,8 @@ #include "ConsoleOutput.h" #include "Tangible.h" #include "TangibleManager.h" +#include "Blueprint/UserWidget.h" + #include "CommonTypes.h" #include "AnimQueue.h" #include @@ -337,11 +339,37 @@ ALuprexGameModeBase *ALuprexGameModeBase::FromContext(const UObject *context) { return result; } -bool ALuprexGameModeBase::IsLookAtChanged(UObject *context) { +bool ALuprexGameModeBase::IsLookAtChanged(const UObject *context) { ALuprexGameModeBase *mode = FromContext(context); return mode->CurrentLookAt.HitObjectHandle != mode->PreviousLookAt.HitObjectHandle; } + +void ALuprexGameModeBase::ClearLookAtWidget(const UObject *Context) +{ + ALuprexGameModeBase *mode = FromContext(Context); + if (mode->LookAtWidget != nullptr) + { + mode->LookAtWidget->RemoveFromParent(); + mode->LookAtWidget = nullptr; + } +} + +void ALuprexGameModeBase::SetLookAtWidget(const UObject *Context, UUserWidget *Widget, int ZOrder) +{ + ALuprexGameModeBase *Mode = FromContext(Context); + if (Mode->LookAtWidget != Widget) + { + ClearLookAtWidget(Context); + } + if (Widget != nullptr) + { + Widget->RemoveFromParent(); + Widget->AddToViewport(ZOrder); + } + Mode->LookAtWidget = Widget; +} + void ALuprexGameModeBase::UpdateLookAt() { // Rotate the variables. PreviousLookAt = CurrentLookAt; @@ -361,6 +389,7 @@ void ALuprexGameModeBase::UpdateLookAt() { CalculateLookAt(pc); if (IsLookAtChanged(this)) { + ClearLookAtWidget(this); LookAtChanged(); } } diff --git a/Source/Integration/LuprexGameModeBase.h b/Source/Integration/LuprexGameModeBase.h index 2402c316..44d8a855 100644 --- a/Source/Integration/LuprexGameModeBase.h +++ b/Source/Integration/LuprexGameModeBase.h @@ -55,30 +55,44 @@ public: UFUNCTION(BlueprintCallable, Category = "Luprex|Miscellaneous") int64 GetPlayerId(); - UFUNCTION(BlueprintCallable, meta = (WorldContext = "context"),Category = "Luprex|Look-At Detection") - static void SetLookAt(UObject *context, const FHitResult &hit) { FromContext(context)->CurrentLookAt = hit; } + UFUNCTION(BlueprintCallable, meta = (WorldContext = "Context"), Category = "Luprex|Look-At Detection") + static void SetLookAt(const UObject *Context, const FHitResult &hit) { FromContext(Context)->CurrentLookAt = hit; } - UFUNCTION(BlueprintPure, meta = (WorldContext = "context"),Category = "Luprex|Look-At Detection") - static const FHitResult &GetLookAt(UObject *context) { return FromContext(context)->CurrentLookAt; } + UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"),Category = "Luprex|Look-At Detection") + static const FHitResult &GetLookAt(const UObject *Context) { return FromContext(Context)->CurrentLookAt; } - UFUNCTION(BlueprintPure, meta = (WorldContext = "context"),Category = "Luprex|Look-At Detection") - static const AActor *GetLookAtActor(UObject *context) { return FromContext(context)->CurrentLookAt.GetActor(); } + UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"),Category = "Luprex|Look-At Detection") + static const AActor *GetLookAtActor(const UObject *Context) { return FromContext(Context)->CurrentLookAt.GetActor(); } - UFUNCTION(BlueprintPure, meta = (WorldContext = "context"),Category = "Luprex|Look-At Detection") - static const FHitResult &GetPreviousLookAt(UObject *context) { return FromContext(context)->PreviousLookAt; } + UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"),Category = "Luprex|Look-At Detection") + static const FHitResult &GetPreviousLookAt(const UObject *Context) { return FromContext(Context)->PreviousLookAt; } - UFUNCTION(BlueprintPure, meta = (WorldContext = "context"),Category = "Luprex|Look-At Detection") - static const AActor *GetPreviousLookAtActor(UObject *context) { return FromContext(context)->PreviousLookAt.GetActor(); } + UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"),Category = "Luprex|Look-At Detection") + static const AActor *GetPreviousLookAtActor(const UObject *Context) { return FromContext(Context)->PreviousLookAt.GetActor(); } - UFUNCTION(BlueprintPure, meta = (WorldContext = "context"),Category = "Luprex|Look-At Detection") - static bool IsLookAtChanged(UObject *context); + UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"),Category = "Luprex|Look-At Detection") + static bool IsLookAtChanged(const UObject *Context); + UFUNCTION(BlueprintCallable, meta = (WorldContext = "Context"), Category = "Luprex|Look-At Detection") + static void SetLookAtWidget(const UObject *Context, UUserWidget *Widget, int ZOrder = 100); + + UFUNCTION(BlueprintCallable, meta = (WorldContext = "Context"), Category = "Luprex|Look-At Detection") + static UUserWidget *GetLookAtWidget(const UObject *Context) { return FromContext(Context)->LookAtWidget; } + + UFUNCTION(BlueprintCallable, meta = (WorldContext = "Context"), Category = "Luprex|Look-At Detection") + static void ClearLookAtWidget(const UObject *Context); + + // + // Look-At Related Events + // + UFUNCTION(BlueprintImplementableEvent, Category = "Luprex|Look-At Detection") void CalculateLookAt(APlayerController *PlayerController); UFUNCTION(BlueprintImplementableEvent, Category = "Luprex|Look-At Detection") void LookAtChanged(); + // Assemble a lua call. To call into lua: // // * Use LuaCallBegin @@ -127,8 +141,8 @@ public: // to update luprex sockets and update luprex itself. virtual uint32 Run() override; - // Get the current Luprex Game Mode Base, given a context object. - static ALuprexGameModeBase *FromContext(const UObject *context); + // Get the current Luprex Game Mode Base, given a Context object. + static ALuprexGameModeBase *FromContext(const UObject *Context); // Asset Lookup by Name. UPROPERTY() @@ -145,6 +159,9 @@ public: UPROPERTY() FHitResult CurrentLookAt; + UPROPERTY() + UUserWidget *LookAtWidget; + // The sensitivity level at which a log message triggers a debugger breakpoint. UPROPERTY(EditAnywhere, Category="Debugging Tools") ElxLogVerbosity BreakToDebuggerLogVerbosity; diff --git a/Source/Integration/UtilityLibrary.cpp b/Source/Integration/UtilityLibrary.cpp index b3c21715..145d8eaa 100644 --- a/Source/Integration/UtilityLibrary.cpp +++ b/Source/Integration/UtilityLibrary.cpp @@ -77,6 +77,34 @@ UEnhancedInputLocalPlayerSubsystem *UlxUtilityLibrary::GetEnhancedInputLocalPlay return nullptr; } +FVector2D UlxUtilityLibrary::PixelToViewportPosition(FVector2D Pixel) +{ + FVector2D ViewportSize; + GEngine->GameViewport->GetViewportSize(ViewportSize); + return Pixel / ViewportSize; +} + +FVector2D UlxUtilityLibrary::ViewportPositionToPixel(FVector2D Fraction, bool Snap) +{ + FVector2D ViewportSize; + GEngine->GameViewport->GetViewportSize(ViewportSize); + FVector2D Pixel = Fraction * ViewportSize; + if (Snap) + { + Pixel.X = FMath::FloorToDouble(Pixel.X) + 0.5; + Pixel.Y = FMath::FloorToDouble(Pixel.Y) + 0.5; + Pixel.X = FMath::Min(ViewportSize.X - 0.5, FMath::Max(0.5, Pixel.X)); + Pixel.Y = FMath::Min(ViewportSize.Y - 0.5, FMath::Max(0.5, Pixel.Y)); + } + else + { + Pixel.X = FMath::Min(ViewportSize.X, FMath::Max(0.0, Pixel.X)); + Pixel.Y = FMath::Min(ViewportSize.Y, FMath::Max(0.0, Pixel.Y)); + } + return Pixel; +} + + bool UlxUtilityLibrary::LineTraceThroughPixel(const APlayerController* PlayerController, FVector2D PixelXY, double MaxDistanceFromCamera, ETraceTypeQuery TraceChannel, bool bTraceComplex, EDrawDebugTrace::Type DrawDebugType, bool bIgnorePlayerPawn, diff --git a/Source/Integration/UtilityLibrary.h b/Source/Integration/UtilityLibrary.h index 8fbfbd8e..44beab25 100644 --- a/Source/Integration/UtilityLibrary.h +++ b/Source/Integration/UtilityLibrary.h @@ -47,17 +47,35 @@ public: // Get the enhanced input local player subsystem from a controller. If the controller // is not a player controller, or if it is a player controller but it doesn't have an // enhanced input subsystem, return nullptr. - UFUNCTION(BlueprintCallable, BlueprintPure, Category="Player Controller|Local Player Subsystems") + UFUNCTION(BlueprintPure, Category="Player Controller|Local Player Subsystems") static UEnhancedInputLocalPlayerSubsystem *GetEnhancedInputLocalPlayerSubsystem(AController *Controller); + // Given a Pixel XY coordinate, convert it to a viewport position. + // + // The input should be in the range (0.0, 0.0) to (ViewportX, ViewportY). + // The output XY will be in the range 0.0 to 1.0. The input + // may specify a fraction of a pixel. So the input (0.0, 0.0) + // represents the upper-left corner of the upper-left pixel, whereas the + // input (0.5, 0.5) represents the center of the upper-left pixel. + UFUNCTION(BlueprintPure, meta = (ReturnDisplayName = "Percent XY"), Category="Luprex|Utility") + static FVector2D PixelToViewportPosition(FVector2D PixelXY); + + // Given a viewport position, convert it to a Pixel XY coordinate. + // + // The input X and Y coordinates should be in the range 0 to 1. The output + // will be in the range (0,0) to (ViewportX, ViewportY). The output may + // specify a fraction of a pixel. If SnapToCenter is true, the output is + // rounded to the center of the nearest pixel. + UFUNCTION(BlueprintPure, meta = (ReturnDisplayName = "Pixel XY"), Category="Luprex|Utility") + static FVector2D ViewportPositionToPixel(FVector2D PercentXY, bool SnapToCenter); + // Do a Line Trace from the camera through a specified pixel. // // This can be used when you have a crosshair on the screen and you want to // determine the object that the crosshairs are pointing at. It can also - // be used to do a line trace through the mouse. - // - // Fractional pixels are allowed. Therefore, (0.0, 0.0) is the upper-left corner - // of the upper-left pixel, whereas (0.5, 0.5) is the center of the upper-left pixel. + // be used to do a line trace through the mouse. Fractional pixels are allowed. + // Be aware that (0.0, 0.0) is the upper-left corner of the upper-left pixel, + // whereas (0.5, 0.5) is the center of the upper-left pixel. // UFUNCTION(BlueprintCallable, Category="Collision", meta=(AutoCreateRefTerm="ActorsToIgnore", Keywords="raycast")) static bool LineTraceThroughPixel(const APlayerController* PlayerController,