Game development using Go and the Ebiten library

Go is a powerful and efficient programming language that can be used to create games. In this article we will look at developing a simple game using the Go language and the Ebiten library for creating 2D games.

What is Ebiten?

Ebiten is a simple and efficient library for creating 2D games in Go. It provides convenient tools for drawing graphics, processing input, and controlling animations.

Installation and configuration

Before you start developing the game, you need to install the Ebiten library. You can do this with the following command:

go get -u github.com/hajimehoshi/ebiten/v2

After installing the library, you are ready to start creating your game!

Example of a “Platformer” game

Let's create a Platformer game where the player controls a character to overcome obstacles.

Step 1: Connecting the necessary packages

package main

import (
	"github.com/hajimehoshi/ebiten/v2"
	"github.com/hajimehoshi/ebiten/v2/ebitenutil"
	"github.com/hajimehoshi/ebiten/v2/inpututil"
	"github.com/hajimehoshi/ebiten/v2/vector"
	"image/color"
)

This block of code imports the necessary packages to work with the Ebiten library. It uses ebiten to create a game, ebitenutil to upload images, inpututil to process keyboard input and vector for drawing graphics.

Step 2: Defining Constants and Variables

const (
	screenWidth  = 2000    // Ширина игрового экрана
	screenHeight = 700     // Высота игрового экрана
)

var (
	playerImage     *ebiten.Image  // Изображение игрока
	backgroundImage *ebiten.Image  // Фоновое изображение
	playerX         = 0            // Координата X игрока на экране
	playerY         = 0            // Координата Y игрока на экране
	jumping         = false        // Флаг прыжка игрока
	jumpVelocity    = 0            // Скорость прыжка игрока
	gravity         = 3            // Сила гравитации
	groundLevel     = 630          // Уровень земли, на котором находится игрок

	obstacleX      = 250  // Координата X первого препятствия
	obstacleY      = 350  // Координата Y первого препятствия
	obstacleWidth  = 40   // Ширина первого препятствия
	obstacleHeight = 40   // Высота первого препятствия

	obstacle2X      = 460  // Координата X второго препятствия
	obstacle2Y      = 350  // Координата Y второго препятствия
	obstacle2Width  = 40   // Ширина второго препятствия
	obstacle2Height = 40   // Высота второго препятствия
)

These constants and variables define gameplay parameters such as screen sizes, player and background images, obstacle coordinates and sizes, and player jump parameters (speed and gravity). They are unchanged during program execution and are used to control gameplay and display of game objects.

Step 3: Define the game structure and methods for updating and rendering it

type Game struct{}

func (g *Game) Update() error {
	// Обновление игрового состояния
}

func (g *Game) Draw(screen *ebiten.Image) {
	// Отрисовка игровых объектов
}

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

This block of code defines the structure Game, which represents the game. Method Update used to update the game state, Draw – for drawing game objects, and Layout – to set screen sizes.

Step 4: Update Game State

