Getting Started With Ebitengine the Go Game Engine

Hopefully you’ve had a chance to get started with setting up your environment and gone over the basic anatomy of a go program. Those two posts are foundational to getting started with the ebitengine game engine. First off, what is a game engine, especially in the case of ebitengine? What is a game engine When you get started bring your dream game into reality, I’m sure that you’re going to want it to run on as many platforms as possible.


Mar. 12, 2024 815 words ebitengine ·

Hopefully you’ve had a chance to get started with setting up your environment and gone over the basic anatomy of a go program. Those two posts are foundational to getting started with the ebitengine game engine.

First off, what is a game engine, especially in the case of ebitengine?

What is a game engine

When you get started bring your dream game into reality, I’m sure that you’re going to want it to run on as many platforms as possible. But a correlation to that is that you’re not going to want to write all of the platform specific code to handle:

  1. Drawing to the screen
  2. Handling sound
  3. Reading hardware input

A game engine abstracts the cross platform realities of handling these features and provides a unified interface that you, as the developer, can program to that interface and the game engine will handle running your game.

Now, as the developer, you just need to learn the interface provided by your game engine, and you can target as many platforms as possible. That is a huge win.

Get the engine

I don’t want to completely reinvent the wheel, so lets first look at the ebitengine install guide (be sure to select your operating system of use at the top, if it isn’t correct). This will give you the steps that you need to install any needed build dependencies, create your game directory, initialize your go.mod file, and the basics needed to have a default game started.

So, jump over there quick, get your game started, and then be sure to come back here.

The initial game

That install guide will give you some go code to run a basic game, lets look at it here.

// Package declaration
package main

// Import statements
import (
	"log"

	"github.com/hajimehoshi/ebiten/v2"
	"github.com/hajimehoshi/ebiten/v2/ebitenutil"
)

type Game struct{}

func (g *Game) Update() error {
	return nil
}

func (g *Game) Draw(screen *ebiten.Image) {
	ebitenutil.DebugPrint(screen, "Hello, World!")
}

func (g *Game) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) {
	return 320, 240
}

// Func main
func main() {
	ebiten.SetWindowSize(640, 480)
	ebiten.SetWindowTitle("Hello, World!")
	if err := ebiten.RunGame(&Game{}); err != nil {
		log.Fatal(err)
	}
}

Required anatomy

If you remember our discussion about go anatomy, there are a few components that are common with each program that we work with.

  1. package declaration
  2. import statements
  3. func main

Each of these are in the code above. They tell the go compiler that we’re in the main package and we have a start to our program with the func main.

The game struct

There is a game struct that is declared. Remember, that a struct is a collection of data. But, we also have 3 (in the case of this example) methods declared on the game struct.

  1. Update
  2. Draw
  3. Layout

These three methods are defined as an interface in the ebitenengine codebase. This is the interface that is required to be satisfied on our game struct, so that it can be passed to the ebiten.RunGame call as seen in our code example above. That run game call has a game created via, &Game{}.

Once you call, RunGame, this will start what is known as the main game loop. It is known as a blocking call. So, unless there is an error, or you stop the game, this loop will run indefinitely.

So, how exactly does this indefinite game loop interact with your game?

The Game Loop

When you call ebiten.RunGame, you pass in an instance of the game defined above. The game loop then interacts with your game via the interface methods defined. The game loop itself may have a lot of different steps, that we don’t really need to know about. These steps can be broken down to:

  1. Update
  2. Draw

Update Step

The game struct that you create, will get the update call. From there, every item within your game, will need to run its update logic. That then implies the update method is the hook into your game logic.

As you build out your game, you’ll need a reference to your game objects from the game object (i.e. player struct, enemy structs, projectile structs etc.). You’ll then run your logic for each of the components of your game here. It is recommended that your game objects have their own update method, which can be called from the main game update method.

Draw Step

The draw step then gets called on each of the game objects. Each object will know where it is located and how to draw itself on the screen (this screen is provided by the game engine each frame).

Conclusion

There is so much to cover with programming in general and a game engine specifically. There is no way that we can cover everything right here. But I hope this discussion gives you enough information to get your thoughts running and a place in the documentation to start learning from your own curiosities.