Health Bar UI

Hi, I would like to know if anyone know how to do Resident Evil 5 Health bar GUI style which doing in circle.

Is there a way to just use 2 pictures or maybe 4 at the most to do this style of health Bar UI.

I read about advanced health bar which is in traditional long rectangle, it only need 2 picture and scale the full health bar and leave the empty health bar under the full health, so it would animate as if the full health is reduced to 0. but mine is circle, and I need to know how to do the scaling or masking so it does the same thing as the rectangle.

Help is really appreciated Thanks

272061--9776--$50_519.png
272061--9777--$17178_1267832743.png_360.png
272061--9778--$resident_evil_5_2_689.jpg

I’m a newbie in scripting, so please be patient to me as well. Thanks

1 Like

I believe the method you’re after is explained in the 3D Platformer Tutorial (Around Page 53) as far as I know the method in the tutorial is the easiest way to do it.

Sorry if this isn’t any help.

thanks for the reply I was going to do 50 pictures of them from full health to 0 health, but a friend of mine said I dont need 50 pictures I can just have few pictures and do masking instead. the Method shown in the pdf is using 6 different pictures for 6 pie, while I will have 50 different pictures, where she said it would make it laggy. I appreciate your answer it makes me a little bit more confident that there is no other way. But I hope there is somebody else who cares to share if they have an idea.

I use the multiple images for mine, and I have about 180 images for (each) of my circles. This is how I did it:

First, I made the bars/circles whatnot in my 3d editor of choice, then animated the bars/circles so that it would appear that they filled up. I rendered the animation out as an image sequence so I would have an individual image for each amount.

Made a helper function to load a specified sequence of images into an array from the Resources folder, so that I didn’t have to click/drag each image into a slot on a texture array:

//loads a sequence of images from Resources folder. Expects images to be numbered from 0001 to (maximum) 9999. 
//Returns the image sequence as an array
//filetype doesn't matter, as Resources.Load doesn't take a filetype (you leave it out of the the name)
public static function LoadSequence(namePrefix : String, length : int) : Array{
	var bars = Array(length);
	var i=0;
	for (i=0;i<length;i++)
	{
		var j = i + 1;
		if (j < 10){
			//Debug.Log("loading " + namePrefix + "000" + j);
			bars[i] = Resources.Load(namePrefix + "000" + j, Texture);
		}
		else if (j < 100){
			//Debug.Log("loading " + namePrefix + "00" + j);
			bars[i] = Resources.Load(namePrefix + "00" + j, Texture);
		}
		else if (j < 1000){
			bars[i] = Resources.Load(namePrefix + "0" + j, Texture);
		}
		else{
			bars[i] = Resources.Load(namePrefix + j, Texture);
		}
	}
	return bars;
}

to use this, I have something like this (EGUI was the script the loader function was in):

private var quarterCircleValues = [];

function Awake() {
    quarterCircleValues = EGUI.LoadSequence("quarterCircleValue_", 180);
}

As you can see, it loads a sequence of images named from quarterCircleValue_0001 to quarterCircleValue_0180 into an array.

Then, I access just the index of the array that I want to based upon the percentage of health/ammo/whatever remaning.

function OnGUI(){
   var smallLeftIndex = Mathf.RoundToInt((quarterCircleValues.length-1)*weaponsController.HandLaserCharge());


   GUI.DrawTexture(Rect (scrWdth - isi, mainpos.y - isi, isi, isi), quarterCircleValues[smallLeftIndex]);
}

It takes a second on starting a level to load all the textures into the array, but once it is done, it’s still quite fast. It looks great too, as it makes the circle smoothly increment/decrement. It is probable you could even speed this up by using a Texture[ ] instead of a general Array, but I’m unsure how to work with those currently.

Thank you for your respond, I will try to do your idea, thanks again

I actually think that you were on the right path with the masking option. You would need the pro version though, because it would require a render to texture.

Sorry, don’t know the math for it. Good luck.

Here’s an idea. Do the red ring as the background, then do the just the green ring over top of it. Give the green ring a gradient on the alpha channel in the direction you want the health meter to go. Assign a Transparent/Cutout shader to the green circle. Drag the cutoff value to make the circle grow and shrink.

Can’t do any of this with the OnGUI stuff. Need to use actual polygons so you can change the shader.

Yes, that’s the way to do it. For example, this (web player). There are two textures; one for the regular graphics (using normal alpha for nice anti-aliasing) and one for the health bar (using alpha cutoff). The health bar’s alpha looks like this:

The non-alpha part of the texture is just a block of solid green.

The code is this:

function Update () {
	renderer.material.SetFloat("_Cutoff", Mathf.InverseLerp(0, Screen.width, Input.mousePosition.x));
}

This is much faster, easier, and less memory-using than having an array of circular textures. :slight_smile:

–Eric

1 Like

Ah, that is an interesting idea. However:

My texture array is capable of changing shape, size, and color. He probably doesn’t need that, but it’s useful to me.

Both methods appear very useful. Thanks for posting them.

