Создаем гоночную игру на Python: от базового шаблона до финала
Для кого эта статья:
- Новички в программировании, интересующиеся созданием игр на Python
- Студенты и самоучки, желающие улучшить свои навыки программирования через практику
Люди заинтересованные в разработке игр, которые хотят ознакомиться с основами использования библиотеки Pygame
Разработка гоночной игры на Python — отличная возможность превратить теоретические знания программирования в осязаемый проект, который действительно работает и приносит удовольствие. Помню, как я сам впервые запустил свою примитивную гонку: всего пара пикселей, изображающих автомобиль, неуклюжее управление стрелочками — но восторг был неподдельным! 🏎️ В этом руководстве мы пройдём все этапы создания гоночной игры: от базовой настройки игрового окна до финальной полировки геймплея. Неважно, новичок вы или уже имеете опыт — этот проект станет идеальной площадкой для применения навыков Python в реальном проекте.
Мечтаете создавать собственные игры, но не знаете, с чего начать? Обучение Python-разработке от Skypro — ваш билет в мир программирования! Наш курс специально разработан для превращения новичков в профессионалов, способных создавать всё: от простых скриптов до полноценных игр. Вы не просто изучите синтаксис — вы научитесь мыслить как разработчик, решать реальные задачи и воплощать свои идеи в код.
Создание гонок на Python: основы и необходимые инструменты
Прежде чем погрузиться в создание гонок на Python, необходимо подготовить инструментарий. Pygame — это библиотека, которая превращает Python из языка для анализа данных и веб-разработки в полноценный инструмент для создания игр. Она предоставляет функции для работы с графикой, звуком и устройствами ввода, делая разработку игр доступной даже для начинающих программистов. 🛠️
Для начала установим необходимые компоненты. Откройте командную строку или терминал и введите:
pip install pygame
После установки библиотеки, давайте напишем базовый шаблон игры, который послужит фундаментом для нашей гоночной игры:
import pygame
import sys
# Инициализация Pygame
pygame.init()
# Настройка окна
screen_width = 800
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("Гоночная игра на Python")
# Основной игровой цикл
running = True
while running:
# Обработка событий
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Логика игры
# Отрисовка
screen.fill((0, 0, 0)) # Заливка экрана черным цветом
pygame.display.flip() # Обновление экрана
# Ограничение FPS
pygame.time.Clock().tick(60)
# Завершение работы
pygame.quit()
sys.exit()
Этот код создаёт базовое окно игры с черным фоном, обрабатывает событие закрытия окна и поддерживает стабильную частоту кадров в 60 FPS.
Помимо Pygame, вам понадобятся графические ресурсы для вашей игры. Для начала можно использовать простые фигуры, которые предоставляет Pygame, но для более привлекательной игры стоит подготовить следующие элементы:
- Спрайты автомобилей (для игрока и, возможно, соперников)
- Текстуры дороги и окружения
- Препятствия и бонусы
- Элементы интерфейса (счетчик скорости, таймер, очки)
| Библиотека | Назначение | Сложность освоения |
|---|---|---|
| Pygame | Основная библиотека для создания игр | Средняя |
| NumPy | Работа с векторами для физики движения | Высокая |
| PIL/Pillow | Обработка изображений | Низкая |
| Pygame-GUI | Создание пользовательского интерфейса | Средняя |
Алексей Петров, разработчик игр на Python
Помню свой первый опыт создания гоночной игры на Python. Я был уверен, что справлюсь за выходные — ведь как сложно может быть нарисовать машинку и заставить её двигаться? Спустя месяц кропотливой работы я понял, что недооценил задачу. Самым сложным оказалось не создание графики или написание кода движения, а настройка физики, которая бы ощущалась естественной. Машина либо двигалась как по рельсам, либо становилась неконтролируемой.
Переломный момент наступил, когда я начал смотреть на проблему как на систему векторов и сил. Вместо того чтобы напрямую менять координаты при нажатии клавиш, я реализовал ускорение, трение и поворот с учётом инерции. Добавил небольшую задержку между нажатием и поворотом машины. Это мгновенно преобразило ощущения от игры! Теперь когда студенты спрашивают меня о создании гоночных игр, я всегда советую им начинать с простой физики, а затем постепенно усложнять её, прислушиваясь к тому, как игра ощущается.

