Which would be the best way to create a hitpoint bar or a nickname label or whatever above another GameObject, so that the font is never shown in a weird perspective towards the camera and retains a constant size on screen?
I could think of some approaches, like just creating a label in my Screen Space - Overlay layer and attaching a script that moves it every time the game object moves, but is there any solution that does not require a scripting overhead?
The best solution is to create a Screen Space canvas and then have your UI elements on the canvas. Have each health bar linked to a ‘character’ and then in the LateUpdate for the healthbar align it into the correct screen space position (if it has changed). You could also do this with a single ‘health bar manager’ so you only need on update call.
I did exactly this last night and I did it the way Tim C said. It seems to work very well.
I wanted health bars above my enemies like in League of Legends and similar games. These health bars are in screen space, but they follow the characters just like you describe.
First I created a canvas with a slider as a child and tweaked the slider the way I wanted it to look. Sliders work very well as health bars I’ve discovered.
Then I saved the slider as a prefab and deleted the one in my scene. I kept the canvas because that would be my health bar manager. There’s no scripts on the canvas though. It’s just there to make sure the sliders show up.
Whenever I instantiate an enemy I also instantiate a health bar, ie. my slider prefab, and I make sure they each have a reference to eachother. I also make sure to set the health bar manager (ie. the canvas) as the parent for my instantiated slider. Otherwise it will not show on screen.
Then in Update (I’m not sure what the difference is with LateUpdate) I use this method Unity - Scripting API: Camera.WorldToScreenPoint to get the screen space position for my health bar based on the enemy’s world space position so I can position the health bar above the enemy.
Whenever the enemy takes damage I update the slider value and if the enemy dies I destroy the referenced slider.
EDIT: I noticed Tim C mentioning only using 1 update call. I’m not familiar with performance in Unity and what’s expensive and what’s not so the Update() method in my example is on a script attached to every health bar. In my head that was better than having a foreach loop inside the manager, but like I said. I have no clue.
My initial approach was different however and it didn’t work at all. I commented on it here because it felt like a bug:
Basically I initially tried putting a canvas with a slider as children of my enemy game object so every enemy would spawn with a health bar, but having a screen space canvas as a child of another game object did not work correctly for some reason.
That is something I’d like more info. What’s the diff having a update call for each object and a for to handle them? Just because you avoid the function call? But what if your objects already have that function running? Should I remove all movement update control from the object script and put in a manager? I’m confused now
@IntDev , the reason I don’t really care is because I only make games for myself and play them on my massive powerhouse desktop computer. But I guess you would use the Unity - Manual: Profiler overview or similar to figure it out if you were at a point were you actually had to optimize your game. Until then I wouldn’t really worry. Of course it’s nice to use “best practices” from the the get-go, but you usually acquire them over time anyway. There’s no need spending a lot of time searching for them if your code works at the moment.
@Taschenschieber , I’m guessing you would have to handle it yourself. I normally have a “bool isMoving” and I set that to true whenever the velocity of the object is > 0. I use that for playing the correct animation etc. Like you hinted at yourself with “turn/frame” your definition of movement may not be the same as mine so it’s best to handle it the way that best fits your needs.
In my setup, things are either moved by just giving their transform a new position or by iTween for animated movement. I’m doing a TBS game, so I don’t need rigidbodies et cetera. So I would just set a bool isMoving to true whenever I change the transform’s position or when an iTween animation is running (for which I would need a second flag).
…this used to be so easy in the old GUI. Maybe I’ll stick with it for that single purpose.
the problem with this approach, I have found, is that when you need to sort the bars for the nearest objects to the top of rendering, you can get 60+ms cpu spikes in Canvas.SendWillRenderCanvases (5.2.2p1, Windows standalone) if you use the sibling reordering methods, like Transform.SetAsLastSibling