Как сделать препятствие pygame

Добавил пользователь Валентин П.
Обновлено: 03.10.2024

pygame - это библиотека модулей для языка Python, созданная для разработки 2D игр.

Для того чтобы установить pygame на свой компьютер необходимо открыть командную строку или терминал и написать команду

pip3 install pygame

После установки необходимо создать новый файл и импортировать модуль pygame и написать шаблон игры

Пользователь может взаимодействовать с нашей игрой. Каждое действие пользователя - это некоторое событие , которое мы можем обработать . Выражение pygame.event.get() - это список событий, произошедших в нашей игре.

Цикл for просто перебирает необработанные события. Каждое событие он присваивает переменной event (можно написать любую другую).

Поговорим о цикле while , основном цикле игры . Как часто он выполняется? Очень и очень часто, это зависит от мощности компьютера. Для обновления экрана в играх часто используют 60 кадров в секунду.

Ограничим количество выполнений цикла.

import pygame
from sys import exit

display = pygame.display. set_mode ( ( 800 , 600 ) )

Методу tick() передается желаемое количество кадров в секунду. Задержку он вычисляет сам. На каждой итерации основного цикла игры секунда делится на 60 и на вычисленную величину выполняется задержка.

В библиотеке pygame существует множество функций для рисования различных фигур.

Функция polygon() рисует произвольную фигуру. Она принимает 3 обязательных параметра (поверхность, цвет и кортеж координат) и 1 необязательный (толщину линий).

import pygame
from sys import exit

display = pygame.display. set_mode ( ( 800 , 600 ) )

FPS = 60
clock = pg.time. Clock ()
while True :
f or event in pygame.event. get ():
if event.type == pygame.QUIT:
pygame. quit ()
exit ()

display - наша поверхность

(255, 0, 0) - красный цвет , почитайте про rgb

( (0, 0), (100, 0), (100, 100), (0, 100) ) - координаты вершин квадрата. Возьмите листочек и нарисуйте его координатах (замените сотню на единицу).

Давайте нарисуем треугольник

import pygame
from sys import exit

display = pygame.display. set_mode ( ( 800 , 600 ) )

(0, 0, 255) - синий цвет

((100, 100), (200, 200), (100, 200)) - координаты вершин нашего треугольник.

Самостоятельно нарисуйте пятиугольник (вам помогут карандаш и лист бумаги)

Рисование окружностей

Чтобы нарисовать окружность нужно вызвать метод circle из модуля draw. Команда выглядит так: pygame.draw.circle(display, color, position, radius).

display - поверхность, на которой рисуем

color - цвет, записанный в кортеже из трех чисел. (еще раз про rgb)

position - координаты точки центра окружности ( кортеж из двух чисел (x, y) )

radius - радиус окружности в пикселях

import pygame
from sys import exit

display = pygame.display. set_mode ( ( 800 , 600 ) )

FPS = 60
clock = pg.time. Clock ()
while True :
f or event in pygame.event. get ():
if event.type == pygame.QUIT:
pygame. quit ()
exit ()

display - наша поверхнотсть для рисования

(255, 255, 0) - желтый цвет

(400, 200) - координаты точки центра (в нашем случае 400 пикселей от верхнего левого угла по горизонтали и 200 пикселей по вертикали)

100 - радиус нашей окружности в пикселях

Объявления переменных для цветов

Для нашего с вами удобства давайте объявим несколько переменных, в которые сохраним используемые нами цвета

import pygame
from sys import exit

WHITE = ( 255 , 255 , 255 )
BLACK = ( 0 , 0 , 0 )
PURPLE = ( 156 , 39 , 176 )
INDIGO = ( 63 , 81 , 181 )
BLUE = ( 33 , 150 , 243 )
GREEN = ( 76 , 175 , 80 )
YELLOW = ( 255 , 235 , 59 )
ORANGE = ( 255 , 152 , 0 )
GREY = ( 158 , 158 , 158 )

display = pygame.display. set_mode ( ( 800 , 600 ) )

FPS = 60
clock = pg.time. Clock ()
while True :
f or event in pygame.event. get ():
if event.type == pygame.QUIT:
pygame. quit ()
exit ()

Рисование прямоугольников

Для отрисовки прямоугольников можно использовать метод rect.

