#Setting initial UI element position relative to Enemy Object
1 messages · Page 1 of 1 (latest)
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);
}
}```
!cs
Thank you! I'll edit that post
what is LookAtMe
Transform . . .
LookAtMe is the enemy gameobject's transform in this case
i gotta quickly
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 . . .
deleted the canvas whoops
well that should work
i think
only thing i altered was
remove Start altogether, it's empty . . .
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);
}
}
localPosition is better (more performant) to use bc it only updates that GameObject's local position and doesn't search up and down the GameObject's hierarchy . . .
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
never knew lol
welp imma go, i also have a game level issue with my code, so i'm gonna fix that.
FaceUICamera is tied to an EnemyUIPanel prefab that I have, so it is spawned in with the UI element I want to move
sorry for not being helpful
I appreciate the help none the less!
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 . . .
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 :)
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:
FaceUICamera is tied to an EnemyUIPanel prefab that I have, so it is spawned in with the UI element I want to move (i responded to the wrong line earlier)
ok so if you round off everything to basically ints
and then do the worldtoscreen
maybe that'll get rid of the big numbers
ok, I can give that a shot
source
another one
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
so there is a script that spawns the EnemyUIPanel which has the FaceUICamera script attached to it? i ask because you shouldn't useFindGameObjectWithTag for every UI that gets added to the scene . . .
Yes. The FindGameObjectWithTag is just to find the canvas I want it to be a child of
nameText = enemyUI.transform.Find("nameText").GetComponent<TextMeshProUGUI>();
hpText = enemyUI.transform.Find("hpText").GetComponent<TextMeshProUGUI>();
hpSlider = enemyUI.transform.Find("hpSlider").GetComponent<Slider>();
this needs to be fixed as well. all of these multiple GetComponent calls on every UI will cause performance issues . . .
sure, what is the actual script that spawns the EnemyUIPanel?
this line: enemyUI = Instantiate(enemyUIprefab, GameObject.FindGameObjectWithTag("Stats UI Overlay").transform);
I see what you mean, now, though
yes, but what script (class name) is this code on?
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
also, not sure why you're using Resources instead of a variable for the enemyUIPrefab . . .
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
are your enemies spawned into the game as well?
Yes, though right now I'm testing it by just putting one in the game world first
without spawning it
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 . . .
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
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 . . .
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?
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 . . .
Gotcha, that would make the setup cleaner.
if this is the ui object you should be using its RectTransform not its Transform component . . .
you want to set the object's anchored position . . .
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
the only thing different is the offset. that seems to be the wrong value . . .
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...
yes, does affect it . . .
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
well, what are these positions? in what space are they in?
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)
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 . . .
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
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 . . .
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!
Ok, I have run into another issue. If I change the aspect ratio of the game, the EnemyPanels no longer line up properly again
that depends on the size of the object and the size of your ui. different values for different sizes . . .
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