In the previous post we discussed some basics of making a Heads Up Display (HUD for short). In this post we’re going to cover the basics of presenting a health bar in part of your HUD. Again, by way of reminder, we’re using the go programming language and the ebitengine game engine. We’re going to be using the vector package from the ebitengine library to draw out primatives. As well as some basic math that you’ve probably forgotten if you’ve learned it, or don’t know it if you haven’t.
In the previous post we discussed some basics of making a Heads Up Display (HUD for short). In this post we’re going to cover the basics of presenting a health bar in part of your HUD.
Again, by way of reminder, we’re using the go programming language and the ebitengine game engine. We’re going to be using the vector package from the ebitengine library to draw out primatives. As well as some basic math that you’ve probably forgotten if you’ve learned it, or don’t know it if you haven’t.
Before we can really get into drawing a health bar in our HUD, we’re first going to have to set the stage for where this makes sense. In our submarine game, there is a single player ship, this ship has a couple of stats on it. Of interest for this discussion, it has a max health and a current health. We’ll be using these two things for this post. Also, if we want to see any changes to our health bar, we’ll also need some way to simulate a hit which removes health.
Before we look at some code, lets discuss some of the mechanics that our health bar will use for drawing. If you look at the main image above, you’ll see a health bar in the top left of the screen. It is drawn with two rectangles, a green one showing current health, and a red one showing the max health/damage.
If you think about this mathematically, the red bar behind is the whole, the green bar in front is the the part, this sounds an awful lot like a ratio. Now that we know this, lets think about it with regards to drawing on an ebitengine image.
We’ll start by picking an arbitrary width for our max health, this really is up to you, it is just whatever fits well into your game HUD. I picked 300 pixels in the example that I’ll add below. Then we need to pick a location for the top left corner of our max health bar; say 50x50. Then, we can draw our current health at the same location. We can then determine the length of our current health as a ratio of our max health. This can be computed as a ratio (part/whole):
healthRatio := currentHealth/maxHealth
currentHealthWidth := 300 * healthRatio
Let’s take a look at some example code that lays out our health bar as discussed above.
package main
import (
"math/rand"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/vector"
"golang.org/x/image/colornames"
)
const (
maxHealthWidth = 300
)
func main() {
ebiten.SetWindowSize(720, 440)
ebiten.SetWindowTitle("Health - HUD")
game := NewGame()
ebiten.RunGame(game)
}
type Ship struct {
MaxHealth float64
CurrentHealth float64
}
func NewShip() *Ship {
return &Ship{
MaxHealth: 12,
CurrentHealth: 12,
}
}
type Game struct {
ship *Ship
}
func NewGame() *Game {
return &Game{
ship: NewShip(),
}
}
func (g *Game) Update() error {
// Simulating a hit. We get a random number, the % is a modulus operator, if the hit is divisible by 5 we'll decrement some health
hit := rand.Intn(100)
if hit%5 == 0 {
g.ship.CurrentHealth -= 0.23
}
// Once the health goes below zero, we'll just randomly pick a percentage of the max health to fill back up to
if g.ship.CurrentHealth <= 0 {
g.ship.CurrentHealth = g.ship.MaxHealth * rand.Float64()
}
return nil
}
func (g *Game) Draw(screen *ebiten.Image) {
// Adding a new color to the background screen image
screen.Fill(colornames.Aliceblue)
// Assigning a max size for our health bar, and drawing it using vector.DrawFilledRect
vector.DrawFilledRect(screen, 50, 50, float32(maxHealthWidth), 20, colornames.Red, true)
// Using our current health as a ratio of max health to get the width for our current health bar
healthRatio := g.ship.CurrentHealth / g.ship.MaxHealth
currentHealthWidth := maxHealthWidth * healthRatio
vector.DrawFilledRect(screen, 50, 50, float32(currentHealthWidth), 20, colornames.Green, true)
}
func (g *Game) Layout(ow, oh int) (w, h int) {
return 720, 440
}
As you can see in this simple example, it only takes a little bit of math and some basic knowledge of the vector package in the ebitengine project you can easily get started