Circular Life Bar
This shader can represent any stats, such as life or stamina (or both \(°o°)/)
You can change a lot of parameters:
-the percentage of the circle
-all the colors
-the antialiasing (I recommend not using it if you use the pixelation as it makes things weird)
-the pixelation (having the pixel factor to 0 act like there is no pixelation)
-the radius of the ring
-the width of the ring
-the radius of the background
-the starting angle of the ring
-the spacing of the segments
-the angle of the segments
-and of course, the segments count
I used this tutorial to help me create this shader: https://www.youtube.com/watch?v=V5h2ClMUguQ&ab_channel=DevOrenge
I also used a bit of code from this shader: https://godotshaders.com/shader/radial-progress-shader/
Shader code
shader_type canvas_item;
const float PI = 3.141592656;
uniform float removed_segments:hint_range(0., 1.) = 1.;
uniform vec4 ring_color : hint_color = vec4(1);
uniform vec4 bg_color : hint_color = vec4(0,0,0,1);
uniform vec4 bg_line_color : hint_color = vec4(0.5,0.5,0.5,1);
uniform vec4 empty_cell_color : hint_color = vec4(0.25,0.25,0.25,1);
uniform bool antialias = false;
uniform float pixelFactor : hint_range(0,1) = .25;
uniform float radius :hint_range(0, 1) = 0.7;
uniform float line_width :hint_range(0, 1) = 0.21;
uniform float bg_width :hint_range(0, 1) = 0.28;
uniform float start_angle:hint_range(0., 360.) = 0.;
uniform float segment_spacing:hint_range(0., 1.) = 0.05;
uniform float segment_angle:hint_range(0., 1.) = 0.;
uniform int segment_count = 3;
mat2 tex_rotate(float _angle){
return mat2(vec2(cos(_angle), -sin(_angle)), vec2(sin(_angle), cos(_angle)));
}
void fragment(){
vec2 uv;
if(pixelFactor != 0.){
vec2 pixelNumber = vec2(textureSize(TEXTURE, 0)) * pixelFactor;
vec2 pixelated_UV = round(UV * pixelNumber) / pixelNumber;
uv = (pixelated_UV * 2.0 - 1.0) * tex_rotate((-radians(start_angle)));
}else{
uv = (UV * 2.0 - 1.0) * tex_rotate((-radians(start_angle)));
}
float angle = atan(uv.x, uv.y) + PI;
float segment_size = (2. * PI) / float(segment_count);
float segment = abs(sin(mod(angle + PI * 2. * segment_angle + segment_size / 2., segment_size) - segment_size / 2.)) * length(uv) - segment_spacing;
angle -= removed_segments * 2. * PI;
float circle = length(uv) - radius;
float ring = abs(circle) - line_width;
float background = abs(circle) - bg_width;
if(antialias){
ring /= fwidth(circle);
angle /= fwidth(angle);
segment /= fwidth(segment);
background /= fwidth(background);
}else{
ring = ceil(ring);
angle = ceil(angle);
segment = ceil(segment);
background = ceil(background);
}
ring = 1. - ring;
segment = 1. - segment;
background = 1. - background;
ring = clamp(ring,0,1);
angle = clamp(angle,0,1);
segment = clamp(segment,0,1);
background = clamp(background,0,1);
float base_ring = ring;
ring -= angle;
if(segment_count >= 2) ring -= segment;
ring = clamp(ring,0,1);
if(ring > 0.){
COLOR = ring_color;
COLOR.a = ring;
}else{
if(segment >= 1. && base_ring >= 1.){
COLOR = bg_line_color;
}else if(base_ring >= 1.){
COLOR = empty_cell_color;
}else{
COLOR = bg_color;
}
COLOR.a = background;
}
}
What a gigantic chad
Agreed.
I don’t know if you still need help but to set up the shader you can use a texture rect with a white texture on it.
I have a HUD class wich is a singleton with a function “UpdateLifeBar”. So I can call this function inside the player. The Hud have a reference to the life bar so it can modifie the parameters inside the “UpdateLifeBar” function.
I hope it helps you on your journey of making games 🙂
hint_color has been renamed to source_color for those wanting to use it in Godot 4.x