pygame.draw.rect(display, color, (x, y, width, height) )

color - цвет (теперь можно просто написать имя переменную)

(x, y, width, height) - кортеж из четырех значений. Первые два значения - это координаты верхнего левого угла прямоугольника, а два последних - это ширина и высота.

import pygame
from sys import exit

WHITE = ( 255 , 255 , 255 )
BLACK = ( 0 , 0 , 0 )
PURPLE = ( 156 , 39 , 176 )
INDIGO = ( 63 , 81 , 181 )
BLUE = ( 33 , 150 , 243 )
GREEN = ( 76 , 175 , 80 )
YELLOW = ( 255 , 235 , 59 )
ORANGE = ( 255 , 152 , 0 )
GREY = ( 158 , 158 , 158 )

display = pygame.display. set_mode ( ( 800 , 600 ) )

FPS = 60
clock = pg.time. Clock ()
while True :
f or event in pygame.event. get ():
if event.type == pygame.QUIT:
pygame. quit ()
exit ()

Если ваша творческая натура требует большего, то вот ссылка на документацию модулю draw

Там можно найти рисование линий, дуг, эллипсов.

Большой пример ( запусти его у себя на компьтере:

В уроке мы научим нашего персонажа прыгать. Прыжок мы сделаем похожим на настоящий, то есть с учетом притяжения объектов. Также мы добавим границы, чтобы игрок не выходил за пределы экрана и всегда оставался в поле зрения.

Видеоурок

При создании игр вам постоянно потребуется продумывать всевозможные алгоритмы и решения, что будут позволять создать необходимый функционал.

В уроке мы не использовали заранее подготовленные методы и решения из каких-либо библиотек. Для создания прыжка мы реализовали все самостоятельно, продумав верный алгоритм.


В первом уроке мы взяли примитивный рогалик, в котором есть только отрисовка карты, один персонаж и возможность ходить стрелками. Описав работу игры на PyGame вкратце, мы поменяли персонажа, серый пол сменили на траву, отредактировали карту.
В этом уроке мы добавим свои объекты в игру, сделаем для них класс и алгоритмы, чтобы отрисовка объектов и персонажа выглядела правильно - нижние объекты перекрывают верхние.


Начнем урок с добавления в скрипты roguelike.py и models.py строки, которая исключит ошибки из-за кириллицы(русских букв в коде).
В самом начале файла models .py добавляем строку, выделенную черным фоном:
И в roguelike.py так же:
После этого комментарии в коде на русском языке, и вообще символы кириллицы перестанут вызывать любые ошибки и проблемы для любых версий Python.


Для удобства ещё уберем с карты игры все тайлы, кроме травы, чтобы не мешались и не портили вид - просто заменяем все 'W' и 'c' в массивах decorationData и tileData на пустые пробелы ' ' . Получаем чистую карту, готовую к добавлению объектов:


Теперь добавим новые tileset-картинки с объектами. (как делать tileset'ы объектов на фотошопе, я опишу в отдельном уроке позже)



При создании объекта указываются:
pos → позиция объекта x,y
objImage → картинка объекта
objName → текстовое имя объекта (по-умолчанию безымянное "unnamed") и
collisionRectSize → высота прямоугольной области коллизий(об этом напишу позже).
Далее создается прямоугольник img_rect (класс pygame.Rect), в который вписана картинка объекта.
Этот Rect[x,y,w,h] является массивом из 4-х чисел, координат x,y, которые сначала равны нулю, и w,h - ширины и высоты картинки объекта.
colorkey получает цвет левого верхнего пикселяфункцией get_at(. ). Полученный цвет используется, как цвет прозрачности в функциях set_colorkey(. ) и mask.from_surface(. ).
Создавая self.img_mask по цвету прозрачности(colorkey), мы получаем маску картинки, в которой все прозрачные пиксели установлены в 0, а непрозрачные - 1. Маска даст возможность столкновения с персонажем и обход объектов.
В конце координаты x,y в img_rect устанавливаются позиции объекта на карте pos, которая передана в аргументах конструктора, чтобы прямоугольник img_rect правильно располагался на экране, вписывая в себя картинку объекта.

Добавляем новые объекты на карту.

randchage(. ) → генерирует случайное число из указанного диапазона
gameObj → наш класс, который мы сделали для своих объектов в файле models.py

Теперь добавляем создание наших новых объектов в функцию:

В этом коде объявляется глобальная переменная global gameObjectList[], доступная во всех остальных функция, в которую мы поместим множество всех созданных объектов. Далее разрезание tileset-картинок на отдельные картинки-объекты и расположение их в случайных местах на карте при помощи функции randrange(. )

Рисуем созданные объекты на игровом экране.


Проверяем работу, и видим, что есть проблема - игрок всегда находится под любым объектом, и сами объекты располагаются поверх друг друга неестественным образом:

Исправим эту проблему, расчитывая нижнюю точку каждого объекта в их массиве gameObjectList[] и сортировку массива по этому признаку.

Рисуем объекты в правильном порядке.

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

Самая нижняя Y-координата для картинки объекта заносится в LowestY.

Теперь файл roguelike.py, добавляем одну строку в функцию

Функция sort(. ) расположит элементы в массиве gameObjectList[] в порядке, соответственном координате lowestY самого нижнего непрозрачного пикселя объекта. Таким образом самые нижние объекты будут рисоваться последними и перекрывать верхние объекты.

Еще нужно добавить отрисовку игрока в соответствии с его Y-координатой. Для этого в конец функции def main ( ) : добавляем две строки:

После этого, игрок и объекты будут правильно отображаться на экране игры, перекрывая друг друга, в соответствии с вертикальным положением на экране:

С помощью класса pygame.Surface можно создавать дополнительные поверхности. После этого отрисовывать их на основной, которая создается методом pygame.display.set_mode(), или друг на друге. Отрисовка выполняется с помощью метода blit().

В pygame поверхности создаются не только вызовом функции display.set_mode() или напрямую вызовом конструктора класса Surface. Также в результате выполнения ряда других функций и методов. Это связано с тем, что поверхности играют важную роль, так как в конечном итоге именно они отображаются на экране. Кроме того они позволяют группировать объекты. Их можно сравнить со слоями в анимации.

При создании экземпляра Surface непосредственно от класса необходимо указать ширину и высоту, подобно тому, как это происходит при вызове set_mode(). Например:

Метод blit() применяется к той поверхности, на которую "накладывается", т. е. на которой "отрисовывается", другая. Другими словами, метод blit() применяется к родительской Surface, в то время как дочерняя передается в качестве аргумента. Также в метод надо передать координаты размещения верхнего левого угла дочерней поверхности в координатной системе родительской. Например:

Здесь sc – основная поверхность. К ней применяется метод blit(), который на sc в ее координате 50x20 прорисовывает поверхность surf.

Пример полного кода:

Поверхности можно делать прозрачными с помощью их метода set_alpha(). Аргумент меняется от 0 (полная прозрачность) до 255 (полная непрозрачность).

Если бы на surf располагались графические объекты, то они также стали бы полупрозрачными.

Кроме blit() и set_alpha() у поверхностей есть множество других методов. Некоторые из них будут упомянуты позже.

Если не принимать во внимание функции модуля pygame.draw, то все, что рисуется на поверхностях, делается с помощью метода blit().

Чтобы проиллюстрировать, что поверхности – это своего рода слои, запрограммируем анимацию одной поверхности (красной) на фоне другой (зеленой). Последняя может смещаться по оси y при клике мышью. При этом красный квадрат всегда будет двигаться ровно по центру по горизонтали зеленой поверхности, но не оконной.

Обратите внимание на комментарий. Сначала hero прорисовывается на background. Потом background прорисовывается на sc. Если сделать наоборот, т. е. две строчки кода поменять местами, то при обновлении окна красного квадрата вы не увидите. Потому что в этом случае на sc отрисуется "старая версия" background, когда на нем еще не было hero.

Также отметим последовательность прорисовок в главном цикле игры. Сначала заливаются оба фона, иначе на них останется "след" от предыдущей итерации цикла. Далее надо заново наложить на каждый слой дочернюю для него поверхность. После этого все окно обновляется функцией update().

Рассмотрим более сложный пример. Напишем программу, в которой окно условно разделено на две половины. Если пользователь кликает по его левой части, то здесь запускается анимация. Если кликает по правой, то активность появляется здесь, при этом анимация на другой половине должна останавливаться. Пусть действием будет "взлет ракеты".

Поскольку похожих объектов будет как минимум два, то уместно написать свой класс, от которого создавать эти объекты.

Заметим, что когда вызывается draw.rect() в качестве первого аргумента передается не главная оконная поверхность, а та, которая принадлежит ракете.

Практическая работа

Напишите код анимационного движения экземпляра Surface, на котором размещены несколько геометрических примитивов, нарисованных функциями модуля draw(). Этим примером иллюстрируется группировка графических объектов.

Курс с примерами решений практических работ:
android-приложение, pdf-версия

Это последняя из пяти частей туториала, посвящённого созданию игр с помощью Python 3 и PyGame. В четвёртой части мы научились распознавать коллизии, реагировать на то, что мяч сталкивается с разными игровыми объектами и создали игровое меню с собственными кнопками.

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

Конец игры

Рано или поздно игра должна закончиться. В этой версии Breakout игра заканчивается одним из двух способов: игрок или теряет все свои жизни, или разрушает все кирпичи. Следующего уровня в игре нет (но его легко можно будет добавить).

Game Over!

Полю game_over класса Game присваивается значение False в методе __init__() класса Game. Основной цикл продолжается до тех пор, пока переменная game_over не изменит значение на True:

Всё это происходит в классе Breakout в следующих случаях:

  • Игрок нажимает в меню на кнопку QUIT.
  • Игрок теряет последнюю жизнь.
  • Игрок разрушает все кирпичи.

В обоих случаях используется функция show_message() . Она отображает текст поверх текущего экрана (игра приостанавливается) и ждёт несколько секунд, прежде чем вернуться. В следующей итерации игрового цикла проверка поля game_over определит, что оно равно True, после чего программа завершится.

Вот как выглядит функция show_message() :

Сохранение рекордов между играми

Добавление звуковых эффектов и музыки

Игры — это аудиовизуальный процесс. Во многих играх есть звуковые эффекты — короткие аудиофрагменты, воспроизводимые при убийстве игроком монстров, нахождении сокровища или ужасной смерти. В некоторых играх также есть фоновая музыка, которая вносит свой вклад в атмосферу. В Breakout есть только звуковые эффекты, но я покажу вам, как воспроизводить музыку в ваших играх.

Звуковые эффекты

Для воспроизведения звуковых эффектов нам потребуются звуковые файлы (как и в случае с файлами изображений). Эти файлы могут иметь формат .wav, .mp3 или .ogg. Breakout хранит свои звуковые эффекты в папке sound_effects :

Давайте посмотрим, как эти звуковые эффекты загружаются и воспроизводятся в нужное время. Во-первых, для воспроизведения звуковых эффектов (или фоновой музыки) нам нужно инициализировать звуковую систему Pygame. Это делается в классе Game: pygame.mixer.pre_init(44100, 16, 2, 4096)

Затем в классе Breakout все звуковые эффекты загружаются из config в объект pygame.mixer.Sound и хранятся в словаре:

Теперь мы можем воспроизводить звуковые эффекты, когда происходит что-то интересное. Например, когда мяч ударяется об кирпич:

Звуковой эффект воспроизводится асинхронно, то есть игра не приостанавливается во время его звучания. Одновременно могут воспроизводиться несколько звуковых эффектов.

Воспроизведение фоновой музыки

Фоновая музыка должна воспроизводиться постоянно. Теоретически, можно создать очень долгий звуковой эффект, но чаще всего применяют зацикленное воспроизведение фоновой музыки. Музыкальные файлы могут иметь формат .wav, .mp3 или .midi. Вот как реализуется музыка:

Одновременно может играть только одна фоновая музыка. Однако поверх фоновой музыки может воспроизводиться несколько звуковых эффектов. Именно это называется микшированием.

Добавление расширенных возможностей

Давайте сделаем что-то любопытное. Разрушать кирпичи мячом интересно, но довольно быстро надоедает. Как насчёт общей системы спецэффектов? Мы разработаем расширяемую систему спецэффектов, связанную с некоторыми кирпичами, которая активируется при ударе мяча об кирпич.

Вот каким будет план. У эффектов есть время жизни. Эффект начинается, когда разрушается кирпич и заканчивается, когда завершается время действия эффекта. Что случится, если мяч ударится об другой кирпич со спецэффектом? В теории, можно создать сочетаемые эффекты, но чтобы упростить всё в исходной реализации активный эффект будет останавливаться, а новый эффект занимать его место.

Система спецэффектов

Спецэффект в наиболее общем случае можно определить как две функции. Первая функция активирует эффект, а вторая сбрасывает его. Мы хотим прикрепить эффекты к кирпичам и дать игроку чётко понять, какие из кирпичей являются особенными, чтобы они могли попробовать ударять их или избегать их в определённые моменты.

Наши спецэффекты определяются словарём из модуля breakout.py. Каждый эффект имеет имя (например, long_paddle) и значение, которое состоит из цвета кирпича, а также две функции. Функции задаются как лямбда-функции, берущие экземпляр Game, в который включается всё, что может изменять спецэффект в Breakout.

При создании кирпичей им может назначаться один из спецэффектов. Вот код:

Класс Brick имеет поле effect, которое обычно имеет значение None, но может (с вероятностью в 30%) содержать один из определённых выше спецэффектов. Заметьте, что этот код не знает о том, какие эффекты существуют. Он просто получает эффект и цвет кирпича и при необходимости назначает их.

В этой версии Breakout я выполняю срабатывание эффектов только при ударе об кирпич, но можно придумать и другие варианты срабатывания событий. Предыдущий эффект сбрасывается (если он существовал), а затем запускается новый эффект. Функция сброса и время запуска эффекта хранятся для будущего использования.

Если новый эффект не запущен, нам всё равно нужно сбросить текущий эффект после срока его жизни. Это происходит в методе update() . В каждом кадре функция сброса текущего эффекта назначается полю reset_effect . Если время после запуска текущего эффекта превышает длительность эффекта, то вызывается функция reset_effect() , а поле reset_effect принимает значение None (означающее, что в данный момент нет активных эффектов).

Увеличение ракетки

Эффект длинной ракетки заключается в увеличении ракетки на 50%. Её функция сброса возвращает ракетку к обычным размерам. Кирпич имеет цвет Orange:

Замедление мяча

Ещё один эффект, помогающий в погоне за мячом, заключается замедлении мяча, то есть уменьшении его скорости на одну единицу. Кирпич имеет цвет Aquamarine.

Больше очков

Если вы хотите больших результатов, то вам понравится эффект утроения очков, дающий по три очка за каждый разрушенный кирпич вместо стандартного одного очка. Кирпич имеет цвет dark green.

Дополнительные жизни

Наконец, очень полезным эффектом будет эффект дополнительных жизней. Он просто даёт вам ещё одну жизнь. Для него не нужен сброс. Кирпич имеет цвет gold.

Возможности, которые можно добавить в будущем

Существует несколько логичных направлений для расширения Breakout. Если вам интересно попробовать себя в добавлении новых возможностей и функций, то вот несколько идей.

Переход на следующий уровень

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

Второй мяч

Эффект временного добавления второго мяча создаст огромный хаос. Сложность здесь в том, чтобы обрабатывать оба мяча как равные, вне зависимости от того, какой из них является исходным. Когда один мяч пропадает, игра продолжается с единственным оставшимся. Жизнь при этом не теряется.

Сохраняющиеся рекорды

Когда у вас есть уровни с увеличивающейся сложностью, желательно создать таблицу рекордов. Можно хранить рекорды в файле, чтобы они сохранялись после игры. Когда игрок побивает рекорд, можно добавить маленькие пиццы или позволить ему написать имя (традиционно всего из трёх символов).

Бомбы и бонусы

В текущей реализации все спецэффекты связаны с кирпичами, но можно добавить эффекты (хорошие и плохие), падающие с неба, которые игрок может собирать или избегать.

Подведём итог

Разработка Breakout с помощью Python 3 и Pygame оказалась очень увлекательным занятием. Это очень мощное сочетание для создания 2D-игр (и для 3D-игр тоже). Если вы любите Python и хотите создавать собственные игры, то не колеблясь выбирайте Pygame.

Я совершенно точно буду создавать на Python и Pygame и другие игры.

Наконец, помните, что у нас есть много контента для Python, доступных для покупки и для изучения на Envato Market.

Читайте также: