#Setting initial UI element position relative to Enemy Object

1 messages · Page 1 of 1 (latest)

charred warren
#

Right now I have this script which is tied to the UI Panel

#
public class FaceUICamera : MonoBehaviour
{
    [Header("Tweaks")]
    [SerializeField] public Transform lookAt;
    [SerializeField] public Vector3 offset;

    [Header("Logic")]
    private Camera cam;

    private void Start()
    {
        
    }
    public void Setup(Transform lookAtMe)
    {
        Canvas canvas = GameObject.FindGameObjectWithTag("Stats UI Overlay").GetComponent<Canvas>();
        cam = Camera.main;
        lookAt = lookAtMe;
        transform.position = cam.WorldToScreenPoint(lookAt.position+offset);
    }

}```
worldly oyster
#

!cs

lyric ingotBOT
#

You can format your multiline code block with C# highlighting! Just add cs to the start of it. Highlighting example below!

class Fluffs : FluffyCat
{
    public void PetCat ()
    {
        Debug.Log ("Petting Cat.")
    }
}
charred warren
#

Thank you! I'll edit that post

gaunt badger
#

screentoWorldpoint

#

oh no nm

worldly oyster
charred warren
#

LookAtMe is the enemy gameobject's transform in this case

gaunt badger
#

i gotta quickly

worldly oyster
#

first, is this FaceUICamera spawned from another script?

#

yeah, if you can edit the original snippet you posted above, it'll be easier to look at code-wise . . .

gaunt badger
#

deleted the canvas whoops

#

well that should work

#

i think

#

only thing i altered was

worldly oyster
#

remove Start altogether, it's empty . . .

gaunt badger
#

uhh instead of localPos using position

#
public class FaceUICamera : MonoBehaviour
{
    [Header("Tweaks")]
    [SerializeField] public Transform lookAt;
    [SerializeField] public Vector3 offset;

    [Header("Logic")]
    private Camera cam;

    public void Setup(Transform lookAtMe)
    {
        Canvas canvas = GameObject.FindGameObjectWithTag("Stats UI Overlay").GetComponent<Canvas>();
        cam = Camera.main;
        lookAt = lookAtMe;
        transform.position = cam.WorldToScreenPoint(lookAt.position+offset);
    }

}
worldly oyster
charred warren
#

I forgot the last few things I had done in an attempt to make this work. localPosition wasn't causing the problem, I wasn't using it initially. I've edited my original code post

gaunt badger
#

welp imma go, i also have a game level issue with my code, so i'm gonna fix that.

charred warren
gaunt badger
#

sorry for not being helpful

charred warren
#

I appreciate the help none the less!

worldly oyster
# gaunt badger never knew lol

yeah, if your object is a child of a parent, it's always best to manipulate the local position. if the object does not have a parent, then using localPosition is the same as position . . .

gaunt badger
#

maybe if the enemy or ui is parented, it sets the localpos + the parent pos so its way off

#

but thats my thought process so yeah :)

charred warren
#

I'll be back in just a couple minutes. I'm going to revert a few changes I made while I was trying to fix this myself and bring myself back to the original issue I was having, that way I'm not introducing weird extra elements

#

Ok, I've reverted back to where I was when I was first having this issue. So, this is my enemy script which instantiates the UI element:

private void Start()
    {

        GameObject enemyUIprefab = (GameObject)Resources.Load("Prefabs/EnemyPanel", typeof(GameObject));
        enemyUI = Instantiate(enemyUIprefab, GameObject.FindGameObjectWithTag("Stats UI Overlay").transform);
        nameText = enemyUI.transform.Find("nameText").GetComponent<TextMeshProUGUI>();
        hpText = enemyUI.transform.Find("hpText").GetComponent<TextMeshProUGUI>();
        hpSlider = enemyUI.transform.Find("hpSlider").GetComponent<Slider>();
        enemyUI.GetComponent<FaceUICamera>().Setup(gameObject.transform);
    }```
#

This is the "FaceUICamera" component script:

public class FaceUICamera : MonoBehaviour
{
    [Header("Tweaks")]
    [SerializeField] public Transform lookAt;
    [SerializeField] public Vector3 offset;

    [Header("Logic")]
    private Camera cam;

    public void Setup(Transform lookAtMe)
    {
        Canvas canvas = GameObject.FindGameObjectWithTag("Stats UI Overlay").GetComponent<Canvas>();
        cam = Camera.main;
        lookAt = lookAtMe;
        transform.position = cam.WorldToScreenPoint(lookAt.position+offset);
    }

}
#

