Abnormal and Complex healthbar Shapes. Unity 5
This question has been asked many times in many ways, However none of the vast sea of questions and responses touch on what exactly is trying to be achieved.
I am trying to create a solution or system which allows me to accurately fill or drain an arbitrary complex shaped health bar https://www.youtube.com/watch?v=OeLPyUxIwlA from a normalized ratio of 0 being Min Health to 1 being Max Health.
There has been a Post about a Kingdom hearts style health bars in 2010 which linked to what is now know as the radial fill in unity 5.
Those methods only focused on the radial and horizontal aspects separately and not the candy cane shape in full.
The cutout method original posted has severe flaws with 0-1 calculation and results in full image breaking when cutout reaches 0 instead of the desired result as well as requiring an ungodly perfect gradient.
The other method talked about two separate images, one for the horizontal and one for the radial, seems like a poor solution as it would not hold up to other complex shapes such as a triangle health bar or Spiral like healthbar akin to Soul Reaver https://www.youtube.com/watch?v=bmlb_3Zukfw.
This post is for all those who have come here for years trying to find THE solution for being able to fill and reveal complex healthbars. And for those who do not want to resort to just trying to buy an asset store pack that makes us reliant on developer updates.
The other solutions were using animated sprites which has overhead issues for using multiple textures. to achieve the proper visuals. but also comes with the caveat of not knowing what to do to link the animation to forward and reverse playback based on current health.
http://embed.gyazo.com/d05df8d6a394afdf997a10405a698f0e.gif
this is the closest I've seen someone get with a cutout shader but i myself have not been able to achieve this result... is anyone willing to spare some advice on how to achieve this request?
I have made some progress however it is only for the animator route. if you make an animation of your healthbar filling, in script you can access the timed playback by using
Animator.Play("stateName", -1, normalizedfloat);
.
Setting the normalized float to anything between 0.0 and 1.0 will have playback start at that frame. To "freeze" the frame. you can set the Animator.speed=0.01f.
So far this works with all animation for the animator.
Its simple and can work on any shape. however there is still room to improve.
I'm looking into making the health bar expand upon leveling up. it will increase the bar length. where i am at now is having a maximum bar length already animated. and setting its normalized time to the relative health start position.
but this seems incorrect.
the scenario should be as follows, max health = 100, Animator.play("animationname",-1, 0.5f) character levels up, new health is 127, Animator.play("animationname",-1,some equatible normalized float between 0 and 1).
on the opposite end of the spectrum the normalized float of the animation has equate to 0-1
if the normalized time is 0.5 and i want to decrease it by my health value. the normalized time has to morph into 1 so that i can calculate the health math properly. but remain .5 in the animation playback.
anyone have any ideas?
Getting much Closer this code also implements maxing out health upon leveling up.
using UnityEngine; using System.Collections;
public class AnimPlayer : $$anonymous$$onoBehaviour { public Animator Healthanimator;
public int curLevel;
public int lastLevel;
public float LVI;
public float $$anonymous$$Health;
public float maxHealth;
public float curHealth;
public float startHealth;
// Use this for initialization
void Awake ()
{
Healthanimator = GetComponent<Animator>();
curHealth = $$anonymous$$athf.Clamp(curHealth,$$anonymous$$Health, maxHealth);
maxHealth = $$anonymous$$athf.Clamp(maxHealth, $$anonymous$$Health, 1.0f);
lastLevel = curLevel;
}
void Start()
{
Healthanimator.speed = 0.01f;
curHealth = startHealth;
maxHealth = startHealth;
}
// Update is called once per frame
void Update ()
{
Healthanimator.Play("Healthanim", -1, curHealth);
LeveledUp();
}
void LeveledUp()
{
if(curLevel!=lastLevel)
{
maxHealth = startHealth + (curLevel * LVI);
curHealth = maxHealth;
lastLevel = curLevel;
}
}
}
$$anonymous$$y next step is to automate the LVI to be a factor of where your current health starts no matter what value it starts at. as of now starting at 0.5f in Healthanimator.play cur health requires 0.01 LVI in order to achieve 100 levels perfectly. this seems problematic if you want to start with much lower health you would have to guess where to decrease the LVI.
$$anonymous$$ade some changes to the code
using UnityEngine;
using System.Collections;
public class AnimPlayer : $$anonymous$$onoBehaviour {
public Animator Healthanimator;
public int curLevel;
public int lastLevel;
public float LVI;
public float $$anonymous$$Health;
public float maxHealth;
public float animHealth;
public float curHealth;
public float startHealth;
// Use this for initialization
void Awake ()
{
Healthanimator = GetComponent<Animator>();
curHealth = $$anonymous$$athf.Clamp(curHealth,$$anonymous$$Health, maxHealth);
maxHealth = $$anonymous$$athf.Clamp(maxHealth, $$anonymous$$Health, maxHealth);
animHealth = $$anonymous$$athf.Clamp(animHealth, 0.0f, 1.0f);
lastLevel = curLevel;
}
void Start()
{
Healthanimator.speed = 0.01f;
maxHealth = (curLevel * LVI);
curHealth = maxHealth;
animHealth = (curHealth / maxHealth) * animHealth;
//animHealth = startHealth;
}
// Update is called once per frame
void Update ()
{
Healthanimator.Play("Healthanim", -1, animHealth);
animHealth = (curHealth / maxHealth) * animHealth;
LeveledUp();
Healthdrain();
}
void LeveledUp()
{
if(curLevel!=lastLevel)
{
maxHealth = (curLevel * LVI);
curHealth = maxHealth;
lastLevel = curLevel;
}
}
void Healthdrain()
{
if(Input.Get$$anonymous$$eyDown("space"))
{
animHealth = (curHealth / maxHealth) * animHealth;
Debug.Log(animHealth);
}
}
}
this will allow for the health to be larger numbers.
the only thing im missing now. is what i was messing with before.
the equation im missing is how do i make the cur level fractionally increase my animhealth value so that no matter what my animhealth value is if my cur level = 100 then my anim value is 1.
using UnityEngine;
using System.Collections;
public class AnimPlayer : $$anonymous$$onoBehaviour {
public Animator Healthanimator;
public int $$anonymous$$Level;
public int maxLevel;
public int curLevel;
public int lastLevel;
public float LVI;
public float startHealth;
public float $$anonymous$$Health;
public float healthCap;
public float curHealth;
public float maxHealth;
public float Value;
public float animHealth;
// Use this for initialization
void Awake ()
{
healthCap = 560.0f;
Healthanimator = GetComponent<Animator>();
lastLevel = curLevel;
}
void Start()
{
Healthanimator.speed = 0.01f;
maxHealth = startHealth;
curHealth = maxHealth;
Debug.Log(animHealth);
animHealth = maxHealth / healthCap;
}
// Update is called once per frame
void Update ()
{
$$anonymous$$Health = $$anonymous$$athf.Clamp($$anonymous$$Health, 0.0f, 0.0f);
curHealth = $$anonymous$$athf.Clamp(curHealth, $$anonymous$$Health, maxHealth);
maxHealth = $$anonymous$$athf.Clamp(maxHealth, $$anonymous$$Health, healthCap);
healthCap = $$anonymous$$athf.Clamp(healthCap, 560.0f, 560.0f);
$$anonymous$$Level = $$anonymous$$athf.Clamp($$anonymous$$Level, 1, 1);
maxLevel = $$anonymous$$athf.Clamp(maxLevel, 100, 100);
curLevel = $$anonymous$$athf.Clamp(curLevel, $$anonymous$$Level, maxLevel);
lastLevel = $$anonymous$$athf.Clamp(lastLevel, $$anonymous$$Level,maxLevel);
animHealth = $$anonymous$$athf.Clamp(animHealth, $$anonymous$$Health, 1.0f);
Healthanimator.Play("Healthanim", -1, animHealth);
LeveledUp();
Healthdrain();
}
void LeveledUp()
{
if(curLevel!=lastLevel)
{
maxHealth = startHealth + (curLevel * LVI)/7;
curHealth = maxHealth;
lastLevel = curLevel;
animHealth = maxHealth / healthCap;
}
}
void Healthdrain()
{
if(Input.Get$$anonymous$$eyDown("space"))
{
Value = (curHealth / maxHealth) * animHealth;
animHealth = Value;
}
}
}
Ok so i rewrote most of the code and set clamps on some numbers.
using UnityEngine; using System.Collections; public class AnimPlayer : $$anonymous$$onoBehaviour { %|983968741_1|% %|1105396935_2|% public int maxLevel; %|-755123838_4|% %|1919164501_5|% %|404150054_6|% %|1536703899_7|% %|1517856100_8|% public float healthCap; %|-1328951472_10|% public float maxHealth; %|148199203_12|% %|1230242035_13|% %|-955339178_14|% %|1208822319_16|% %|-34147522_17|% %|-277359944_18|% { %|1106205360_20|% %|-2094978461_21|% %|-1708132090_22|% } void Start() { Healthanimator.speed = 0.01f; %|152870073_27|% %|209886245_28|% %|-1231494026_29|% animHealth = maxHealth / healthCap; %|-2069510969_31|% } %|-317370307_33|% %|862696631_34|% %|-1087997622_35|% %|-1079620227_36|% %|111043252_37|% %|-379503036_38|% %|1780132347_39|% %|-1514019991_40|% %|1281760394_41|% %|-1458493548_42|% %|-1881740871_43|% %|1842984761_44|% %|525403864_45|% %|1229612313_46|% %|2104881123_47|% %|1759120269_48|% %|-1058175338_49|% %|1879579863_50|% %|-1257481494_51|% %|890701023_52|% void LeveledUp() %|1338738944_54|% %|1975355425_55|% %|948242119_56|% %|1877468440_57|% %|-975249186_58|% %|631608535_59|% %|1287856505_60|% %|1196453310_61|% } void Healthdrain() %|958419857_64|% %|-737660610_65|% %|1015751528_66|% %|67275021_67|% %|705471506_68|% } %|-1199536741_70|% %|1034225212_71|% }
This code now allows for health expanding Based on Level like $$anonymous$$ingdomHearts.
As well as any shaped Health bar such as a spiral or $$anonymous$$H bar or triangle spiral.
So long as its made from an animation, not sure if movie textures work..
it even drains based on where the health visual is. So you can have a maxed health bar waiting to be revealed but drain from whats currently visible.
The only thing left is to add an equation for allowing health to fill back up upon healing.
If there's Anyone who would like to give it a shot I've pretty much covered the rest.
Answer by Davonafe · Nov 28, 2015 at 02:26 PM
using UnityEngine;
using System.Collections;
public class AnimPlayer : MonoBehaviour {
public Animator Healthanimator;
public int minLevel;
public int maxLevel;
public int curLevel;
public int lastLevel;
public float LVI;
public float startHealth;
public float minHealth;
public float healthCap;
public float curHealth;
public float maxHealth;
public float Value;
public float animHealth;
// Use this for initialization
void Awake ()
{
healthCap = 560.0f;
Healthanimator = GetComponent<Animator>();
lastLevel = curLevel;
}
void Start()
{
Healthanimator.speed = 0.01f;
maxHealth = startHealth;
curHealth = maxHealth;
animHealth = maxHealth / healthCap;
}
// Update is called once per frame
void Update ()
{
minHealth = Mathf.Clamp(minHealth, 0.0f, 0.0f);
curHealth = Mathf.Clamp(curHealth, minHealth, maxHealth);
maxHealth = Mathf.Clamp(maxHealth, minHealth, healthCap);
healthCap = Mathf.Clamp(healthCap, 560.0f, 560.0f);
minLevel = Mathf.Clamp(minLevel, 1, 1);
maxLevel = Mathf.Clamp(maxLevel, 100, 100);
curLevel = Mathf.Clamp(curLevel, minLevel, maxLevel);
lastLevel = Mathf.Clamp(lastLevel, minLevel,maxLevel);
animHealth = Mathf.Clamp(animHealth, minHealth, 1.0f);
Healthanimator.Play("Healthanim", -1, animHealth);
LeveledUp();
Healthdrain();
}
void LeveledUp()
{
if(curLevel!=lastLevel)
{
maxHealth = startHealth + (curLevel * LVI)/7;
curHealth = maxHealth;
lastLevel = curLevel;
animHealth = maxHealth / healthCap;
}
}
void Healthdrain()
{
if(Input.GetKeyDown("space"))
{
Value = (curHealth / healthCap);
animHealth = Value;
}
}
}
this does it all 4 years i have been wanting this. anyone want to test and tell me if its not working correctly.
Answer by AmbientSoda · Oct 02, 2019 at 09:39 PM
I feel what you want to do is primarily with the shader; you use the shader to draw a shape around a point, and then fill polygons with colour or vice versa depending on collisions or boolean states.
So that is the answer so imagine you draw a square with 5 vertices, one vertice in the centre the other four making up the shape of the square.
Then you can create a series of empty squares and rotate between filling sections of the square using the vertic in the centre to fill the triangles (in the square) between vertices with colour - to fill up you hp, and add effects while doing so, or vice versa when damaged. Currently Open GL is a good place to start when buying books as the processes will be similar to a good Unity shader book. And actually it is generally Open GL being used in the background.
Otherwise you have little choice but to use a health bar or code a visual hp system.
I hope that helps - and I struggle to find useful Unity shader tutorials or books, good luck.
Best Wishes
GamesTechnologist
Your answer
Follow this Question
Related Questions
GUI Texture slide down || Clipping mask. 0 Answers
Help with a health bar 0 Answers
Need a simple health script 1 Answer
re historic GUI system 1 Answer
How to make a class that can be accessed from any script in a project. 2 Answers