Практическое руководство по разработке игр на Python

Раздел: Разработка на Python -> Создание приложений

Основной подход: библиотека Pygame

Как создать окно и игровой цикл?

Pygame предоставляет модули для работы с графикой, звуком и событиями. Окно создается функцией pygame.display.set_mode(), игровой цикл обрабатывает события и обновляет экран.

import pygame
pygame.init()
screen = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()
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()
    clock.tick(60)
pygame.quit()

Python application py (создание приложения python)

Проблема: окно зависает, если не вызывать pygame.display.flip(). Решение: всегда обновлять экран после отрисовки. Ошибка: забыли инициализировать часы для фиксации FPS - игра работает слишком быстро или медленно.

Как добавить спрайт и управлять его движением?

Спрайты описываются классом pygame.sprite.Sprite. Движение реализуется изменением позиции в ответ на нажатие клавиш.

class Player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.Surface((50, 50))
        self.image.fill((0, 255, 0))
        self.rect = self.image.get_rect(center=(400, 300))
        self.speed = 5
    def update(self):
        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT]:
            self.rect.x -= self.speed
        if keys[pygame.K_RIGHT]:
            self.rect.x += self.speed
        if keys[pygame.K_UP]:
            self.rect.y -= self.speed
        if keys[pygame.K_DOWN]:
            self.rect.y += self.speed

создание игр на языке python (создание игр на python (pygame и др.))

Типичная ошибка: спрайт выходит за границы окна. Решение: добавить проверку self.rect.clamp_ip(screen.get_rect()) или ограничить координаты.

Как реализовать столкновение с помощью группы спрайтов?

Для обнаружения пересечений используется pygame.sprite.groupcollide() или pygame.sprite.spritecollide().

all_sprites = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
# В цикле:
if pygame.sprite.spritecollide(player, enemies, True):
    print('Hit!')

как сделать калькулятор в python (создание калькулятора на python)

Проблема: спрайты не удаляются из группы после столкновения, если параметр dokill равен False. Решение: установить True, если нужно удалить врага.

Как добавить звуковое сопровождение?

Звук загружается через pygame.mixer.Sound(), музыка через pygame.mixer.music.load().

pygame.mixer.init()
shoot_sound = pygame.mixer.Sound('shoot.wav')
shoot_sound.play()

Python создание чата (создание чат-приложения на python)

Ошибка: файл не найден или имеет неподдерживаемый формат. Решение: использовать WAV или OGG, проверить путь.

Как использовать библиотеку Arcade для упрощения разработки 2D-игр?

Arcade предоставляет встроенные классы для спрайтов, физики (прыжки, гравитация) и анимации. Вместо ручного цикла используется класс arcade.Window с методами on_draw() и on_key_press().

import arcade

class MyGame(arcade.Window):
    def __init__(self):
        super().__init__(800, 600, 'Arcade Game')
        self.player = None

    def setup(self):
        self.player = arcade.Sprite('player.png', scale=0.5)
        self.player.center_x = 400
        self.player.center_y = 300

    def on_draw(self):
        arcade.start_render()
        self.player.draw()

    def on_key_press(self, key, modifiers):
        if key == arcade.key.LEFT:
            self.player.change_x = -5
        elif key == arcade.key.RIGHT:
            self.player.change_x = 5

    def update(self, delta_time):
        self.player.update()

MyGame().run()
Типичная ошибка: не вызывается arcade.start_render() в on_draw() - экран остается черным. Решение: всегда начинать отрисовку с этого вызова.

Как создать игру с поддержкой 3D-графики на Python?

Для 3D удобен движок Panda3D. Он предоставляет готовые узлы сцены, камеры и физику. Базовая настройка:

from direct.showbase.ShowBase import ShowBase

class MyApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        self.model = self.loader.loadModel('models/environment')
        self.model.reparentTo(self.render)
        self.model.setScale(0.25)
        self.model.setPos(-8, 42, 0)