yeah thanks everyone for helping

Eric5h5, can you explain better what you did here?

I might be able to help you out here :wink:

Most of the shaders in the Transparent section of the menu use the texture’s alpha channel to create variable transparency in the image. The shaders under Transparent/Cutoff work a bit differently. They compare each pixel’s alpha value with an overall cutoff threshold value. Any pixel with alpha below that threshold is not rendered at all. The point of this is that you can vary the cutoff value from a script and make different parts of the image appear selectively.

In Eric’s example, the circle contains a gradient which varies smoothly from 100% down to near zero alpha. As the cutoff value is reduced, more of the circle will appear and the revealed portion will seem to move around the circle.

I’m using Eric’s style and it works awesome, but…

The problem I’m having with it at the moment is that because the material that gets its alpha altered has to be on an object, I am using a plane with the material set on it.

In front of that plane in my GUI is the texture that surrounds the meter (like the metal ring in Eric’s post). So far, so good, and it works great in the resolution I set it at.

When I change resolutions though, the object size changes (to the new aspect ratio) and the health meter then ends up at the wrong scale. My “ring around” texture scales fine because it’s in an OnGUI, but the meter objects don’t.

So, I’m trying to figure out how to properly scale them to fit directly under their “ring around” GUI textures at whatever resolution someone chooses.

Maybe I’m going about things the wrong way, not sure. Just want to throw it out there in case anyone has a quick solution that I am probably not thinking of.

At any rate, thanks Eric for the idea. It does exactly what I need for our meters.

I ran into the same issue…my first thought is is scale the plane accordingly depending on the resolution. How does the GUI go about it? It’s easy enough to get the resolution that it’s set at but no scaling of the plane I have attempted has came out right.

Anyone have any suggestion on how to scale a gameobject based on resolution like the GUITexture does?

Yep, I’m under the gun right now and have to finish this up so I think I’m going to have to scrap using this method and come up with something else that does the same thing but without the scaling issues. Hopefully someone has a work-around.

Hi guys,

Ok if you do the array of lets say 100 images to make the health meter, but you start at level 1. When you reach level 2, your max health increases to 110. How would you do that using this array images method?

I did it another way so I thought I would share it.

Requires Unity Pro.

Okay all you do is render nothing into a render-texture. Using this image effect.

All you have to do after that is simply do a drawTexture using RT as your texture.

You can obviously set the render Texture dimensions (even 256 x 256) is not that bad.

The script.

using UnityEngine;
[ExecuteInEditMode]

[AddComponentMenu("Image Effects/HealthCircle")]
public class HealthCircleEffect : ImageEffectBase {
	public float radius = 0.5f;
	public Color colorGood;
	public Color colorBad;
	public float health = 0.5f;
	
	public Texture rampTexture;
	public float 	m_angle = 0.2f;
	
	void Start()
	{
		setHealth( health );
	}
	//we except health to be from 0 to 1.
	public void setHealth(float health)
	{
		m_angle = health * 360f;
	}
	void OnRenderImage (RenderTexture source, RenderTexture destination) {
		material.SetColor("m_colorGood",colorGood);
		material.SetColor("m_colorBad",colorBad);
		material.SetFloat("m_angle",m_angle);
		material.SetFloat("m_radius", radius);
		material.SetTexture("rampTexture",rampTexture);
		Graphics.Blit (source, destination, material);
	}
}

Shader

Shader "Hidden/SphereEffectX" {
Properties {
	_MainTex ("Base (RGB)", RECT) = "white" {}
	rampTexture ("Base (RGB)", 2D) = "rampTexture" {}
}

SubShader {
	Pass {
		ZTest Always Cull Off ZWrite Off
		Fog { Mode off }
				
CGPROGRAM
#pragma vertex vert_img
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest 
#include "UnityCG.cginc"

uniform samplerRECT _MainTex;
uniform sampler2D rampTexture;
uniform float _RampOffset;
uniform float m_angle = 0;
uniform float m_radius = .5;
uniform float4 m_colorGood = float4(1,1,0,1);
uniform float4 m_colorBad   = float4(1,0,0,1);
float4 frag (v2f_img i) : COLOR
{
	float4 rc = float4(1,0,0,0);
	float2 distance = i.uv - float2(0.5,0.5);
	float d = length(distance);
	float rad = atan2(distance.y,distance.x);
	
	if(rad < 0)
	{
		rad += (3.14 * 2);
	}
	float angle = (rad * 180) / 3.14;
	if(d < m_radius)
	{
		rc = m_colorGood;
		if(angle > m_angle)
		{
			rc = m_colorBad;
		}
	}
	return rc *tex2D(rampTexture, i.uv);
}
ENDCG

	}
}

Fallback off

}

[/code]

attached a screenshot

335788--11781--$health1_965.png

The “best” solution to get a non linear health bar, in my opinion, is to build a mesh having the shape needed, and then change the UV coords in real time to define what is visible on the bar.
Then you’ll only need to store a simple linear texture, and not be bothered with alpha stuff