Roguelike Devlog

In the few games that I have written I have always had something called the State Machine that handled what was being executed during the main loop. I am unsure where I first picked up this method but it has the following simple interface:

interface StateMachineI {
    Push (s *State)
    Pop (s *State) error
    Replace (s *State) error
    Peek () *State, error
}

type StateMachine struct {
    stack []*State
}

With State being just as simple:

interface State {
    Init (owner StateMachine)
    Update (dt float32)
    Draw (dt float32)
    Destroy (owner StateMachine)
}

When a State is added to the state stack via either Push or Replace its Init function is called. Similarly if its removed via either being replaced or being removed from the head via Pop the states Destroy function is called. This allows each state to manage its dependencies and clean up if needed.

Then within the main function I am able to set up the state engine like so:

func main() {
   sM := StateMachine{stack: make([]*State, 0)}
   sM.Push(NewWelcomeState())

   var dt float32

   for {
       if currentState, e := sM.Peek(); e != nil {
           // You can imagine what this does
           handleError(e) 
       } else {
           currentState.Update(dt)
           currentState.Draw(dt)
       }


       // Calculate dt, sleep to keep constant
       // time, etc.
   }
}

This allows me to have a pause screen loaded like so within the Update method of the calling state:

func (s WorldState) Update (dt float32) {
    if pauseButtonIsPressed() {
        s.owner.Push(NewPauseState())
        return
    }
}

Now the state will look like: [PausedState, WorldState] and the next game loop execution will happen on the PausedState.

Once the user wishes to resume the paused state can Pop itself off the top of the stack and in doing so its Destroy function gets called and the WorldState gets executed on the next loop.


This was probably one of the quickest things I got set up and working in Golang for my game. It has been very useful displaying different scenes, windows and menus.

In case you're wondering, I pass the pointer to a Game struct between states that need access to shared variables by doing s.owner.Push(Inventory(s.Game)). This has the added benefit of keeping the save/load functions within that struct so from the load menu it can create a new instance of Game and using its load function marshal the saved file data before handing it to the WorldState constructor function:

func (s LoadMenu) Update (dt float32) {
    if UserHasSelectedSavedGame() {
        g := &Game{}
        g.Load(filepathname)
        s.owner.Replace(NewWorldState(g))
    }
}

I will be packaging this code into a go library that I will continue to use in future projects and further discuss its utility both here and on my main blog.


🕹️

For a while now I have dabbled in game development. My day to day work involves building web applications and event systems mostly using PHP and Vue.js and so I haven't the systems experience that comes with building desktop applications in languages like C#, Python and Rust.

Over the past few years the folks over at /r/roguelikedev have been hosting an eight week long event where members of the community go through the Complete Roguelike Tutorial and build their own game.

The tutorial focuses on using libtcod with Python and is in my opinion very well written. Teaching is difficult and writing good tutorials is even more so and yet within a few hours I had a working yet basic Roguelike game ready for me to expand upon.

Having completed the tutorial and deciding that Python was maybe one step outside my comfort zone too far I opened a new Golang project to see how much I could get ported into that language. Having no prior experience of game development in either Python or Golang wasn't going to hold me back.

I have in the past used the faiface/pixel library to tinker with game development ideas however for this project I felt that may be too complicated and instead opted to use the gen2brain/raylib-go Go bindings for the Raylib game engine.

Raylib reminds me a lot of the simplicity found in the p5.js project and getting set up was quite easy thanks to the extensive list of examples they provide.

The available Go bindings for libcotd are a good three to five years out of date so I decided that as I was only using libcotd for FOV and font image to tiles; that it should be fairly easy to write something native in Go especially if doing so from the libcotd source.

So here I begin, an adventure in building a game in a language I am learning. This is going to be fun.


🕹️