DEV Community

Cover image for Game -> Playable (Cosplore3D Pt:16)
Chig Beef
Chig Beef

Posted on

Game -> Playable (Cosplore3D Pt:16)


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 InvItems, so we have access to this new property.

type InvItem struct {
    name  string
    image *ebiten.Image
Enter fullscreen mode Exit fullscreen mode

Now that we have these InvItems, 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)
Enter fullscreen mode Exit fullscreen mode

And then we just call this on every InvItem in the player's inventory.

Cosmium showing up in the player's HUD

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
Enter fullscreen mode Exit fullscreen mode

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.

Ammo being front to back

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
Enter fullscreen mode Exit fullscreen mode

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.

Ammo being drawn back to front (the correct way)

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(; row++ {
    for col := 0; col < len([row]); col++ {
        if[row][col].code == 4 { // Cosplorer Reactor
  [row][col].imageCols = g.imageColumns["cosplorerReactor"]
Enter fullscreen mode Exit fullscreen mode

After creating an image for an empty reactor, I simply set the image to the regular reactor when the player collides with the trigger.


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.

Top comments (0)