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;
	}
}
Tags
2d, bar, circle, gui, health, pixel, progress, stamina, variable
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

Related shaders

Procedural Circular Progress Bar

Low life flash 2D

Circular Waves 2D

Subscribe
Notify of
guest

5 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Potassium Shot
2 years ago

What a gigantic chad

ZDrener
2 years ago
Reply to  Potassium Shot

Agreed.

Kigadev
Kigadev
1 year ago
how do i connect this shader to my player node
Tarnished
Tarnished
11 months ago

hint_color has been renamed to source_color for those wanting to use it in Godot 4.x