Настройка игрового окна и подготовка графических ресурсов
Правильная настройка игрового окна — это первый шаг к созданию увлекательной гоночной игры. Игровое окно должно иметь оптимальное разрешение, которое обеспечит хороший баланс между качеством изображения и производительностью. 🖥️
Давайте расширим базовый шаблон, добавив систему загрузки и управления графическими ресурсами:
import pygame
import os
import sys
# Инициализация и настройки окна (как в предыдущем примере)
pygame.init()
screen_width = 800
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("Гоночная игра на Python")
# Создаем класс для управления ресурсами
class ResourceManager:
def __init__(self):
self.images = {}
self.sounds = {}
def load_image(self, name, path, scale=1):
fullpath = os.path.join('assets', 'images', path)
try:
image = pygame.image.load(fullpath).convert_alpha()
if scale != 1:
w, h = image.get_width(), image.get_height()
image = pygame.transform.scale(image, (int(w * scale), int(h * scale)))
self.images[name] = image
return image
except pygame.error as e:
print(f"Не удалось загрузить изображение: {fullpath}")
print(f"Ошибка: {e}")
return None
def get_image(self, name):
return self.images.get(name)
# Создаем экземпляр менеджера ресурсов
resources = ResourceManager()
# Загружаем изображения
car_image = resources.load_image('player_car', 'car.png', scale=0.5)
road_image = resources.load_image('road', 'road.png')
background_image = resources.load_image('background', 'background.png')
# Настройка игровых объектов
car_x = screen_width // 2
car_y = screen_height – 100
# Основной игровой цикл
clock = pygame.time.Clock()
running = True
while running:
# Обработка событий
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Отрисовка
if background_image:
screen.blit(background_image, (0, 0))
if road_image:
screen.blit(road_image, (0, 0))
if car_image:
screen.blit(car_image, (car_x, car_y))
pygame.display.flip()
clock.tick(60) # 60 FPS
pygame.quit()
sys.exit()
В этом коде мы создали класс ResourceManager для удобной работы с графическими ресурсами. Это позволяет легко загружать и масштабировать изображения, а также обеспечивает организованный доступ к ним в течение игры.
Для создания качественных графических ресурсов у вас есть несколько вариантов:
- Нарисовать самостоятельно используя графические редакторы (Photoshop, GIMP, Aseprite)
- Использовать бесплатные ресурсы с таких сайтов как OpenGameArt, Kenney.nl или Itch.io
- Создать простые геометрические формы с помощью Pygame (для прототипа)
- Модифицировать существующие ресурсы с соответствующих лицензией
При подготовке графических ресурсов, учитывайте следующие рекомендации:
- Используйте PNG-формат с прозрачностью для спрайтов
- Создавайте ресурсы большего размера, чем требуется — масштабировать вниз всегда легче
- Поддерживайте одинаковый стиль для всех элементов игры
- Используйте отдельные слои для различных элементов (дорога, разметка, препятствия)
- Сохраняйте исходные файлы в высоком разрешении для возможных будущих изменений
Структура папок для вашего проекта может выглядеть так:
racing_game/
├── main.py
├── assets/
│ ├── images/
│ │ ├── cars/
│ │ │ ├── player_car.png
│ │ │ └── enemy_cars/
│ │ ├── background/
│ │ │ ├── road.png
│ │ │ └── scenery.png
│ │ └── ui/
│ │ ├── buttons.png
│ │ └── scoreboard.png
│ └── sounds/
│ ├── engine.wav
│ ├── crash.wav
│ └── music.mp3
├── src/
│ ├── car.py
│ ├── game.py
│ └── utils.py
└── README.md
Такая организация поможет поддерживать порядок по мере роста вашего проекта и облегчит внесение изменений и дополнений в будущем.
Программирование управления и движения автомобиля
Правильное управление автомобилем — ключевой аспект любой гоночной игры. Игрок должен чувствовать отзывчивость и реалистичность движения, что требует внимательного подхода к программированию физики. 🎮
Создадим класс Player, который будет отвечать за управление автомобилем игрока:
class Player:
def __init__(self, x, y, image):
self.x = x
self.y = y
self.image = image
self.speed = 0
self.max_speed = 10
self.acceleration = 0.2
self.deceleration = 0.1
self.turning_speed = 5
self.angle = 0 # Угол поворота в градусах
self.rotated_image = image
self.rect = self.image.get_rect(center=(x, y))
def handle_keys(self):
keys = pygame.key.get_pressed()
# Ускорение и торможение
if keys[pygame.K_UP]:
self.speed = min(self.speed + self.acceleration, self.max_speed)
elif keys[pygame.K_DOWN]:
self.speed = max(self.speed – self.acceleration, -self.max_speed/2)
else:
# Замедление, когда не нажаты клавиши
if self.speed > 0:
self.speed = max(self.speed – self.deceleration, 0)
elif self.speed < 0:
self.speed = min(self.speed + self.deceleration, 0)
# Поворот только когда автомобиль движется
if abs(self.speed) > 0.1:
if keys[pygame.K_LEFT]:
self.angle += self.turning_speed * (self.speed / self.max_speed)
if keys[pygame.K_RIGHT]:
self.angle -= self.turning_speed * (self.speed / self.max_speed)
def update(self):
# Расчет движения на основе скорости и угла
radians = math.radians(self.angle)
dx = -math.sin(radians) * self.speed
dy = -math.cos(radians) * self.speed
self.x += dx
self.y += dy
# Обновление позиции и поворота изображения
self.rotated_image = pygame.transform.rotate(self.image, self.angle)
self.rect = self.rotated_image.get_rect(center=(self.x, self.y))
def draw(self, screen):
screen.blit(self.rotated_image, self.rect.topleft)
Этот класс реализует несколько важных аспектов управления автомобилем:
- Ускорение и замедление с плавными переходами
- Поворот автомобиля в зависимости от скорости (быстрее на высоких скоростях)
- Расчет движения на основе угла и скорости
- Вращение спрайта автомобиля согласно текущему направлению
Теперь интегрируем наш класс Player в основной игровой цикл:
# В начале файла добавим:
import math
# После загрузки ресурсов:
player = Player(screen_width // 2, screen_height – 100, car_image)
# В основном игровом цикле:
while running:
# Обработка событий
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Обновление игровой логики
player.handle_keys()
player.update()
# Отрисовка
if background_image:
screen.blit(background_image, (0, 0))
if road_image:
screen.blit(road_image, (0, 0))
player.draw(screen)
pygame.display.flip()
clock.tick(60)
| Параметр | Эффект на управление | Рекомендуемые значения |
|---|---|---|
| acceleration | Скорость набора скорости | 0.1 – 0.3 |
| deceleration | Скорость замедления | 0.05 – 0.2 |
| max_speed | Максимальная скорость | 5 – 15 |
| turning_speed | Скорость поворота | 3 – 8 |
Настройка этих параметров — процесс итеративный. То, что выглядит хорошо для одной игры, может не подойти для другой. Не бойтесь экспериментировать и подстраивать значения под ощущения, которые вы хотите передать игроку.
Для добавления реализма можно также реализовать:
- Дрифт при резких поворотах на высокой скорости
- Различные типы поверхностей с разным сцеплением
- Физику ускорения, которая зависит от текущей скорости (труднее ускоряться на высоких скоростях)
- Визуальные эффекты, такие как следы от шин или дым при дрифте
Создание трассы и реализация физики столкновений
Хорошо разработанная трасса — сердце гоночной игры. Она должна быть интересной, иметь разнообразные повороты и препятствия, а также корректно обрабатывать столкновения с автомобилем игрока. 🛣️
Существует несколько подходов к созданию трассы:
- Использование готового изображения трассы с определенными маркерами границ
- Программное создание трассы из отдельных сегментов
- Использование системы тайлов для построения различных конфигураций
- Процедурная генерация трассы на основе определенных параметров
Для простоты начнем с первого подхода и создадим класс для обработки трассы и столкновений:
class Track:
def __init__(self, image, boundary_color=(255, 0, 0)):
self.image = image
self.boundary_color = boundary_color
# Создаем маску для обнаружения столкновений с границами
self.mask = pygame.mask.from_surface(self.image)
def draw(self, screen):
screen.blit(self.image, (0, 0))
def check_collision(self, player):
# Получаем позицию игрока относительно трассы
player_x = int(player.x)
player_y = int(player.y)
# Проверяем, находится ли точка на границе трассы
try:
color = self.image.get_at((player_x, player_y))
if color[0:3] == self.boundary_color:
return True
except IndexError:
# Если игрок вышел за пределы изображения
return True
return False
def handle_collision(self, player):
# Упрощенная обработка столкновения – просто остановка и небольшой откат
if self.check_collision(player):
# Уменьшаем скорость и немного отбрасываем назад
player.speed = -player.speed * 0.5
# Откатываем позицию на один шаг назад
radians = math.radians(player.angle)
player.x += math.sin(radians) * player.speed * 2
player.y += math.cos(radians) * player.speed * 2
return True
return False
Теперь создадим изображение трассы. Для простой трассы можно использовать обычное изображение с черной дорогой и красными границами. Важно, чтобы цвет границ точно соответствовал значению boundary_color в классе Track.
Интегрируем класс Track в основной код:
# После загрузки ресурсов:
track_image = resources.load_image('track', 'track.png')
track = Track(track_image, boundary_color=(255, 0, 0))
# В основном игровом цикле, перед отрисовкой игрока:
track.draw(screen)
# После обновления игрока, но до отрисовки:
track.handle_collision(player)
Для более сложной и реалистичной обработки столкновений можно использовать систему на основе маски или многоугольников. Вот улучшенная версия метода check_collision с использованием масок:
def check_collision(self, player):
# Создаем маску для спрайта игрока
player_mask = pygame.mask.from_surface(player.rotated_image)
# Смещение для проверки коллизии
offset_x = int(player.rect.x)
offset_y = int(player.rect.y)
# Проверка перекрытия масок
overlap = self.mask.overlap(player_mask, (offset_x, offset_y))
return overlap is not None
Михаил Соколов, преподаватель программирования
На одном из моих курсов студент по имени Никита разрабатывал гоночную игру, и все шло гладко, пока он не столкнулся с проблемой обнаружения столкновений. Его машина то проезжала сквозь стены, то неожиданно останавливалась на ровной дороге. Он перепробовал десятки подходов — проверку цветов пикселей, простые прямоугольные границы — но результат всегда оставался неудовлетворительным.
Решение пришло неожиданно, когда мы изменили сам подход к трассе. Вместо работы с единым изображением Никита создал две версии трассы: визуальную, которую видит игрок, и "маску столкновений" — невидимое изображение, где каждая область имела свой цвет, соответствующий определенному типу поверхности. Черный для асфальта, красный для границ, зеленый для травы (с пониженным сцеплением) и т.д.
Это изменение не только решило проблему столкновений, но и открыло новые возможности для геймплея. Теперь машина реагировала по-разному на разные поверхности: замедлялась на траве, скользила на льду. А для игрока ничего визуально не изменилось — он по-прежнему видел красивую, детализированную трассу. Этот подход "двойного слоя" стал стандартным приемом для всех последующих проектов студентов курса.
Добавление игровой механики и финальная доработка проекта
На финальном этапе разработки гоночной игры важно добавить элементы, которые превратят её из технической демонстрации в полноценную игру с увлекательным геймплеем. Здесь мы добавим соперников, счетчики времени и очков, а также различные игровые режимы. 🏆
Начнем с создания класса для компьютерных соперников:
class AIOpponent:
def __init__(self, x, y, image, track, waypoints):
self.x = x
self.y = y
self.image = image
self.track = track
self.waypoints = waypoints # Список точек, по которым будет двигаться ИИ
self.current_waypoint = 0
self.speed = 3
self.angle = 0
self.rotated_image = image
self.rect = self.image.get_rect(center=(x, y))
def update(self):
# Получаем текущую целевую точку
target_x, target_y = self.waypoints[self.current_waypoint]
# Рассчитываем направление к целевой точке
dx = target_x – self.x
dy = target_y – self.y
# Рассчитываем угол к целевой точке
target_angle = math.degrees(math.atan2(-dx, -dy))
# Плавно поворачиваем к целевой точке
angle_diff = (target_angle – self.angle + 180) % 360 – 180
if abs(angle_diff) > 2:
self.angle += min(2, max(-2, angle_diff * 0.1))
# Двигаемся вперед
radians = math.radians(self.angle)
self.x -= math.sin(radians) * self.speed
self.y -= math.cos(radians) * self.speed
# Обновляем изображение и прямоугольник
self.rotated_image = pygame.transform.rotate(self.image, self.angle)
self.rect = self.rotated_image.get_rect(center=(self.x, self.y))
# Проверяем, достигли ли мы текущей точки
if math.hypot(dx, dy) < 30:
self.current_waypoint = (self.current_waypoint + 1) % len(self.waypoints)
def draw(self, screen):
screen.blit(self.rotated_image, self.rect.topleft)
Теперь добавим систему подсчета времени и очков:
class GameHUD:
def __init__(self, screen_width, screen_height):
self.screen_width = screen_width
self.screen_height = screen_height
self.font = pygame.font.SysFont('Arial', 24)
self.start_time = pygame.time.get_ticks()
self.score = 0
self.lap = 0
def update(self, player_speed, lap_completed=False):
if lap_completed:
self.lap += 1
self.score += 1000 # Бонус за круг
# Дополнительные очки за скорость
self.score += abs(int(player_speed * 0.1))
def draw(self, screen):
# Рассчитываем прошедшее время
elapsed_time = (pygame.time.get_ticks() – self.start_time) // 1000
minutes = elapsed_time // 60
seconds = elapsed_time % 60
# Отрисовываем информацию
time_text = self.font.render(f'Время: {minutes:02d}:{seconds:02d}', True, (255, 255, 255))
score_text = self.font.render(f'Очки: {self.score}', True, (255, 255, 255))
lap_text = self.font.render(f'Круг: {self.lap}', True, (255, 255, 255))
screen.blit(time_text, (10, 10))
screen.blit(score_text, (10, 40))
screen.blit(lap_text, (10, 70))
Добавим систему контрольных точек для отслеживания прогресса на трассе:
class Checkpoint:
def __init__(self, x, y, width, height, checkpoint_id):
self.rect = pygame.Rect(x, y, width, height)
self.id = checkpoint_id
self.passed = False
def check_passed(self, player_rect):
if not self.passed and self.rect.colliderect(player_rect):
self.passed = True
return True
return False
def reset(self):
self.passed = False
def draw(self, screen, debug=False):
if debug:
pygame.draw.rect(screen, (0, 255, 0) if self.passed else (255, 0, 0), self.rect, 2)
Интеграция всех этих элементов в основной игровой цикл:
# Создаем контрольные точки
checkpoints = [
Checkpoint(400, 200, 50, 100, 0),
Checkpoint(600, 400, 100, 50, 1),
Checkpoint(200, 500, 100, 50, 2),
]
# Создаем путевые точки для ИИ соперников
ai_waypoints = [
(400, 200), (500, 300), (600, 400),
(500, 500), (300, 500), (200, 400),
(200, 200), (300, 150)
]
# Создаем ИИ соперника
opponent_image = resources.load_image('opponent_car', 'opponent_car.png', scale=0.5)
opponent = AIOpponent(300, 200, opponent_image, track, ai_waypoints)
# Создаем игровой HUD
hud = GameHUD(screen_width, screen_height)
# Переменные для отслеживания кругов
current_checkpoint = 0
total_checkpoints = len(checkpoints)
lap_completed = False
# В основном игровом цикле
while running:
# ... (обработка событий)
# Обновление
player.handle_keys()
player.update()
opponent.update()
# Проверка контрольных точек
if checkpoints[current_checkpoint].check_passed(player.rect):
current_checkpoint = (current_checkpoint + 1) % total_checkpoints
if current_checkpoint == 0:
lap_completed = True
# Обновление HUD
hud.update(player.speed, lap_completed)
lap_completed = False # Сбрасываем флаг круга
# Проверка столкновений
track.handle_collision(player)
# Отрисовка
track.draw(screen)
# Отрисовка контрольных точек в режиме отладки
for cp in checkpoints:
cp.draw(screen, debug=True)
player.draw(screen)
opponent.draw(screen)
hud.draw(screen)
pygame.display.flip()
clock.tick(60)
Для финальной доработки проекта рекомендую добавить следующие элементы:
- Меню с возможностью выбора трасс и автомобилей
- Звуковые эффекты для двигателя, столкновений, прохождения контрольных точек
- Систему повреждений автомобиля
- Бонусы и улучшения, которые можно подобрать на трассе
- Таблицу лидеров для отслеживания лучших результатов
- Различные режимы игры (гонка на время, заезд с соперниками, дрифт-режим)
Вот таблица возможных игровых режимов и их особенностей:
| Режим игры | Описание | Особенности реализации |
|---|---|---|
| Гонка на время | Прохождение трассы за минимальное время | Точный таймер, контрольные точки, штрафы за столкновения |
| Гонка с соперниками | Финиширование раньше ИИ-противников | Несколько ИИ-машин, система обгона, позиции в гонке |
| Режим дрифта | Набор очков за дрифт на поворотах | Система подсчета длительности и угла дрифта, множители очков |
| Выживание | Избегание препятствий максимально долго | Процедурная генерация препятствий, прогрессивная сложность |
Помните, что разработка игры — это итеративный процесс. Начните с базовой функциональности, протестируйте её, получите обратную связь и постепенно добавляйте новые возможности. Такой подход поможет создать сбалансированную и увлекательную гоночную игру на Python.
Создание гоночной игры на Python — это гораздо больше, чем просто кодирование. Это творческий процесс, который соединяет математику, физику, графику и игровой дизайн в единое целое. Начав с простой модели движения и базовой трассы, вы можете постепенно расширять проект, добавляя всё более сложные механики и визуальные эффекты. Не бойтесь экспериментировать с параметрами физики и дизайном уровней — именно эти эксперименты помогут вашей игре обрести уникальный характер. И помните: самое ценное в разработке игр — это не конечный продукт, а опыт и знания, которые вы получаете в процессе создания.
Читайте также
- Топ-5 библиотек Python для разработки игр: от 2D до 3D проектов
- Создаем крестики-нолики в Pygame: основы и пошаговая инструкция
- Python для 3D игр: возможности, ограничения, практические решения
- Игровая графика на Python: библиотеки и техники для новичков
- Python для разработки игр: возможности, преимущества, примеры
- Python для разработки онлайн-игр: архитектура, протоколы и инструменты
- Godot и Python: создание игр без изучения нового языка программирования
- Топ-5 графических библиотек Python: возможности и применение
- Топ-15 книг: освоение Python через создание игр для новичков
- Создаем RPG игру на Python: пошаговое руководство для начинающих


