Go является мощным и эффективным языком программирования, который можно использовать для создания игр. В этой статье мы рассмотрим разработку простой игры с использованием языка Go и библиотеки Ebiten, предназначенной для создания 2D игр.
Что такое Ebiten?
Ebiten - это простая и эффективная библиотека для создания 2D игр на языке Go. Она предоставляет удобные инструменты для рисования графики, обработки ввода и управления анимациями.
Установка и настройка
Перед тем как начать разработку игры, вам нужно установить библиотеку Ebiten. Вы можете сделать это с помощью следующей команды:
go get -u github.com/hajimehoshi/ebiten/v2
После установки библиотеки вы готовы начать создавать свою игру!
Пример игры "Платформер"
Давайте создадим игру «Платформер», где игрок управляет персонажем, преодолевая препятствия.
Шаг 1: Подключение необходимых пакетов
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" )
Этот блок кода импортирует необходимые пакеты для работы с библиотекой Ebiten. В нем используются ebiten для создания игры, ebitenutil для загрузки изображений, inpututil для обработки ввода с клавиатуры и vector для рисования графики.
Шаг 2: Определение констант и переменных
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 // Высота второго препятствия )
Эти константы и переменные определяют параметры игрового процесса, такие как размеры экрана, изображения игрока и фона, координаты и размеры препятствий, а также параметры прыжка игрока (скорость и гравитация). Они неизменны в течение выполнения программы и используются для управления игровым процессом и отображением игровых объектов.
Шаг 3: Определение структуры игры и методов ее обновления и отрисовки
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 }
В этом блоке кода определяется структура Game, которая представляет игру. Метод Update используется для обновления игрового состояния, Draw - для отрисовки игровых объектов, а Layout - для установки размеров экрана.
Шаг 4: Обновление игрового состояния
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 }
Эта функция обновляет состояние игры каждый кадр, обрабатывает пользовательский ввод и обновляет положение игрока на основе нажатых клавиш. Она также обрабатывает прыжки игрока, гравитацию и проверку коллизий с препятствиями, чтобы предотвратить перемещение игрока через препятствия. Функция checkCollision проверяет, пересекаются ли два прямоугольника (игрок и препятствие) в пространстве.
Шаг 5: Отрисовка игровых объектов
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) }
Эта функция отображает фоновое изображение, изображение игрока и два препятствия на экране. Она использует методы из библиотеки Ebiten для отрисовки изображений и векторных прямоугольников на экране игры.
Шаг 6: Запуск игры
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) } }

Управление игроком: Игрок может управлять персонажем с помощью клавиш клавиатуры, перемещая его влево, вправо и выполняя прыжки.
Гравитация и прыжок: Есть гравитация, которая воздействует на персонажа, а также возможность выполнять прыжки.
Ограничение перемещения: Игрок не может выйти за пределы экрана.
Коллизии с препятствиями: Есть несколько препятствий на уровне, и персонаж не может пройти сквозь них.
Вывод
В результате создания этой игры вы получили работающий прототип с простой меха��икой и управлением. Даже на основе этого простого примера можно увидеть потенциал Ebiten для создания более сложных игр.
Вы можете найти полный исходный код этого проекта на GitHub