You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3.4 KiB

title categories draft
How to create a twin-stick shooter game with Ebiten [tutorial] true


Code for this tutorial is available here.

go get # Download and install
~/go/bin/step-1 # Run


This tutorial explains how to create a basic twin-stick shooter video game using Ebiten.

Note: This tutorial is incomplete.

What are twin-stick shooter video games?

Multidirectional shooters with one joystick for movement and one joystick for firing in any direction independent of movement are called twin-stick shooters.


What is Ebiten?

Ebiten is an open source game library for the Go programming language. Ebiten's simple API allows you to quickly and easily develop 2D games that can be deployed across multiple platforms.

Why use Ebiten instead of ____?

Ebiten's design is simple: each component of the library is contained in its own package.

This requires developers to write a little extra code compared to "batteries included" type frameworks, but Ebiten adheres to the deign principles of Go:

  • Each package operates independently (packages are not tightly coupled)
  • Each package provides a primitive (e.g. audio, image and vector) or utility (e.g. inpututil, )

Step 1: Create a new project

Initialize go.mod file

go mod init

Install Ebiten

go get

Create main.go file

package main

import (


func main() {
	// Set window title.
	ebiten.SetWindowTitle("Step 1 - Twin-stick shooter tutorial")

	// Create a new game.
	game := NewGame()

	// Run the game.
	err := ebiten.RunGame(game)
	if err != nil {

Create game.go file

package main

import ""

// Game represents a twin-stick shooter game.
type Game struct {

// NewGame returns a new Game.
func NewGame() *Game {
	return &Game{}

// Layout is called by Ebiten when the game starts, and every time the game state is updated.
func (g Game) Layout(width, height int) (int, int) {
	// Scale the size of the screen to support high-DPI displays.
	s := ebiten.DeviceScaleFactor()
	return int(s * float64(width)), int(s * float64(height))

// Update is called by Ebiten to update the game state.
func (g Game) Update() error {
	return nil

// Draw is called by Ebiten to draw the game onto the screen.
func (g Game) Draw(screen *ebiten.Image) {
	// We aren't drawing anything yet.

Step 2: Embed and load assets

Audio assets

  • bat sound
Find some assets
Embed assets
Load assets

Image assets

Find some assets
Embed assets
Load assets
  • display sprite

Step 3: Create a level

Random dungeon generator

Add floor and wall sprites

Add prop sprites

Step 4: Add entities

Add items

Add enemies

Step 5: Add game mechanics

Add health and damage system

Add objective

Bat Blaster