Intro
This is a series following Cosplore3D, a raycaster game to learn 3D graphics. This project is part of 12 Months 12 Projects, a challenge I set myself. Now throughout the development of the game, we've been lacking some visual cues that the game is working, so we're going to add those in.
Picking Up Items
We want items to show up in our HUD, so first, we need an image to show in the HUD. In the case of Cosmium, our only item, this is the same sprite that is used for the 3D world render. Now, the player's inventory shouldn't just be a slice of strings, but a slice of InvItem
s, so we have access to this new property.
type InvItem struct {
name string
image *ebiten.Image
}
Now that we have these InvItem
s, we need a way to draw them.
func (ii *InvItem) draw(screen *ebiten.Image, x, y float64) {
ogW, ogH := ii.image.Size()
op := ebiten.DrawImageOptions{}
op.GeoM.Scale(50/float64(ogW), 50/float64(ogH))
op.GeoM.Translate(x, y)
screen.DrawImage(ii.image, &op)
}
And then we just call this on every InvItem
in the player's inventory.
Perfect, now we can move on to the next improvement.
Shooting Animation
It's really annoying that when you shoot nothing visibly changes other than the ammo amount. This isn't going to be that much of a change, just a simple new image.
But we need to show this image for a few frames after we fire.
if w.animationCounter == 0 {
img = w.image
} else {
img = w.fireImage
}
There wasn't a lot of code to show, but this is the part that decides which image is shows.
Item Drawing Priority
Currently we have an issue.
Sometimes, ammo that is behind other ammo gets drawn after, which causes this effect, so we definitely need to fix this.
This can simply be done by sorting bot the items and the enemies, and for this we're going to use bubble sort.
func (l *Level) sort_enemies_by_distance(c *Camera) {
for i := 0; i < len(l.enemies); i++ {
for j := 0; j < len(l.enemies)-i-1; j++ {
if l.enemies[j].get_distance(c, false) < l.enemies[j+1].get_distance(c, false) {
temp := l.enemies[j]
l.enemies[j] = l.enemies[j+1]
l.enemies[j+1] = temp
}
}
}
}
Now, I know that bubble sort probably isn't the fastest in most cases, however, this might be the one case that it could be decently fast (kind of). The reason for this is that after running it for the first time, the enemies will be sorted, and there's probably only going to be one or two swaps to be made, so in this way bubble sort wins by using simplicity. However, if performance does become an issue it might be a good place to check whether this is actually an issue.
Visually Changing The Reactor
Now, I think it's cool that the Cosmium in our HUD disappears when we get close to the reactor, however, I think we need to visually change the reactor, so that it reflects this change.
l := g.levels[g.player.curLevel]
for row := 0; row < len(l.data); row++ {
for col := 0; col < len(l.data[row]); col++ {
if l.data[row][col].code == 4 { // Cosplorer Reactor
l.data[row][col].imageCols = g.imageColumns["cosplorerReactor"]
}
}
}
After creating an image for an empty reactor, I simply set the image to the regular reactor when the player collides with the trigger.
Next
This game is long due for a menu system. Currently you get thrown into the game without any sort of information about what's happening, so it would useful to maybe have a controls page. It might also be useful to allow the player to start at any level, and implement a level unlocking system so that they can see their progression.