This is the scene once I hit play. RedSlime is the enemy I would like the EnemyPanel(Clone) to be near:

#

with this script exactly as it is, the panel is instead spawning here (top right, the UI canvas I want it on is in the bottom left)

#

and this is the rect transform of the panel:

gaunt badger
#

ok i maybe got the fix

#

its hacky

#

but who cares

charred warren
gaunt badger
#

ok so if you round off everything to basically ints

#

and then do the worldtoscreen

#

maybe that'll get rid of the big numbers

charred warren
#

ok, I can give that a shot

gaunt badger
#

source

#

another one

charred warren
#

Actually, I'm not sure how I would go about rounding it in the first place

#

Ok, so I added
Debug.Log(cam.WorldToScreenPoint(lookAt.position));
to see what position it was returning before I was putting that position into the Canvas's location. Its returning
(531.60, 415.80, 23.39)
which seems like reasonable numbers

worldly oyster
charred warren
#

Yes. The FindGameObjectWithTag is just to find the canvas I want it to be a child of

worldly oyster
worldly oyster
charred warren
#

this line: enemyUI = Instantiate(enemyUIprefab, GameObject.FindGameObjectWithTag("Stats UI Overlay").transform);

#

I see what you mean, now, though

worldly oyster
charred warren
#

This is on an Enemy class, just a script called Enemy

#

which is attached to the enemy prefab I've created, which is the parent of the model I'm using for that enemy, and otherwise is an empty GameObject

worldly oyster
#

also, not sure why you're using Resources instead of a variable for the enemyUIPrefab . . .

charred warren
#

Because every enemy was going to be pulling in the same UI, I figured it would be better to pull from resources rather than having to drag the prefab UI onto each enemy I created

worldly oyster
#

are your enemies spawned into the game as well?

charred warren
#

Yes, though right now I'm testing it by just putting one in the game world first

#

without spawning it

worldly oyster
#

okay, what script spawns them in? i ask bc you can have the prefab as a variable on the script that spawns them in and it will take care of spawning a ui along with the enemy . . .

charred warren
#

right now I don't have a script that spawns it in, I was working on that when I ran into this issue, but I can definitely make that change

worldly oyster
#

the script that spawns them in is basically a manager that keeps track of all enemies. this makes it easier bc everything can be setup from one script. it will have a variable for the canvas (parent of the ui) and a variable for the enemyPrefab so you don't have to search for those . . .

charred warren
#

Sure, I can definitely do that. But would making those changes fix the initial problem of my Panel spawning thousands of units away from the ScreenPosition of my enemy that I've placed in the scene?

worldly oyster
#

also, instead of getting the component multiple times for each child of a parent, you need to make a script and create variables instead, that way, you can assign the components from the inspector for the TextMeshProUGUI and Slider components . . .

charred warren
#

Gotcha, that would make the setup cleaner.

worldly oyster
#

you want to set the object's anchored position . . .

charred warren
#

Ok, its definitely getting closer to the expected position

#

I've changed the code to this:

    public void Setup(Transform lookAtMe)
    {
        Canvas canvas = GameObject.FindGameObjectWithTag("Stats UI Overlay").GetComponent<Canvas>();
        cam = Camera.main;
        lookAt = lookAtMe;
        Debug.Log(cam.WorldToScreenPoint(lookAt.position));
        transform.GetComponent<RectTransform>().anchoredPosition = cam.WorldToScreenPoint(lookAt.position + offset);
        Debug.Log(transform.position);
    }
#

and my debug logs are returning this:

UnityEngine.Debug:Log (object)
FaceUICamera:Setup (UnityEngine.Transform) (at Assets/FaceUICamera.cs:19)
Enemy:Start () (at Assets/Enemy.cs:31)
(15.75, 28.32, -45.00)
UnityEngine.Debug:Log (object)
FaceUICamera:Setup (UnityEngine.Transform) (at Assets/FaceUICamera.cs:21)
Enemy:Start () (at Assets/Enemy.cs:31)
#

the first one being the panel's location, the second being the enemy's screen location

#

I changed the debug.log to

Debug.Log(cam.WorldToScreenPoint(lookAt.position));
Debug.Log(transform.GetComponent<RectTransform>().anchoredPosition);
#

and it returned

UnityEngine.Debug:Log (object)
FaceUICamera:Setup (UnityEngine.Transform) (at Assets/FaceUICamera.cs:19)
Enemy:Start () (at Assets/Enemy.cs:31)