app = MyApp()
app.run()
Проблема: модель не отображается, если не указать путь к panda-файлам. Решение: установить переменную среды PANDA_PATHS или указать абсолютный путь.

Как использовать Pyglet для создания игры с собственным OpenGL?

Pyglet - легковесная библиотека для окон, обработки событий и OpenGL. Она не имеет встроенных спрайтов, но дает полный контроль над рендерингом.

import pyglet

window = pyglet.window.Window(800, 600, 'Pyglet')

@window.event
def on_draw():
    window.clear()
    pyglet.graphics.draw(4, pyglet.gl.GL_QUADS,
        ('v2f', (100, 100, 200, 100, 200, 200, 100, 200)),
        ('c3B', (255,0,0, 0,255,0, 0,0,255, 255,255,0))
    )

pyglet.app.run()
Ошибка: не определены вершины или цвета - программа падает. Решение: проверить количество элементов в списке, оно должно соответствовать количеству вершин * размерность.

Ниже приводятся расширенные примеры с полным кодом и описанием результата.

Пример 1: Простая игра «Пинг-понг» на Pygame

Реализация двух ракеток, мяча и счета.

Пример
import pygame
import random

pygame.init()
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()

class Paddle(pygame.sprite.Sprite):
    def __init__(self, x, y):
        super().__init__()
        self.image = pygame.Surface((15, 100))
        self.image.fill((255, 255, 255))
        self.rect = self.image.get_rect(center=(x, y))
        self.speed = 6

    def move(self, up=True):
        if up:
            self.rect.y -= self.speed
        else:
            self.rect.y += self.speed
        self.rect.clamp_ip(screen.get_rect())

