So I have a character, and when he speaks I want my dialogue UI to appear right above his head. I know how to convert his position to canvas coordinates but not his scale. Because I need his scale to add to his Y position so it will be perfectly above his head right? Is there a better way to do it??? Please help!
If you don’t understand what I’m asking then please ask for clarification.
In the script that the guy answered with he has a static height variable. I need that to be changed according to the height of my character and the size of the current resolution, then translated to UI coordinates. Look, this is my problem:
In unity editor:
In Build & Run:
The gameobject being the clam in the suit. This is when I use a static variable like 3.5f for example, it’s only going to look right when the screen is the right size. How do I fix it so it’s always above the head no matter what? I want the height of the gameobject + the y position and then converted to canvas coordinates. I tried this:
but for some reason the text goes higher when the localscale gets lower, it should be reversed right??? I’m so confused.
Would you be open to using a WorldSpace Canvas as a child of the character, and positioning it in the world above the characters head?
Otherwise you can get the height of the character using Bounds, and then convert to screenspace using Camera.main.WorldToScreenPoint(worldSpacePosition). If your character is made up of multiple renderers, you can get an aggregate bounds by using Bounds.Encapsulate() for each renderer making up the character.
Also please use code tags and paste the code into your post, do not upload screenshots of code.
To make floating HUD item / text whatever work, you could make it’s offset relative to canvas and proportional to canvas size. And like @LiterallyJeff said, you can use bounds of an object, for example if your character has a box collider or such…
float offsetProp = 0.01f;
// Proportional distance based on canvas size
var propDist = canvasRect.rect.y * -offsetProp;
// Placement using transform pos, bounds and offset percentage based on canvas size
var offset = target.transform.position.y + (col.bounds.extents.y) + propDist;
Vector3 offsetPos = new Vector3(target.transform.position.x, offset, target.transform.position.z);
EDIT:
This way canvas (actually screen) size shouldn’t matter (I think 4k and 800x600 worked the same), and you can scale the character’s size or one axis.
So what’s wrong with just converting the target position from world space to screen space? This is a relatively trivial problem to solve. Here is how I approach it.
Create an empty GameObject as a child of the character in the position you want the text to appear
Convert the empty GameObject’s position to screen space with Camera.WorldToScreenPoint.html
Set up the UI.Text with the pivot position at the bottom, anchors at bottom left corner of the screen*
Move the UI.Text’s position to the screen space position of the empty GameObject
*I think its bottom left. There is a sweet spot for the anchors that means Transform.position lines up with screen space. If you can’t find it, just calculate an appropriate offset.
Where do you get col from? and is the target the UI or the gameobject?
This is what it looks like for me rn:
void positionText(GameObject target)
{
//CHANGE X POSITION
float offsetProp = 0.01f;
// Proportional distance based on canvas size
var propDist = target.GetComponent<RectTransform>().rect.y * -offsetProp;
// Placement using transform pos, bounds and offset percentage based on canvas size
var offset = target.transform.position.y + (col.bounds.extents.y) + propDist;
Vector3 offsetPos = new Vector3(target.transform.position.x, offset, target.transform.position.z);
}
“So what’s wrong with just converting the target position from world space to screen space?”
It was used, see the link to other thread. Only difference was that you used the empty transform, which in the end might be a better choice in this case…
EDIT: now that I think / start to remember the reason for suggesting the idea… was that with this way it’s possible to have floating HUD bar / text over target, no matter what. Think about a RTS game unit that gets turned upside down when hit, or a character that crouches and continues speaking, as target’s root transform position and bounds are used to place something above it, it wouldn’t matter if target is rotating or changing it’s size.
Nevermind, finally got it working, I put a “TextPoint” gameobject as a child so I could easily position the text like you guys said. Then made an empty script on it called TextPoint and this is what my final script looks like:
if (target.transform.position.x < -3.5f)
{
dText.transform.position = new Vector3(
Camera.main.WorldToScreenPoint( new Vector3(-4f, (target.transform.position.y), target.transform.position.z)).x,
Camera.main.WorldToScreenPoint(target.GetComponentInChildren<TextPoint>().transform.position).y,
dText.transform.position.z
);
}
else if (target.transform.position.x >= -3.5f && target.transform.position.x < 3.5f)
{
dText.transform.position = new Vector3(
Camera.main.WorldToScreenPoint( target.transform.position).x,
Camera.main.WorldToScreenPoint(target.GetComponentInChildren<TextPoint>().transform.position).y,
dText.transform.position.z
);
}
else if (target.transform.position.x >= 3.5f)
{
dText.transform.position = new Vector3(
Camera.main.WorldToScreenPoint(new Vector3(4f, (target.transform.position.y), target.transform.position.z)).x,
Camera.main.WorldToScreenPoint(target.GetComponentInChildren<TextPoint>().transform.position).y,
dText.transform.position.z
);
}
dText is the text UI, target is the gameobject, and I just got the components position and just converted everything. The if statements are for keeping the text within the view of the camera.
Way simpler than I tried to make it at first. This should work no matter the resolution.