(531.60, 415.80)
UnityEngine.Debug:Log (object)
FaceUICamera:Setup (UnityEngine.Transform) (at Assets/FaceUICamera.cs:21)
Enemy:Start () (at Assets/Enemy.cs:31)

#

so the values now match. Now I just need to figure out why it isn't showing in the expected spot

worldly oyster
charred warren
#

right now offset is a vector 3 with 0,0,0 as the position, so it shouldn't be changing anything. I'll remove it now to see if its making any change

#

Do you think my canvas scale is affecting it? The render mode for my canvas is Screen Space Camera, tied to a UI Camera, which is setting it's scale to .0296296...

worldly oyster
#

yes, does affect it . . .

charred warren
#

I multiplied the vector3 by .03f (just an approximation of the scale) and it didn't really change in the way I expected. I put in 2 enemies to test this out a bit better to see relative positions of 2 panels

#

Removing the offset made no change to the position. they are both returning the same vectors

#

changing the scale to 1 by making them Screen Space - Overlay had no change on them either

#

Ok, so I changed the offset to (-10.5f, -12.25f, 0), which worked, but I don't know exactly why

#
UnityEngine.Debug:Log (object)
FaceUICamera:Setup (UnityEngine.Transform) (at Assets/FaceUICamera.cs:19)
Enemy:Start () (at Assets/Enemy.cs:31)

Panel Anchor Position: (-464.30, -796.34)
UnityEngine.Debug:Log (object)
FaceUICamera:Setup (UnityEngine.Transform) (at Assets/FaceUICamera.cs:21)
Enemy:Start () (at Assets/Enemy.cs:31)

EnemyPosition: (807.45, 412.01, 22.44)
UnityEngine.Debug:Log (object)
FaceUICamera:Setup (UnityEngine.Transform) (at Assets/FaceUICamera.cs:19)
Enemy:Start () (at Assets/Enemy.cs:31)

Panel Anchor Position: (-137.55, -682.66)
UnityEngine.Debug:Log (object)
FaceUICamera:Setup (UnityEngine.Transform) (at Assets/FaceUICamera.cs:21)
Enemy:Start () (at Assets/Enemy.cs:31)

EnemyPosition: (227.40, 396.95, 21.64)
UnityEngine.Debug:Log (object)
FaceUICamera:Setup (UnityEngine.Transform) (at Assets/FaceUICamera.cs:19)
Enemy:Start () (at Assets/Enemy.cs:31)

Panel Anchor Position: (-717.60, -697.71)
UnityEngine.Debug:Log (object)
FaceUICamera:Setup (UnityEngine.Transform) (at Assets/FaceUICamera.cs:21)
Enemy:Start () (at Assets/Enemy.cs:31)

```
#

I don't know how these numbers translate to one another

worldly oyster
#

well, what are these positions? in what space are they in?

charred warren
#

The EnemyPosition is : cam.WorldToScreenPoint(lookAt.position)

#

and the Panel Anchor Position is : transform.GetComponent<RectTransform>().anchoredPosition

#

but the difference between the 2 values, for example (480.7, 298.33) and (-464.3, -796.34) isn't just a difference of (-10.5, -12.5)

worldly oyster
#

WorldToScreenPoint is just the screen position defined in pixels
anchoredPosition is the position of the pivot relative to its anchor reference point (the position of the anchors)

these positions have no relation to each other . . .

charred warren
#

So then was changing their anchored position not the right thing to do, and I just got lucky?

#

It seems to work no matter where I place them, which is exactly what I want. So it definitely works. I just want to understand what I did at this point to make sure I can reproduce it or fix it if something else breaks

worldly oyster
#

no, moving the anchoredPosition is the correct way. setting the anchoredPosition to the screen position from the conversion should place it at the pivot of the enemy . . .

charred warren
#

Hmm... so why did I have to have such a drastic offset to align it to the enemy's screen location

#

I was expecting to have to just have a small -y and the X value would already be centered, but instead it was up and to the right by a pretty large margin

#

and even moving the canvas itself didn't cause any issues, which is great!

charred warren
#

Ok, I have run into another issue. If I change the aspect ratio of the game, the EnemyPanels no longer line up properly again

worldly oyster
charred warren
#

Also, my main issue with having to set such a high offset was that I had the anchor set to the top middle instead of the bottom right. That's why the objects were showing in the right area relative to each other, but not in the right space relative to the screen. Since 0,0 is the bottom left of the canvas