func (g *Game) Update() error
{
	if inpututil.IsKeyJustPressed(ebiten.KeyEscape) {
		return nil // Закрываем игру, возвращая nil
	}

	// Управление игроком
	if ebiten.IsKeyPressed(ebiten.KeyLeft) {
		playerX -= 10 // Смещаем игрока влево при нажатии клавиши влево
	}
	if ebiten.IsKeyPressed(ebiten.KeyRight) {
		playerX += 10 // Смещаем игрока вправо при нажатии клавиши вправо
	}
	if ebiten.IsKeyPressed(ebiten.KeyUp) {
		if !jumping { // Если игрок не в состоянии прыжка
			jumping = true     // Устанавливаем флаг прыжка
			jumpVelocity = 50  // Устанавливаем скорость прыжка
		}
	}

	// Прыжок игрока
	if jumping {
		playerY -= jumpVelocity   // Обновляем положение игрока по вертикали
		jumpVelocity -= gravity   // Уменьшаем скорость прыжка из-за гравитации
		if playerY > groundLevel { // Если игрок достиг земли
			playerY = groundLevel  // Устанавливаем его на уровень земли
			jumping = false        // Сбрасываем флаг прыжка
		}
	} else if playerY < groundLevel {
		// Если игрок находится в воздухе выше уровня земли
		playerY = groundLevel // Устанавливаем его на уровень земли
	}

	// Ограничение перемещения игрока в пределах экрана
	if playerX < 0 {
		playerX = 0 // Не даем игроку выйти за левую границу экрана
	}
	if playerX > screenWidth-16 {
		playerX = screenWidth - 16 // Не даем игроку выйти за правую границу экрана
	}
	if playerY < 0 {
		playerY = 0 // Не даем игроку выйти за верхнюю границу экрана
	}
	if playerY > screenHeight-16 {
		playerY = screenHeight - 16 // Не даем игроку выйти за нижнюю границу экрана
	}

	// Проверка коллизий с препятствиями
	if checkCollision(playerX, playerY, 16, 16, obstacleX, obstacleY, obstacleWidth, obstacleHeight) {
		// Если произошла коллизия с первым препятствием
		playerX = obstacleX - 16 // Устанавливаем игрока перед препятствием
		playerY = obstacleY - 16 // Устанавливаем игрока на верхний край препятствия
	}

	if checkCollision(playerX, playerY, 16, 16, obstacle2X, obstacle2Y, obstacle2Width, obstacle2Height) {
		// Если произошла коллизия со вторым препятствием
		playerX = obstacle2X - 16 // Устанавливаем игрока перед вторым препятствием
		playerY = obstacle2Y - 16 // Устанавливаем игрока на верхний край второго препятствия
	}

	return nil
}
//Вспомогательная функция для проверки коллизий
func checkCollision(x1, y1, w1, h1, x2, y2, w2, h2 int) bool {
	return x1 < x2+w2 && x1+w1 > x2 && y1 < y2+h2 && y1+h1 > y2
}

This function updates the game state every frame, processes user input, and updates the player's position based on the keys pressed. It also handles player jumping, gravity, and obstacle collision checking to prevent the player from moving over obstacles. The checkCollision function checks whether two rectangles (the player and the obstacle) intersect in space.

Step 5: Rendering Game Objects

func (g *Game) Draw(screen *ebiten.Image) {
	// Отображение фонового изображения с уменьшением размера в два раза
	op := &ebiten.DrawImageOptions{}
	op.GeoM.Scale(0.8, 0.7) // Уменьшение размера в два раза
	screen.DrawImage(backgroundImage, op)

	// Рисование игрока с уменьшением размера в два раза
	geoM := ebiten.GeoM{}
	geoM.Translate(float64(playerX), float64(playerY))
	geoM.Scale(0.4, 0.4) // Уменьшение размера в два раза
	screen.DrawImage(playerImage, &ebiten.DrawImageOptions{GeoM: geoM})

	// Рисование препятствия 1
	vector.DrawFilledRect(screen, float32(obstacleX), float32(obstacleY), float32(obstacleWidth), float32(obstacleHeight), color.Gray{}, false)

	// Рисование препятствия 2
	vector.DrawFilledRect(screen, float32(obstacle2X), float32(obstacle2Y), float32(obstacle2Width), float32(obstacle2Height), color.Gray{}, false)

}

This feature displays a background image, a player image, and two obstacles on the screen. It uses methods from the Ebiten library to draw images and vector rectangles on the game screen.

Step 6: Launch the game

func main() {
	// Загрузка изображения игрока
	img, _, err := ebitenutil.NewImageFromFile("person.png")
	if err != nil {
		panic(err)
	}
	playerImage = img

	// Загрузка фонового изображения
	backgroundImage, _, err = ebitenutil.NewImageFromFile("Game_Background.png")
	if err != nil {
		panic(err)
	}

	playerX = 50 // Персонаж начинает игру немного правее

	// Запуск игры
	game := &Game{}
	if err := ebiten.RunGame(game); err != nil {
		panic(err)
	}
}
Game Features:

Game Features:

  • Player Control: The player can control the character using the keyboard keys, moving him left, right and jumping.

  • Gravity and jump: There is gravity that affects the character, as well as the ability to perform jumps.

  • Restriction of movement: The player cannot move off the screen.

  • Collisions with obstacles: There are several obstacles in the level and the character cannot pass through them.

Conclusion

As a result of the creation of this game, you received a working prototype with simple mechanics and controls. Even from this simple example, you can see the potential for Ebiten to create more complex games.

you can find full source code for this project on GitHub

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *