DEV Community

Chig Beef
Chig Beef

Posted on

Creating A HUD (Cosplore3D Pt:5)


This is a new series following Cosplore3D, a raycaster game to learn 3D graphics. This project is part of 12 Months 12 Projects, a challenge I set myself.
In the last post we added enemies (that are visible through walls), but now we need to start dealing with them, so in this post we will be working on a HUD.

Changing The Player

Since we're adding a new feature it's going to impact the Player, so we need to add a few properties.

type Player struct {
    x         float64
    y         float64
    angle     float64
    camera    *Camera
    curLevel  string
    speed     float64
    haste     float64
    health    float64
    weapon    Weapon
Enter fullscreen mode Exit fullscreen mode

All we added was health and a weapon. Now, we don't have this weapon type, se we're going to have to create one.

type Weapon struct {
    damage float64
    rof    uint8 // Rate Of Fire - How many frames between shots
    mag    uint8 // Magazine - How many bullets the weapon can hold
Enter fullscreen mode Exit fullscreen mode

Drawing A HUD

In DOOM and Wolfenstien3D the HUD is drawn on a bar at the bottom, which is how we are going to do this HUD. The first thing we want is some sort of health visualization. We will start by drawing up some health first.

heartImg := g.images["heart"]
ogW, ogH := heartImg.Size()
newW := (float64(screenHeight)/8.0 - 20)
newH := (float64(screenHeight)/8.0 - 20)

for i := 0; i < 5; i++ {

    if < float64((i+1)*20) {
    op := ebiten.DrawImageOptions{}

    op.GeoM.Scale(newW/float64(ogW), newH/float64(ogH))

    op.GeoM.Translate(10*float64(i+1)+newW*float64(i), float64(screenHeight)/8.0*7+10)

    screen.DrawImage(&heartImg, &op)
Enter fullscreen mode Exit fullscreen mode

This will draw 5 hearts at the bottom of the screen. The lower the health the player has, the less hearts that will appear.

5 Heart images denoting health

That's pretty good, but now we need to show a weapon on screen.

func (w *Weapon) draw(g *Game, screen *ebiten.Image) {
    img := g.images["gun"]
    ogW, ogH := img.Size()
    sW := screenWidth / 6.0 / float64(ogW)
    sH := screenHeight / 4.0 / float64(ogH)

    op := ebiten.DrawImageOptions{}
    op.GeoM.Scale(sW, sH)

    op.GeoM.Translate(screenWidth/2.0-(sW*float64(ogW))/2.0, screenHeight/8.0*7-sH*float64(ogH))

    screen.DrawImage(&img, &op)
Enter fullscreen mode Exit fullscreen mode

Here's our result.

Gun on screen

I know, it doesn't look like a gun, we're just going to pretend like it does, I will change it later.


The last thing we need to show is how much ammo the player has left. We are going to do this with some text. Now there isn't much interesting code so I'm just going to show the result.

A "0" denoting ammo left


The world is looking pretty bleak. Sure, I can add colored blocks in some places when I feel like it, but it would be really great to have images. Because of this, I will have to work on upgrading how levels are stored, by adding more codes and more information, such as ground and sky color.

Top comments (0)