So I’ve modified the Vive controller template to be able to fire a laser via a trigger press that measures the distance from controller to impact point and prints a string on-screen. I want this string to be displayed in a UMG Widget but I have no clue how to do this and it’s sort of hard to find tutorials on this specific thing.
I want the string value to be displayed near the controller where it says “LASER” currently.
In the future I want to be able to select two points with the controller and have the engine print the distance between those two points. Again, no clue how do this is. But with help we’ll get there.
You are currently using a Text Render component or a Widget component for the LASER text, hard to tell from the pic. If it’s a widget component, you can access the embedded 2d widget with the GetUserObjectWidget node, cast it and set its TextBlock’s text directly.
To get distance between 2 points - length of A-B:
I was using a Text Render component, but I’m using a Widget component now. Are these the nodes I need? Can’t really get it working. Cast it? “DistanceMeasured” is my widget blueprint that contains a simple Text Block. This is all new to me.
Yeah, that looks good, providing DistanceMeasured is the widget that you set in the widget component.
Essentially, widget component only knows that it contains a widget, it does not really care what widget it is. Casting allows you to specify the instance of the widget and manipulate the data within.
Next step would be to open the DistanceMeasured blueprint and expose the text block as a variable (isVariable at the top of the details panel). Then drag a wire from CastAsDistanceMeasured and search for that text block. Drag a wire off it again, and SetText.
Alright, thank you so much so far!
I’ve set the text block (Text Block 37) in my DistanceMeasured widget blueprint to Is Variable.
In my Widget component in the BP_MotionController blueprint I’ve set the Widget Class to DistanceMeasured (my blueprint widget). I suppose that’s the way to do it, since I can see its text content.
I’ve connected the nodes in a way that makes sense to the idiot that I am, but it’s not working yet.
Do I not also need to convert the number data of the distance measured print string into something that the widget can work with in order for it to manipulate the text block and display the distance numbers? What about binding a function to the Text content of the DistanceMeasured blueprint? Just thinking out loud here, I dont know how to actually do this.
I’d be so happy if I can just get this step working, I’l worry about the two-point vector measurement later.
You need to connect your nodes.
The white wire is the execution line, the coloured wires are data or data targets.
Blueprint nodes are context sensitive, you should always take advantage of this. Do not just plop them in the graph. Instead, drag a wire off AsDistanceMeasured’s blue pin, search for the text block and Get it. Do not Set here, you’re not replacing the widget, you’re obtaining the reference so you can adjust its embedded text.
SetText needs a target, too which is the text block on the left. Just connect them all:
The conversion from string to text (which widgets love) is automatic. Widgets can work directly with strings (when binding property) but in this very case it needs to be converted.
Oh, btw, it takes years to take it all in. I had questions just like yours 3 years ago but there was hardly anyone to answer them back then. So it was trial and error, mostly error.
Also, I’m completely unfamiliar with VR development, is the red beam a spline or a particle emitter?
That makes a lot of sense, thanks a lot for explaining that. Maybe in a few years I’ll feel less of an idiot.
No more errors now, but as soon as I use the laser, the text widget disappears from my controller (I made it float near it), I can see the string printed on-screen but the widget data isn’t replaced with the string data. The red beam is a particle system with a point light at it’s impact point that has a slight offset.
Get rid of MakeLiteralString (that was just my example) and plug in what you plug in into your PrintString node. At the moment you’re sending the content of MakeLiteralString which has no value.
And thanks for the info.
Cool, it works! Looking at it now, it makes sense, you know what that’s like l’m sure.
I have a vague understanding of printing the vector distance between two actors, as in I know which nodes to use. But for selecting two points (impact points) with the laser and printing the vector between those, no clue. I’m guessing we need to tell the engine to remember point 1 before we select point 2. And whether or not (and how) to reset that data when selecting a point for the third time. And there’s some smaller stuff going on there as well, like for how long to display the print etc. but I might even be able to figure that out on my own.
Where to start though? Appreciate it so much!
I’m guessing we need to tell the
engine to remember point 1 before we
select point 2.
Create 2 vector vars: loc1 and loc2. Create 2 bools: loc1Stored and loc2Stored.
When you pull the trigger, check if the bools are true/false. If no locations have been stored, store the first hit in loc1 and set loc1Stored(true)
Pull the trigger again, check if the loc1 has been stored already; if it has, store the result as loc2 and set the second bool to true as well. Calculate and push data to the widget.
Resetting data is setting loc1 and loc2 to 0 and both bools to false, and pushing something to the widget.
Not really a pseudo code but it might help.
To control the display time - you could use widget animation for this if you want to be cheeky. You do not really need to animate anything, just let the anim play its length (that’s your countdown). The anim has an onFinishedEvent that will fire when the anim is over - reset the data.
Using widget animation for this is fairly neat as you can very easily add additional elements.
It works! Block is 180cm tall. This is awesome, thanks so much!
Resetting is the one thing I can’t get working right now. Maybe the setup I’m using with the Sequence isn’t what I should be doing. Obviously when I connect the Branch that has the Reset Loc condition, everything breaks down, no more points are measured and the widget print stays at 0.0.
I’m using the Vive controller trigger axis to activate the laser, so you can see what you’re pointing at. The click on the trigger (or axis value 1.0) is what activates the Get Loc1 and/or 2. The yellow BP lines are connected to the Impact Location of a Break Hit Result, which is connected to a LineTraceByChannel that gets updated on Event Tick. Clicking and holding the trigger causes it to immediately get Loc2 (upon the next frame I suppose) and printing the distance. So that’s less than ideal, I’d like for it to grab Loc1 or Loc2 for just the duration of one frame (or by whatever way that should be done, I don’t know if I’m tied to the line trace for that). And be required to have a Trigger Axis value of less than 1.0 in between measurements. So one could never hold the trigger for too long and screw up the measurement. But obviously I need your help with that too. I’ll see what I can do with my limited skills in the meanwhile as well.
- Fixed the above by setting the Loc1 and Loc2 coordinates to 0 upon trigger axis value equal to 0.0, so that’s my reset
- Measurement starts at trigger axis value 1.0 (click) and that’s when the vector distance widget is visible as well. So the user clicks the trigger and drags the controller to measure, works very well.
Still looking for a way to round off the number to two decimal places, maybe even put “cm” or “centimeters” behind the value. And figure out a way to have another line trace from point Loc1 to Loc2 just to visually clarify what the user is measuring. Not sure how to all do it, but I might get lucky…
To preformat text:
To visualise the measuring process, try adding a spline component to whichever object is responsible for the measuring. Splines do not have rendering capability so you will need to create a mesh and use it as splinemesh. Make sure both are movable:
I’ve been using a mesh like this and it has served me well, ensuring the beam is visible from every angle:
You will also need a material for the Splinemesh itself: 2-Sided, Additive, used with Spline Meshes. Assign the material to the Splinemesh component visible in the screenshot above.
As default, splines have point 0 and 1. Place point 0 at start location and point 1 at the current hit vector produced by the laser (I’m assuming you’re tracing every frame). The Splinemesh does not automagically follow the spline, it needs to be updated:
I really can’t thank you enough!
I’ve connected my event tick to the Set Spline Points and set Loc1 to 0 of the Make Array and Loc2 to 1. To me it makes sense, but to the engine it does not - nothing is visible. Disconnecting from the event tick shows the spline mesh where I’ve put it by default in the Viewport of the BP.
That’s right, I am tracing the (red) laser every frame.
Spline and Mesh are set to Movable.
World / Local coordinate space is set as per your screenshot.
Both PointIndexes read 0.
edit: Also, I did not test it but judging by what it’s supposed to be used for, you may need to use World Coordinate Space on SetSplinePoints. Just experiment with both
Ah, makes sense. The point indexes refer to the Array points, right?
Turns out Set Spline Points coordinate space needs to be set to World and the Get location and Tangent at Local.
This is pretty neat, thank you so so much for your help. I might try adding some extra stuff to this setup but this is exactly what I needed!
The point indexes refer to the Array
Yes, and you can have as many as you need, when measuring distance between more than 2 objects, for example.
Turns out Set Spline Points coordinate
space needs to be set to World and the
Get location and Tangent at Local.
Yeah, sorry - I was just conjuring it too rapidly, my bad.
This is pretty neat
Agreed, looks slick! But then again, it’s lasers… good stuff.
Here’s another challenge of stuff I’d like to add on top of this Vector measurement: Delta X, Delta Y and Delta Z between two impact points. So I don’t have to worry about making a perfectly straight line (or sometimes that’s just not possible), but still get a correct measurement. Ceiling to floor for example.
I think I’ll create three more separate widgets for that, correct? That part and its nodes I can probably manage (thanks again!). The maths part I’m not sure in what way the engine works. Probably also with vectors, but with some specific calculations added in between to produce the delta’s? I see no “delta” nodes that seem usable.
Yes, I think locking an axis is kind of what it comes down to:
I want to be able to create two impact points (red) with my laser and not just get that red vector distance that we now have, but also the blue delta. For the X, Y and Z axis, so straight lines I suppose. Makes sense?
[…] Delta X, Delta Y and
Delta Z between two impact points. So
I don’t have to worry about making a
perfectly straight line (or sometimes
that’s just not possible), but still
get a correct measurement. Ceiling to
floor for example.
I’ll admit I’m not sure what you mean. Are you talking about locking an axis so the measurement is only done in a straight line? Or some kind of SnapToObject feature?
Or do you just want to display the delta at hit location?