Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Multiple enemy health bars

Discussion in '2D' started by PixelPockets, Apr 30, 2022.

  1. PixelPockets

    PixelPockets

    Joined:
    Sep 7, 2020
    Posts:
    143
    I really wasn't sure where this question belonged..

    I've been trying to come up with an easier way to handle this, but I need some suggestions..

    My original idea was to use a prefab health bar "game object" that could be instantiated at start when an enemy was instantiated (the enemy would instantiate the health bar prefab at start). The prefab would have all of the necessary child objects to make the health bar function, along with a health bar script for scaling and setting the color and position. I tried to get this to work, but ran into several issues, and I don't think using a prefab would be ideal anyway.

    At the moment, each of my enemy prefabs have their own built-in health bar components that are a permanent part of the enemy prefab itself. The health bar is a game object (with other various children) that is a child of the enemy, but this is a rather convoluted and laborious way to do it, so I was wondering if there was a better way to handle it. Perhaps with a UI system of some sort?

    I have a UI canvas that has a health/energy bar for the player, and that canvas is loaded with each scene. Is there a way to use the UI like this for all enemies, and have the health bar stick to the enemy's position and update the bars on a per-enemy basis?
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    39,067
    I think this is the best way to go. This lets Enemy type X know that it needs Health Bar #3, which it just spawns up.

    You also don't necessarily need to parent the bars.. but each frame the enemy moves, it could tell the health bar where it is, letting it "Chase it around" so to speak.

    I like the factory pattern for stuff like this, for instance an EnemyHudFactory that can make huds from prefabs on demand and hand them back. That lets you test it easily, then connect it in code to the enemy.

    But if you do parent things, just make sure that none of the GameObjects involved in parenting have any scales set (Eg, always scale 1,1,1)... only scale the child objects that won't have further children.

    (From the other post:)

    I'm stalking you!! j/k :)
     
  3. PixelPockets

    PixelPockets

    Joined:
    Sep 7, 2020
    Posts:
    143
    Hey Kurt,

    I was actually working on this a little bit, and the prefab thing is definitely the way to go. At least, perhaps for my own use case.

    Here's what I did -

    I already had a health bar set up for one enemy type. So, I decided to make that health bar a prefab. Since the enemy is a prefab, all I really need to do then is instantiate the health bar prefab and use the overload from the Instantiate() function that allows you to set the parent object. Then, in my enemy health manager script (attached to the parent object), I can use the GetComponentInChildren() function to get the health bar prefab, and use the methods in the script that's attached to the health bar prefab to set the bar's position, scale, and color according to that specific enemy.

    So, the level manager can instantiate the enemies, and then the enemies themselves can instantiate their own health bar prefabs. There might be a better way to do this, but it seems to work correctly as it is. Each enemy has it's own health bar positioned correctly, and shows their independent health.
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    39,067
    Perfect. No reason the level manager needs to know about health bars. The enemy knows what he wants/needs. Nice.

    I forgot to post my factory pattern code snippet... this further keeps all the setup and connection of the healthbar inside the health bar script(s) themselves. Check it:

    Factory Pattern in lieu of AddComponent (for timing and dependency correctness):

    https://gist.github.com/kurtdekker/5dbd1d30890c3905adddf4e7ba2b8580

    So your enemy would call a static factory method in HealthBar such as:

    Code (csharp):
    1. HealthBar.Attach( enemyGameObject, AnyArgumentsThingsHere);
    If you really want to get spiffy, pass in a delegate that the health bar calls to get the enemy's health. That way the enemy never has to worry who is observing his health.

    given this factory:

    Code (csharp):
    1. public static void Attach( GameObject go, System.Func<float> GetHealth) ...
    Then the enemy would call:

    Code (csharp):
    1. HealthBar.Attach( gameObject, () => { return MyHealth; });
     
  5. PixelPockets

    PixelPockets

    Joined:
    Sep 7, 2020
    Posts:
    143
    Thanks for the link!

    I do have one issue with the instantiation of my health bar prefab -

    I am instantiating the health bar prefab from a specific game object, and I need to have it as a child of that object. Is there a way to set the parent in the Instantiate() function as the object that instantiated it in the first place? I realized that the script I am using to instantiate the prefab is attached to the object that the prefab needs to be parented to.


    EDIT: Nevermind, I figured it out lol. I don't know why I keep doing this..

    For anyone curious, just use "transform" as the parent.
     
    Kurt-Dekker likes this.
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    39,067
    Yaaas, this indeed:

    Specifically,

    Use the overload of Instantiate<T> that accepts a Transform as the final argument, which will auto-parent on instantiate, which is rather critical for UI-based prefabs.
     
  7. PixelPockets

    PixelPockets

    Joined:
    Sep 7, 2020
    Posts:
    143

    Awesome, thanks!