Когда я только начал разрабатывать свой тактический футбольный менеджер, встал вопрос о графике. С тем, что игра будет 2D, я определился сразу. А вот как именно должна выглядеть сцена матча — и особенно поле — предстояло решить.

Всё, что я расскажу в этой статье, основано на моём личном опыте. Надеюсь, читатель не сочтёт это саморекламой, а воспримет как живой пример из практики. Если захотите узнать о проекте подробнее — ссылка на другую статью будет в конце.

1. Почему изометрия?

Недолго думая, я пришёл к выводу: чтобы сцена матча выглядела интересно и выигрышно, нужно использовать изометрию. Сочетание пиксель‑арта с изометрией при должном подходе даёт отличный результат.

Коротко об изометрии: это проекция с соотношением сторон 2:1 — стандарт для многих игр.

Тип проекции

Соотношение

Угол

Симметрия

1:1

45°

Изометрия

2:1

~26.565°

Слева - симметрия, справа - изометрия
Слева — симметрия, справа — изометрия

В случае изометрии на футбольном поле можно разместить больше объектов, сохраняя читаемость и объём.

2. Магия изометрии: плоская картинка с глубиной

Перед нами — 2D‑изображение. Но согласитесь: возникает ощущение глубины, будто мы можем заглянуть в этот мир.

С помощью изометрии можно создать целый мир со всеми деталями — и для этого не нужен 3D. Это как мастерство живописца: хорошая работа со светотенью и цветом заставляет воображение зрителя дорисовывать объём. А что ещё нужно для успеха, если не удивление и вовлечённость?

3. Как я разбивал поле на клетки (билинейная интерполяция)

На экране изометрическое поле выглядит как трапеция. Задача — разделить эту трапецию на равные клетки, которые в «реальности» (в игровом мире) были бы одинаковыми прямоугольниками.

Для этого я использую билинейную интерполяцию.

3.1. Сетка на поле

У поля есть 4 угла:

  • A1 — левый верхний

  • A2 — правый верхний

  • B1 — левый нижний

  • B2 — правый нижний

Каждая клетка задаётся координатами (u, v), где:

  • u — положение по горизонтали (0 — левый край, 1 — правый)

  • v — положение по вертикали (0 — верх, 1 — низ)

3.2. Формула

Для любой точки с координатами (u, v):

верхняя_точка = A1 * (1-u) + A2 * u
нижняя_точка  = B1 * (1-u) + B2 * u
результат     = верхняя_точка * (1-v) + нижняя_точка * v

Или одной строкой:

точка = (A1*(1-u) + A2*u)*(1-v) + (B1*(1-u) + B2*u)*v

3.3. Как это работает

Что делаем

Что получаем

Берём u

Находим точку на верхней и нижней границах поля

Берём v

Находим точку между этими границами

В итоге

Получаем координаты любой клетки на поле

Метод даёт ровную сетку, работает с любой трапецией и не требует сложных вычислений.

Пример использования:

  • Чтобы найти центр поля, берём u = 0.5v = 0.5. Формула вернёт координаты центра.

  • Чтобы найти левую верхнюю клетку (если поле поделено на 4 части), берём u от 0 до 0.5, v от 0 до 0.5.

3.4. Код Godot

extends Node2D

@export var cols: int = 2
@export var rows: int = 2

var corners = []

func _ready():
	# Углы поля
	corners = [
		Vector2(0, 0),   # A1 - левый верхний
		Vector2(4, 0),   # A2 - правый верхний
		Vector2(4, 2),   # B2 - правый нижний
		Vector2(0, 2)    # B1 - левый нижний
	]
	
	var field_center = get_point_on_field(0.5, 0.5)
	print("Центр поля: ", field_center)
	
	for row in rows:
		for col in cols:
			var center = get_cell_center(col, row)
			print("Клетка [", col, ",", row, "] центр: ", center)

func get_point_on_field(u: float, v: float) -> Vector2:
	var top = corners[0].lerp(corners[1], u)
	var bottom = corners[3].lerp(corners[2], u)
	return top.lerp(bottom, v)

func get_cell_center(grid_x: int, grid_y: int) -> Vector2:
	var u = (grid_x + 0.5) / cols
	var v = (grid_y + 0.5) / rows
	return get_point_on_field(u, v)

3.5. Таким образом, мы получаем равномерную сетку, идеально совпадающую с границами изометрического поля

4. Вместо заключения

Если статья показалась вам интересной, а мой проект — достойным внимания, буду рад видеть вас в моём сообществе VK. Именно поддержка помогает авторам доводить свои проекты до конца.

Ссылка на сообщество в VK: Plus3S

Ссылка на статью об игре: Уволился. Делаю компьютерную игру / Хабр