class Ball(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.Surface((20, 20))
        self.image.fill((255, 255, 0))
        self.rect = self.image.get_rect(center=(WIDTH//2, HEIGHT//2))
        self.dx = random.choice([-4, 4])
        self.dy = random.choice([-4, 4])

    def update(self):
        self.rect.x += self.dx
        self.rect.y += self.dy
        if self.rect.top <= 0 or self.rect.bottom >= HEIGHT:
            self.dy = -self.dy
        if self.rect.left <= 0 or self.rect.right >= WIDTH:
            self.dx = -self.dx

player1 = Paddle(50, HEIGHT//2)
player2 = Paddle(WIDTH-50, HEIGHT//2)
ball = Ball()

all_sprites = pygame.sprite.Group(player1, player2, ball)

score1 = score2 = 0
font = pygame.font.Font(None, 74)

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    keys = pygame.key.get_pressed()
    if keys[pygame.K_w]:
        player1.move(True)
    if keys[pygame.K_s]:
        player1.move(False)
    if keys[pygame.K_UP]:
        player2.move(True)
    if keys[pygame.K_DOWN]:
        player2.move(False)

    ball.update()

    if ball.rect.colliderect(player1.rect) or ball.rect.colliderect(player2.rect):
        ball.dx = -ball.dx

    screen.fill((0,0,0))
    all_sprites.draw(screen)
    score_text = font.render(f'{score1} : {score2}', True, (255,255,255))
    screen.blit(score_text, (WIDTH//2 - score_text.get_width()//2, 50))
    pygame.display.flip()
    clock.tick(60)

pygame.quit()
Результат: окно 800x600 с двумя белыми ракетками по бокам и желтым мячом. Мяч отскакивает от стен и ракеток. Счет пока не увеличивается (для примера упрощено).

Пример 2: Игра «Змейка» с использованием Arcade

Полноценная игра с коллизиями и управлением стрелками.

Пример
import arcade
import random

CELL_SIZE = 20

class SnakeGame(arcade.Window):
    def __init__(self):
        super().__init__(800, 600, 'Snake')
        self.snake = [(10, 10)]
        self.direction = (1, 0)
        self.food = (random.randint(0, 39), random.randint(0, 29))
        self.game_over = False

    def on_draw(self):
        arcade.start_render()
        for (x, y) in self.snake:
            arcade.draw_rectangle_filled(x*CELL_SIZE + CELL_SIZE/2,
                                         y*CELL_SIZE + CELL_SIZE/2,
                                         CELL_SIZE-2, CELL_SIZE-2,
                                         arcade.color.GREEN)
        arcade.draw_rectangle_filled(self.food[0]*CELL_SIZE + CELL_SIZE/2,
                                     self.food[1]*CELL_SIZE + CELL_SIZE/2,
                                     CELL_SIZE-2, CELL_SIZE-2,
                                     arcade.color.RED)
        if self.game_over:
            arcade.draw_text('Game Over', 250, 300, arcade.color.WHITE, 50)

    def update(self, delta_time):
        if self.game_over:
            return
        head = self.snake[-1]
        new_head = (head[0] + self.direction[0], head[1] + self.direction[1])
        if (new_head in self.snake or
            new_head[0] < 0 or new_head[0] >= 40 or
            new_head[1] < 0 or new_head[1] >= 30):
            self.game_over = True
            return
        self.snake.append(new_head)
        if new_head == self.food:
            self.food = (random.randint(0, 39), random.randint(0, 29))
        else:
            self.snake.pop(0)

    def on_key_press(self, key, modifiers):
        if key == arcade.key.UP and self.direction != (0, -1):
            self.direction = (0, 1)
        elif key == arcade.key.DOWN and self.direction != (0, 1):
            self.direction = (0, -1)
        elif key == arcade.key.LEFT and self.direction != (1, 0):
            self.direction = (-1, 0)
        elif key == arcade.key.RIGHT and self.direction != (-1, 0):
            self.direction = (1, 0)

SnakeGame().run()
Результат: игровое окно с зеленой змейкой, которая движется в заданном направлении, и красной едой. При столкновении с границей или собой игра завершается.

Пример 3: Вращающийся куб в 3D с помощью Panda3D

Создание окна и вращающегося куба с простой анимацией.

Пример
from direct.showbase.ShowBase import ShowBase
from panda3d.core import NodePath, CardMaker, Texture

class CubeApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        self.camera.setPos(0, -10, 5)
        self.cube = self.loader.loadModel('models/box')
        self.cube.reparentTo(self.render)
        self.cube.setScale(2, 2, 2)
        self.taskMgr.add(self.spin, 'spin')

    def spin(self, task):
        self.cube.setHpr(task.time * 50, task.time * 30, 0)
        return task.cont

app = CubeApp()
app.run()
Результат: 3D-окно с вращающимся кубом. Вращение по горизонтали и вертикали с течением времени.

Пример 4: Анимация частиц с использованием Pyglet и OpenGL

Рисование множества движущихся точек.

Пример
import pyglet
from pyglet.gl import *
import random

window = pyglet.window.Window(800, 600, 'Particles')
particles = [(random.randint(0, 800), random.randint(0, 600),
              random.uniform(-1, 1), random.uniform(-1, 1))
             for _ in range(100)]

@window.event
def on_draw():
    glClear(GL_COLOR_BUFFER_BIT)
    glBegin(GL_POINTS)
    for x, y, dx, dy in particles:
        glVertex2f(x, y)
    glEnd()

def update(dt):
    for i, (x, y, dx, dy) in enumerate(particles):
        x += dx
        y += dy
        if x < 0 or x > 800:
            dx = -dx
        if y < 0 or y > 600:
            dy = -dy
        particles[i] = (x, y, dx, dy)

pyglet.clock.schedule_interval(update, 1/60)
pyglet.app.run()
Результат: окно с 100 точками, которые движутся и отскакивают от границ, имитируя частицы.

Создание игр на Python (Pygame и др.) - comments

En
создание игр на языке python (python)