Creating A HUD (Cosplore3D Pt:5)
Tags: go, gamedev, learning
Published: 2024-02-05 23:52:16

## Intro
This is a new series following [Cosplore3D](https://github.com/Chig-Beef/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.
```golang
type Player struct {
	x         float64
	y         float64
	angle     float64
	camera    *Camera
	curLevel  string
	speed     float64
	haste     float64
	health    float64
	weapon    Weapon
}
```
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.
```golang
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
}
```

## 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.
```golang
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 p.health < float64((i+1)*20) {
		continue
	}
	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)
}
```
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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/br43ug39myit5hflly9w.png)

That's pretty good, but now we need to show a weapon on screen.
```golang
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)
}
```
Here's our result.

![Gun on screen](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n6zv6dm7yfi98dm42cp0.png)

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

## Ammo
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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l1r793fxbfdw1cpsn4rq.png)

# Next
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.