Get relative or screen space location of Image in a Widget Blueprint.

Hi!

I have a Widget Blueprint. In that Widget Blueprint I have a crosshair as an image. That crosshair image is then given anchors to the center, alignment (0.5, 0.5) and position X = 0.0 and position Y = -220.0. The result of this is a crosshair in the middle of the screen raised slightly.

I want to use this crosshair to aim at what I want to shoot at. So say the crosshair is over a box in the world, I then linetrace from the crosshair and hit the box, the location of the hit is where my weapon will target and shoot at. The issue I’m having is getting the location of the crosshair on the screen in order to do the linetrace. I COULD do it with hard-coded values but I don’t want to hard-code such values. So my question is: How do I get the location of this crosshair dynamically? (resulting in a Vector2D)

The problem isn’t getting the value as much as transmitting it back to the blueprint.

Why not just go the other way around the problem?
Create a variable (game level is a good spot for this one) - pass the variable to the widget in BP, which will use it to offset the cross hair. Use the same value in your ray tracing calcs.

That way the value is not set in Widget and you won’t have to read it out either. (note -220 is probably not the value you want for the trace. camera position break vector, add to Z to offset up. You might need to transform this value that works in world space with unreal untis to something the widget can use.)

Alright. So my plan now is to give the crosshair a relative position of (0.0, 0.0) to (1.0, 1.0) which I then use to position the crosshair in the Widget. Then I use viewport size * the relative position to get screen position to use with DeprojectScreenPositionToWorld function. I assume that would work?

Alright this ended up being my solution:

I created a FVector2D variable in the PlayerController which holds the CrosshairRelativeLocation. I put it here because I couldn’t figure out how to access the Game Level variables through the widget but the widget does have a reference to the PlayerController.

In the widget I then went to the graph and added what can be seen in the image:

Then in my PlayerController I have a function for doing the line trace:



bool AFirstPersonController::LineTraceSingleByChannelFromCrosshair(FHitResult& OutHit, float DistanceToCheck, ECollisionChannel TraceChannel) const
{
    int32 ViewportSizeX, ViewportSizeY;
    GetViewportSize(ViewportSizeX, ViewportSizeY);

    FVector WorldLocation, WorldDirection;
    DeprojectScreenPositionToWorld(ViewportSizeX * CrosshairRelativeLocation.X, ViewportSizeY * (1.f - CrosshairRelativeLocation.Y), WorldLocation, WorldDirection);

    FCollisionQueryParams Params = FCollisionQueryParams(FName(TEXT("")), false, GetOwner());
    if (GetPawn())
    {
        Params.AddIgnoredActor(GetPawn());
    }

    DrawDebugLine(GetWorld(), WorldLocation, WorldLocation + WorldDirection * DistanceToCheck, FColor::Red, true);

    return GetWorld()->LineTraceSingleByChannel(
        OutHit,
        WorldLocation,
        WorldLocation + WorldDirection * DistanceToCheck,
        TraceChannel,
        Params
    );
}


This works just fine, the problem with this however is that it’s bound to Tick. It really doesn’t need to update the location of the crosshair every tick but I couldn’t find another way to get the geometry, the ones I found just returned 0,0. Any tips on how to do this in like a BeginPlay or something like that?

Edit:
So I fixed the tick thing with using On Initialized event and using Get Viewport Widget Geometry -> Get Local Size which worked just fine.