Автор: Афанасьев В. Брагин Н. Ташкин А. Идрисов М.
Теги: языки программирования программирование детское развитие информационные технологии задачи по программированию искусство программирования язык программирования python
ISBN: 978-5-04-222344-0
Год: 2026
УДК 004.43-053.2
ББК 32.973.2-018.2
П35
П35
Python для детей. Играем, чтобы программировать /
Владимир Афанасьев, Никита Брагин, Александр Ташкин,
Мухамет Идрисов. — Москва : Эксмо, 2026. — 304 с. : ил. —
(Программирование для детей).
ISBN 978-5-04-222344-0
«Python для детей. Играем, чтобы программировать» приглашает юных
читателей в увлекательное путешествие вместе с веселыми героями Коди
и Багги. От первых строк кода до собственной игры — простыми шагами
ребенок осваивает основы Python: синтаксис, переменные, циклы, условия
и базовые функции. Множество подробных инструкций и реальных примеров превращают обучение в игру: решай задачки, тестируй идеи, создавай проекты. Подходит для занятий и дома, и в школе: развивает логику,
творческое мышление и уверенность в собственных силах.
УДК 004.43-053.2
ББК 32.973.2-018.2
ISBN 978-5-04-222344-0
© Афанасьев В.В., Брагин Н.С., Идрисов М.И.,
текст, иллюстрации, 2026
© Ташкин А.И., разработка персонажей, 2026
© Оформление. ООО «Издательство «Эксмо», 2026
СОДЕРЖ А НИ Е
ВВЕДЕНИЕ
7
Чем «Python для детей. Играем, чтобы программировать»
отличается от других книг по Python для детей . . . . . . . . . . . . 7
Место книги «Python для детей. Играем,
чтобы программировать» в процессе изучения Python . . . . . . 10
Кому и зачем читать эту книгу . . . . . . . . . . . . . . . . . . . . . . 13
Как пользоваться этой книгой . . . . . . . . . . . . . . . . . . . . . . 16
Почему детям важно учить программирование . . . . . . . . . . . 20
Что такое Python и среда программирования.
Объяснение без сложных слов, но по делу . . . . . . . . . . . . . . 24
Что такое Python и среда программирования . . . . . . . . . . . . 24
Где применяется Python в реальном мире? . . . . . . . . . . . . . . 26
Как настроить среду разработки Python
(Да, это проще, чем установить Майнкрафт с модами) . . . . . . . 28
Как настроить среду разработки Python . . . . . . . . . . . . . . . 28
ЧАСТЬ 1
35
Глава 1.1. Базовые типы данных, арифметические операции.
Переменные . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
Глава 1.2. Логические выражения и операторы . . . . . . . . . . . 42
Глава 1.3. Условия. Ветвление . . . . . . . . . . . . . . . . . . . . . . 45
Глава 1.4. Логические выражения и операторы . . . . . . . . . . . 53
Глава 1.5. Задачи на закрепление материала . . . . . . . . . . . . . 57
Глава 1.6. Ветвление. Условный оператор . . . . . . . . . . . . . . 61
Глава 1.7. «Случайные» числа — r andom, randint, randrange . . . . 66
Глава 1.8. Ошибки и исключения. Обработка исключений . . . . 71
Глава 1.9. Циклы в программировании: цикл while . . . . . . . . . 76
Глава 1.10. Циклы в программировании: цикл for . . . . . . . . . . 83
Глава 1.11. Задачи на закрепление материала . . . . . . . . . . . . . 87
Глава 1.12. Строки . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
Глава 1.13. Списки . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
Глава 1.14. Кортежи . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
Глава 1.15. Словари . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
Глава 1.16. Параметры и аргументы функции . . . . . . . . . . . 109
Глава 1.17. Возврат значений из функции. Оператор return . . . . 113
ЧАСТЬ 2
Глава 2.1. Знакомство с Pygame . . . . . . . . . . . . . . . . . . . .
Глава 2.2. Окно игры и графика . . . . . . . . . . . . . . . . . . . .
Глава 2.3. Управление персонажем . . . . . . . . . . . . . . . . . .
Глава 2.4. Создание игры «Кликер» . . . . . . . . . . . . . . . . . .
Глава 2.5. Движение объектов . . . . . . . . . . . . . . . . . . . . .
Глава 2.6. Работа с графикой . . . . . . . . . . . . . . . . . . . . . .
Глава 2.7. Игра «Крестики-нолики» . . . . . . . . . . . . . . . . . .
Глава 2.8. Анимация в Pygame . . . . . . . . . . . . . . . . . . . . .
Глава 2.9. Звуковое сопровождение . . . . . . . . . . . . . . . . .
Глава 2.10. Создание игры «Змейка» . . . . . . . . . . . . . . . . .
Глава 2.11. Физика в играх . . . . . . . . . . . . . . . . . . . . . . . .
Глава 2.12. Парящая птичка . . . . . . . . . . . . . . . . . . . . . . .
Глава 2.13. Рисование фигур . . . . . . . . . . . . . . . . . . . . . .
119
120
126
133
138
153
157
164
175
184
188
199
203
213
ЧАСТЬ 3
223
Глава 3.1. Знакомство с 3D . . . . . . . . . . . . . . . . . . . . . . .
Глава 3.2. Вид от первого лица . . . . . . . . . . . . . . . . . . . . .
Глава 3.3. Улучшаем вид сцены . . . . . . . . . . . . . . . . . . . . .
Глава 3.4. Мини-карта . . . . . . . . . . . . . . . . . . . . . . . . . .
Глава 3.5. Движение игрока и столкновение
со стенами — к
ак стать настоящим героем . . . . . . . . . . . . .
224
235
243
245
251
Глава 3.6. Физика с помощью pymunk — создаём платформер . . 260
Глава 3.7. Продолжаем игру с физикой —
добавляем сложные взаимодействия! . . . . . . . . . . . . . . . . 265
Глава 3.8. Ren’Py — игровой движок . . . . . . . . . . . . . . . . .
Глава 3.9. Сценарий и создание персонажей . . . . . . . . . . . .
Глава 3.10. Изображения в Ren’Py . . . . . . . . . . . . . . . . . .
Глава 3.11. Музыка в Ren’Py . . . . . . . . . . . . . . . . . . . . . .
Глава 3.12. Выбор в сценарии . . . . . . . . . . . . . . . . . . . . .
276
279
283
286
289
ЗАКЛЮЧЕНИЕ
291
ПРИЛОЖЕНИЕ
294
ОБ АВТОРАХ
300
ВВЕДЕНИЕ
Чем «Python для детей.
Играем, чтобы
программировать»
отличается от других книг
по Python для детей
Если ты держишь в руках эту книгу, значит, скорее всего, у тебя есть
как минимум два вопроса:
1. Почему именно Python?
2. Почему именно «Python для детей. Играем, чтобы программировать»?
С первым всё относительно просто: Python — один из самых дружелюбных языков программирования для начинающих. Он понятный,
гибкий и его синтаксис напоминает разговорную речь. Именно поэтому его часто выбирают как первый язык для обучения.
А вот со вторым вопросом — почему эта книга заслуживает твоего
внимания — давай разбираться подробнее. Особенно учитывая, что
сегодня на книжных полках уже можно найти десятки самоучителей
по Python, включая и вполне достойные. Тем не менее, у «Python
для детей. Играем, чтобы программировать» есть несколько фишек,
которые заметно отличают её от аналогов.
1. Книга с характером: Коди против Багги
Другие книги объясняют синтаксис и предлагают задачи. В «Python
для детей. Играем, чтобы программировать» появляется настоящий
диалог — между персонажами. Коди — твой виртуальный наставник,
разумный и логичный. А Багги — шумный, вредный, иногда нелепый,
но чертовски харизматичный баг, который то и дело врывается в процесс, чтобы всё испортить.
Зачем это? А затем, что программирование — это не скучный набор
правил, а история о борьбе с ошибками, о поиске решений и о том,
что иногда ты сам себе Багги.
Коди и Багги создают эмоциональный рельеф: ты не просто читаешь, ты споришь, удивляешься, ловишь себя на мысли. Это позволяет
лучше запоминать материал и вовлекаться.
7
Введение
2. Не теория ради теории, а живой проект —
своя игра!
Почти каждая книга по Python для детей строится вокруг сухих задач:
«суммируй числа», «нарисуй фигуру», «выведи фразу». Это хорошо,
но увы — быстро утомляет.
«Python для детей. Играем, чтобы программировать» идёт по другому пути: ты учишься писать код на живом игровом проекте. С первой же главы ты создаёшь простую игру. А дальше — по нарастающей.
В процессе ты не просто учишься, ты строишь что-то своё. Это даёт
эффект конструктора: «Вот оно — я это сделал!» И это совсем другое
ощущение от обучения.
3. Pygame как способ визуализировать успех
Многие книги не используют графику вообще или используют её эпизодически. А в «Python для детей. Играем, чтобы программировать»
графика — это не украшение, а учебный инструмент. Мы подключаем
библиотеку Pygame, чтобы буквально видеть, как код оживает.
Поменял переменную — и видишь, как персонаж стал быстрее.
Добавил проверку — и игрок теперь не может пройти сквозь стену. Ты
учишься не в теории, а на картинке. А значит — быстрее осваиваешь
принципы программирования.
4. Уровень сложности растёт не по линейке,
а по спирали
Классическая ошибка учебников — скакать по темам линейно: «вот
тебе переменные, вот тебе циклы, вот тебе строки, а теперь — сюрприз, иди пиши игру».
«Python для детей. Играем, чтобы программировать» имеет другую
структуру. Здесь главы устроены как витки спирали. Каждое новое
понятие возвращает тебя к предыдущим, но на новом уровне. Уже
писал простой if? Отлично, теперь напишем условие с логическим
оператором. Уже работал с циклами? Давай сделаем вложенные.
Уже знаешь списки? Добавим им случайные элементы через random.
Это позволяет не терять нить, не «зависать» на сухой теории
и не забывать, зачем ты вообще всё это учишь.
8
Чем эта книга отличается от других
5. Юмор, метафоры и «живая речь»
Эта книга разговаривает с тобой, а не читает лекции. Здесь не будет фраз вроде «иттерируем по контейнеру, применяя условную
фильтрацию». Тут скорее скажут: «Если твой круг вылез за границу
экрана — это не баг, это Багги, и с ним нужно разбираться!»
Такая подача делает обучение легче, теплее, а главное — понятнее.
Ведь если ты посмеёшься над шуткой о делении на ноль, ты запомнишь
её навсегда. А если ты смеёшься над багом, который создаёт баг, ты
не просто учишься — ты впитываешь культуру программирования.
6. Самостоятельные мини-задания — с подвохом
Да, почти во всех книгах есть упражнения, но в «Python для детей.
Играем, чтобы программировать» они с изюминкой. Вопрос может
быть представлен в виде мини-комикса с Коди и Багги или квеста:
«Как думаешь, что произойдёт, если сделать вот так?..»
Это не просто «вставь пропущенное», это обучение через любопытство. Причём некоторые задания откровенно провокационные —
с багом или ошибкой, которую надо найти. Всё это потому, что настоящие программисты учатся не только писать код, но и отлаживать
его. Здесь ты тренируешь и то, и другое.
7. «Код как история» — с труктурная особенность
В «Python для детей. Играем, чтобы программировать» каждый пример
напоминает сценку. Есть завязка (например, «круг вылез за экран»),
есть решение (вспоминаем про координаты и граничные условия),
есть финал — баг побеждён. Благодаря этому код становится не абстракцией, а частью повествования.
Это особенно важно для детей — они лучше воспринимают информацию через нарратив, а не через схему. Если ты расскажешь
историю, они запомнят и команду, и её смысл.
Место книги «Python
для детей. Играем, чтобы
программировать»
в процессе изучения Python
Условно процесс изучения программирования можно разделить
на три этапа.
1. Первый контакт с кодом — знакомство, интерес, простейшие
конструкции.
2. Фундаментальная база — переменные, условия, циклы, функции, работа с данными.
3. Переход к проектному мышлению —
когда ребёнок (или
взрослый) не просто пишет код, а строит что-то своё: игру,
приложение, визуализацию.
Именно между вторым и третьим этапом чаще всего возникает
пробуксовка.
Книг и курсов, которые охватывают синтаксис и дают «посчитай,
напечатай, нарисуй звёздочку», достаточно. Но далеко не все могут
сделать следующий шаг — перейти от учебных задач к собственным проектам. А ведь именно на этом шаге зажигается внутренний «огонь»: когда
ученик видит, что может создать нечто своё — игру, эффект, анимацию.
Вот здесь и появляется «Python для детей. Играем, чтобы программировать» — как мост от базовых знаний к самостоятельной разработке.
Что было до «Python для детей.
Играем, чтобы программировать»?
Представим типичный путь новичка.
• Он проходит вводный курс на «Учи.ру» или в Scratch.
• Потом пробует Python для простых задач: «найти сумму»,
«вывести квадрат», «проверить делимость».
• Если повезло — пробует Turtle или простую графику. Но дальше начинаются формулы, массивы, ввод-вывод, и вся магия
теряется.
10
Место этой книги в процессе изучения Python
В этот момент многие бросают. Потому что одно дело — учиться
ради оценки. И совсем другое — учиться для того, чтобы построить
игру, где твой круг рисует радугу и разговаривает.
«Python для детей. Играем, чтобы программировать» вовлекает
там, где другие утомляют. Она не начинается с «вот тебе int, вот тебе
str». Она начинается с игры — простой, но твоей.
«Python для детей. Играем, чтобы программировать» — это не «ещё
один самоучитель». Это переходник между миром учебных задач
и миром собственных проектов.
Если сравнивать это с велоспортом:
• учебники по Python — это пособия «как крутить педали»;
• «Python для детей. Играем, чтобы программировать» — это тот
самый момент, когда ты впервые съезжаешь с горки и кричишь: «Да! Я еду сам!»
Книга не заменяет начальное обучение, она его оживляет и превращает в реальный результат.
Как встроить книгу в образовательный маршрут?
1. После 10–15 уроков Python в школе или кружке
Если ребёнок уже изучил:
• что такое переменная,
• как работают if, for, while,
• как создавать функции,
то можно переходить к «Python для детей. Играем, чтобы программировать». Книга поможет закрепить пройденное и применить его на практике, не скатываясь в скучные задачники.
2. В качестве первого проекта
Многие преподаватели сталкиваются с проблемой: как дать
школьнику не просто тему, а проект, где он может быть автором?
Ответ — дать ему «Python для детей. Играем, чтобы программировать». Уже с первой главы он начнёт писать игру, и каждая
новая тема будет реальным апгрейдом его проекта.
3. Как альтернатива учебникам с перегрузом
Некоторые книги (особенно переводные) увязают в терминах:
объектная ориентация, интерфейсы, классы, обёртки. «Python
для детей. Играем, чтобы программировать» — это учебник,
где сначала ты что-то делаешь, а потом понимаешь, что уже
11
Введение
это умеешь — без перегрузки, без слов, от которых у ребёнка
«плавится мозг».
4. Как летний практикум
Отдельный сценарий: использовать книгу как летнюю практику. Пусть ученик за 2 месяца сделает 3–4 игры — это даст
ему фору на весь следующий учебный год. Особенно если он
планирует участвовать в олимпиадах, поступать в IT-классы
или просто хочет «быть программистом».
Что даёт книга в образовательном смысле?
• Устойчивое понимание структуры кода.
Благодаря постоянной работе с проектом, ученик не просто
«знает», что такое if, он понимает, как с его помощью включить
цвет или изменить поведение персонажа.
• Навык самостоятельной работы.
Задания с подсказками, но требуют принятия решений: что
изменить, как улучшить. Это формирует проектное мышление.
• Подготовку к олимпиадному мышлению.
В некоторых главах (например, где используются логические
выражения, работа со списками и случайными числами) заложены паттерны, часто встречающиеся в конкурсных задачах.
• Мотивацию через результат.
Вместо «я решил задачку» — «я создал игру!» Такой подход не только круче, благодаря положительным эмоциям, он позволяет лучше
закрепить знания.
А что потом?
Если ты прошёл «Python для детей. Играем, чтобы программировать» — у тебя есть два пути.
1. Углубиться: перейти к более серьёзным проектам, где ты будешь использовать Pygame, библиотеки машинного обучения, web-разработку на Python (например, с Flask).
2. Преподавать другим: многие дети, пройдя «Python для детей.
Играем, чтобы программировать», начинают объяснять другим основы программирования. Это лучший способ закрепить
знания и почувствовать себя профи.
Кому и зачем
читать эту книгу
Если коротко:
• школьникам — для того чтобы сделать свою первую игру;
• родителям — для того чтобы понять, что «сидит за компом»
не всегда = «тратит время зря»;
• учителям и преподавателям — для того чтобы вдохновить учеников и не загонять их в скучные задачники;
• новичкам-энтузиастам — для того чтобы понять, что учиться
программированию можно даже без «технического» бэкграунда, если материал живой и понятный.
Теперь подробнее. Ведь у каждого — свой вход в эту книгу. У каждого — свои цели.
Для детей и подростков 12+ лет
Это главная аудитория книги. Если ты хоть раз думал:
• «а что, если я сам сделаю игру?»
• «как вообще компьютер понимает, что я ему пишу?»
• «а как заставить круг лететь за мышкой?»
…то ты пришёл по адресу.
Эта книга — твой первый шаг в мир программирования, где ты
будешь не просто писать команды, а строить что-то своё. Тут ты
не только узнаешь, как работают переменные, условия или циклы,
но и поймёшь, как из всего этого сложить настоящее приложение —
свою игру.
Ты увидишь результат уже на первых страницах — и это будет
не «5 баллов за задачу», а «Вау! У меня всё работает!»
13
Введение
Для родителей
Если вы — родитель, который:
• хочет отвлечь ребёнка от бессмысленных игр,
• ищет развивающее занятие или просто не понимает, чем занят
сын/дочь в «этом вашем Питоне»,
то «Python для детей. Играем, чтобы программировать» — отличная
точка входа.
Это не скучный учебник. Это книга с характером, юмором и, главное, с проектным мышлением. Ваш ребёнок будет не просто изучать
команды, а создавать свою игру — с нуля, шаг за шагом.
Плюс: с этой книгой вы можете учиться вместе. Не обязательно
знать программирование. Достаточно желания и немного времени.
Это отличный способ стать ближе к ребёнку в той области, которую
он выбрал сам.
Для учителей, репетиторов,
менторов
Если вы ведёте кружок по программированию, ИТ-класс или просто
обучаете Python на базовом уровне — «Python для детей. Играем,
чтобы программировать» станет вашей опорой.
Книга представляет собой мост между теорией и практикой:
каждый раздел даёт не только объяснение, но и возможность сразу
применить полученные знания, код, задание, проект. Благодаря такому формату вы можете:
• строить занятия на основе главы;
• давать её в качестве домашнего задания;
• использовать куски кода как шаблоны;
• проводить мини-хакатоны на базе главы;
• устраивать соревнования: «кто круче прокачает своего персонажа».
Плюс книги в том, что в ней есть юмор и персонажи — Коди и Багги.
Это значит, что ученик чувствует себя не в классе, а внутри истории.
Такой подход сильно повышает вовлечённость.
14
Кому и зачем читать эту книгу
Для взрослых, которые хотят начать «с нуля»
Забудьте фразу: «Мне уже поздно учиться программированию». Это
не так.
Если вы — взрослый человек, который хочет:
• войти в IT мягко и без боли,
• попробовать, что такое код, без терминов и стресса,
• или просто поиграть в разработчика в свободное время,
эта книга даст вам классный старт.
Пусть оформление ориентировано на школьников — это не делает материал менее полезным. Вы просто научитесь всему быстрее
и легче, чем по «серьёзным» книгам, перегруженным терминологией.
А ещё — здесь есть приколы, примеры, метафоры и готовые игры,
которые действительно работают.
В чём практическая ценность для всех?
•
•
•
•
Вы поймёте, как писать код, чтобы видеть результат на экране.
Научитесь основам Python и Pygame без лишней теории.
Создадите собственную игру — и не одну.
Получите базу, которую можно расширять как в сторону
олимпиад, так и в сторону стартапа.
• И просто почувствуете, что программирование — это не о скуке, а о креативе, стиле и веселье.
Кто точно получит удовольствие от книги
КТО ЧИТАТЕЛЬ
ЧТО ПОЛУЧАЕТ
Ребёнок
из 6–8 класса
Свой первый опыт создания игры
Мама/папа
Возможность провести время с ребёнком
за делом
Учитель
Готовый курс на 20+ занятий
Подросток-геймер
Понимание того, как устроены любимые игры
Взрослый
гуманитарий
Ясную и добрую точку входа в мир Python
Как пользоваться
этой книгой
(в том числе
как заниматься по ней)
Сначала главное — это не та книга, которую нужно «зубрить».
Это книга, с которой нужно кодить.
Не читать всё подряд. Не переписывать всё бездумно. А именно запускать код, менять его, ломать, чинить, радоваться результату
и ругать Багги (ну, в меру вежливо).
Что внутри
Книга состоит из двух больших частей:
• Часть 1 — основы Python
Ты изучаешь переменные, условия, циклы, списки, функции,
исключения и т. д. Но делаешь это не на «котиках и математике»,
а сразу на живом игровом коде. Всё, что ты узнаёшь, можешь
тут же использовать в мини-игре.
• Часть 2 — Pygame: создание игр
Здесь ты не просто узнаёшь, что можно «рисовать круг»,
а делаешь игры: кликеры, змейку, платформер, крестикинолики, леталки и т. п. Каждая задача — это не абстракция,
а твой личный мини-проект.
Структура каждой главы
Практически каждая глава строится по следующему принципу:
1. Мини-история или игровой контекст
Не «учим print», а «давай выведем координаты шарика».
2. Объяснение темы
Коротко, ясно, на примерах. Часто — с метафорами или диалогами Коди и Багги. Потому что скука — наш враг.
16
Как пользоваться этой книгой (в том числе как заниматься по ней)
3. Код
Он сразу рабочий. Запускай, смотри, что происходит. Можно
менять его и получать другие эффекты.
4. Подсказки
Что менять, куда смотреть, как исправить. Помогает не застревать.
5. Задания
От простых («измени цвет») до провокационных («а что, если
добавить ещё одну кисть?»).
6. Итоги + контрольные вопросы
Быстрое повторение для закрепления материала.
Как заниматься по книге — пошагово
1. Готовим среду
Установи Python и Pygame. Если не знаешь как — загляни
в раздел с инструкциями (в книге он есть). Можно использовать:
• Thonny (простой редактор для новичков),
• VS Code (если уже чувствуешь себя немного уверенно),
• или любой онлайн-редактор с Pygame (например, Replit,
но его нужно настраивать).
2. Работай «с руками на клавиатуре»
Не просто читай — переписывай код, запускай, проверяй,
экспериментируй. Книга рассчитана на активное участие.
3. Не бойся ломать
Ошибка — это не провал. Это — встреча с Багги. Он специально мешает тебе, чтобы ты стал сильнее. Учись читать ошибки,
понимать, что не так, и пробовать снова.
4. Меняй код под себя
Хочешь, чтобы кружок был зелёным и прыгал? Сделай!
Хочешь, чтобы кнопка «кликера» взрывалась цветами? Why not!
Книга даёт базу — но финальная игра должна быть твоей.
5. Возвращайся к главам
Некоторые темы перекликаются. Это нормально. Повторение — часть обучения. Циклы могут быть и в 3-й, и в 10-й
главе — просто на разных уровнях сложности.
6. Решай задания (и добавляй свои)
17
Введение
В каждой главе есть несколько заданий. Реши их. Придумай
дополнительные. Покажи другу. Сделай по-своему.
7. Не обязательно идти подряд
Можно читать по порядку. А можно перескочить на следующую главу, если ты уже что-то знаешь. Главное — не терять
нить, что ты создаешь.
Как использовать книгу
в разных режимах
Самостоятельно — один на один с Python
Отличный режим для тех, кто любит учиться в одиночку. Книга ведёт
пошагово, и тебе не нужен наставник — всё объяснено максимально
просто. Главное — не лениться писать код руками.
С родителем / ментором
Один читает, другой кодит. Один пишет, другой проверяет. Книга
подходит для совместной работы, особенно если родитель сам хочет
разобраться в программировании. Иногда дети объясняют родителям,
как всё работает, и это прекрасно.
В группе или кружке
Можно использовать главы как готовые сценарии занятий:
• вводная часть — объяснение темы,
• практическая — кодинг по образцу,
• задания — индивидуальная работа,
• мини-хакатон — кто и как улучшит игру.
Как подступиться к проектам
Каждая игра (например, «Змейка», «Кликер», «Птичка») — это не просто
копирование, а сборка. Как из LEGO.
• Сначала ты видишь, каким должен быть результат.
• Потом получаешь детали (код, пояснения).
• Потом — собираешь.
• А дальше — апгрейд: добавь бонус, врага, музыку.
Так формируется проектное мышление — умение не только выполнять инструкции, но и создавать своё.
18
Как пользоваться этой книгой (в том числе как заниматься по ней)
Чего НЕ нужно делать
•
•
•
•
Не заучивай команды наизусть.
Не пропускай «мелочи» — в них часто спрятаны важные идеи.
Не думай, что «ошибка = конец». Это только начало.
Не бойся переписывать или изменять код — это путь к пониманию.
Финальный совет от Коди
«Читать книгу и ничего не запускать — это как учиться плавать по учебнику, сидя на диване»
Так что — вперёд, кодить!
P. S. Можно ли использовать книгу как учебник в школе?
Можно. И даже нужно, потому что:
• каждая глава — готовый модуль.
Есть теория, практика, задания, вопросы.
Подача — легкая, ориентированная на подростков;
• можно строить целый курс или факультатив.
Почему детям
важно учить
программирование
Спойлер: не для того, чтобы они обязательно стали программистами.
Это может показаться странным — в книге о Python вдруг заявлять,
что программирование само по себе не является целью. Но именно
так и есть.
Учить детей программированию — это не о профессии, а о мышлении, свободе, творчестве и уверенности. О том, чтобы не просто
быть пользователем технологий, а их автором. О том, чтобы уметь
строить, а не только кликать.
Разберёмся, почему это так важно именно сейчас.
Мы живём в цифровом мире. Компьютеры везде. От телефона
в кармане до холодильника, который сам заказывает еду. Все они
управляются программами. Программы пишут люди. Люди — это
программисты.
Сегодня знать хотя бы основы программирования — это всё равно что знать, как устроен велосипед в начале XX века: может, ты
и не станешь механиком, но зато не будешь бояться ездить.
Ребёнок, который знает, как устроены программы, — не просто
пользователь. Он — участник. Создатель. Архитектор.
Программирование — это язык логики
Дети учат языки: английский, русский, математику. Python — ещё
один язык. Но это не просто язык, это структурированное мышление
в действии.
Когда ребенок пишет if x > 10:, он не просто печатает буквы. Он
учится:
• формулировать условия,
• ставить задачи,
20
Почему детям важно учить программирование
• делать выбор,
• проверять гипотезы.
Это мышление, которое пригождается в любой сфере — от биологии до юриспруденции.
Программирование =
творчество + результат
В школе часто говорят: «Будь креативным!» Но где это проявить?
Программирование — идеальное поле для детского творчества:
• придумал игру — реализовал её,
• захотел создать летающий квадрат — написал код,
• захотел, чтобы он говорил, — добавил звук.
Код — это новая форма самовыражения. Это как пластилин, только
цифровой, а вместо рук — клавиатура и мозги.
Ошибки — это нормально
В обычной школе ошибка — это плохо. Красная ручка. Минус балл.
В программировании ошибка — это часть процесса. Это не провал,
а шаг вперёд.
Ты запускаешь — программа ломается — читаешь, думаешь, исправляешь. Победа!
Программирование учит устойчивости, критическому мышлению
и самостоятельности. Дети учатся не бояться пробовать, не бояться
падать, и главное — они учатся вставать.
Навыки будущего — уже сегодня
Когда мы говорим «навыки XXI века», мы имеем в виду:
• решение нестандартных задач,
• работа в команде,
• системное мышление,
• умение проектировать и доводить дело до результата.
Программирование даёт всё это. Даже если ребёнок никогда
не напишет свой стартап, он будет лучше понимать, как устроен мир.
А это — главное преимущество.
21
Введение
Это можно делать вместе
Программирование — не обязательно одиночество за ноутбуком.
Наоборот, это может быть:
• совместный проект в семье,
• групповой хакатон,
• конкурс,
• кружок.
Дети учатся договариваться, делить задачи, презентовать идеи.
И получают обратную связь не от учителя, а от самой программы:
всё работает — значит, ты молодец.
Это развивает сразу несколько типов
интеллекта
По Говарду Гарднеру, существует несколько типов интеллекта:
• логико-математический,
• визуально-пространственный,
• лингвистический,
• интерперсональный и т. д.
Программирование задействует почти все:
• логика — в коде,
• визуализация — в графике и интерфейсе,
• язык — в переменных и именах,
• работа с другими — в проектах.
Это интегративный навык, который «прокачивает» ребёнка во всех
направлениях.
Программирование помогает в других
предметах
Пример: в книге «Python для детей. Играем, чтобы программировать»
мы пишем кликер. В процессе ребёнок:
• считает очки (математика),
• работает с координатами (геометрия),
• делает логические ветвления (алгебра),
• пишет тексты для интерфейса (русский язык).
22
Почему детям важно учить программирование
И всё это — не в виде задач, а в виде собственной игры. Это круто
и незаметно развивает «обычные» школьные навыки.
Это о том, как «создавать», а не «потреблять»
Современный ребёнок окружён контентом. Видео, игры, картинки.
Всё готовое. Всё «потребляется».
Программирование меняет роли. Теперь ты не зритель, а режиссёр. Не игрок, а автор. Не участник, а создатель.
А это уже совсем другой уровень мотивации и самооценки.
А если захочет — пойдет дальше
Мир IT-специальностей — огромен. Не всем быть backend-разработчиками. Но знание Python — это старт для:
• аналитики данных,
• геймдева,
• искусственного интеллекта,
• автоматизации в любой сфере — от медицины до бизнеса.
Книга «Python для детей. Играем, чтобы программировать» — это
не «школа программиста». Это первая ступенька. Дальше — выбор
за ребёнком. Но старт уже будет уверенным.
Программирование — это суперсила
И нет, не потому что «все идут в IT, и зарплаты высокие». Это побочный бонус.
Главное — умение мыслить, пробовать, создавать и быть свободным. Не бояться ошибок. Не зависеть от готовых решений. Уметь
достраивать мир под себя.
А это и есть то, что пригодится любому ребёнку, в любой профессии, в любой жизни.
Что такое Python и среда
программирования.
Объяснение без сложных
слов, но по делу
Что такое Python
Python — это язык. Да-да, как английский или русский. Только он нужен
для общения не между людьми, а между человеком и компьютером.
Когда ты говоришь:
python
print("Привет, мир!")
компьютер отвечает: «Окей, вывести “Привет, мир!” на экран».
Python — это способ «объяснить» компьютеру, чего ты от него
хочешь.
Почему именно Python?
Есть много языков программирования: Java, C++, Go, PHP, Scratch
и ещё штук сто.
Но Python:
• простой — его можно читать почти как обычный текст;
• популярный — на нём пишут игры, сайты, приложения, анализ
данных, AI и роботов;
• востребованный — его учат в школах, вузах и берут в работу
в реальных компаниях.
Его любят взрослые программисты, но он идеально подходит
и для начинающих.
Он не пугает. Он помогает.
Пример: фраза на русском и на Python.
Вот как ты скажешь человеку на русском языке:
«Если идёт дождь, возьми зонт»
24
Что такое Python и среда программирования
А вот как ты скажешь это компьютеру:
if rain == True:
take("umbrella")
Видишь? Это почти то же самое.
Python специально создан понятным.
Что такое среда программирования?
Компьютер сам по себе не умеет «думать». Для того чтобы написать
код и запустить его, тебе нужно определённое место. Это и есть
среда программирования.
Примеры сред:
• Thonny — очень простой редактор, идеален для начинающих;
• VS Code — мощный редактор, для тех, кто хочет большего;
• Jupyter Notebook —
веб-приложение для анализа данных
и исследований;
• Replit — онлайн-среда, работает прямо в браузере.
Если сравнивать с рисованием:
• Python — это краски и кисти;
• Среда — это мольберт и палитра.
Без среды ты не можешь начать рисовать. А без языка у тебя нет
цветов.
Как это выглядит?
Ты открываешь среду (например, Thonny), видишь чистое окно.
Вводишь код:
print ("Я начинающий программист!")
Нажимаешь Run — и снизу появляется:
Я начинающий программист!
Магия? Немного.
Но на самом деле — просто инструкция для компьютера.
Где применяется Python
в реальном мире?
Если тебе кажется, что программирование только для очкариков,
которые сидят в подвалах и жуют пиццу, — у нас есть новости.
Вот где живёт Python
ГДЕ?
ЧТО ДЕЛАЕТ?
Игры
Двигает персонажей, считает очки, запускает
анимации
Сайты
Работает «под капотом» — производит поиск,
создаёт фильтры, делает регистрацию
Аналитика
Считает, прогнозирует, строит графики
Искусственный интеллект
Обучает нейросети, создает чат-ботов
Космос
Используется в NASA (да-да, серьёзно)
Медицина
Анализирует ДНК, прогнозирует заболевания
Офис и автоматизация
Обрабатывает таблицы, сортирует файлы,
автоматизирует рутину
Короче: Python — везде.
Он тихо работает внутри привычных для тебя вещей.
И каждый, кто умеет с ним обращаться, как будто обладает суперсилой.
Для старта тебе не нужны высшая математика или знание английского. Тебе нужно:
• чуть-чуть терпения,
• желание пробовать,
• и хорошая книга (вот как эта, кстати).
26
Где применяется Python в реальном мире?
И что дальше?
После того как ты освоишь Python и среду:
• ты сможешь писать простые программы;
• делать игры (да, с графикой, звуком и управлением);
• автоматизировать свою жизнь (например, пересортировать
1000 файлов по папкам одной строкой);
• и главное — понимать, что у тебя есть сила создавать.
Как настроить среду
разработки Python
(Да, это проще, чем установить
Майнкрафт с модами)
Чтобы писать код и запускать игры из этой книги, нужно сделать
всего две вещи.
1. Установить Python — язык, на котором ты будешь программировать.
2. Установить редактор — место, где ты будешь писать код и нажимать «Запустить!»
Это как ручка и тетрадь, только виртуальные.
Ниже приведена инструкция, которая позволит настроить всё
с нуля. Даже если раньше ты запускал только браузер и «Роблокс».
Шаг 1. Установка Python
Что такое Python?
Это язык программирования. Он установлен на миллионах компьютеров, на нём написаны игры, сайты, программы и даже роботы.
Как установить Python
1. Перейди на официальный сайт: https://www.python.org.
2. Нажми на большую жёлтую кнопку Download Python 3.x.x
(где x.x — самая новая версия, например, 3.12.3).
3. Скачай установщик и запусти его.
4. Внимание! Перед тем как нажать Install поставь галочку:
Add Python to PATH — это важно!
5. Жми Install Now. Жди 1–2 минуты.
6. Готово! Python установлен.
28
Как настроить среду разработки Python
Шаг 2. Проверка установки
Проверь, всё ли работает. Это как завести компьютер и услышать
«пииип» — значит, живой.
1. Нажми Win + R (если у тебя Windows), напиши cmd, нажми
Enter.
Откроется чёрное окно (терминал). Напиши:
python --version
2. Нажми Enter.
3. Если всё хорошо, ты увидишь что-то вроде:
nginx
Python 3.12.3
Поздравляю!
Python работает!
Шаг 3. Установка среды для написания кода
Теперь нужен редактор, в котором ты будешь писать программы. Это
как Word, только для кода.
Вариант 1 — Thonny (рекомендуется для новичков)
Почему именно он?
Thonny — это как «песочница» для Python. Простой, понятный,
не содержит ничего лишнего.
Как установить
1. Перейди на сайт: https://thonny.org.
2. Скачай версию под Windows, Mac или Linux.
3. Установи как обычную программу (жми Next, Install и жди).
4. Запусти.
Ты увидишь пустое окно. Можешь сразу написать в нём:
print("Привет, мир!")
29
Введение
Нажми Run (зелёную кнопку сверху). Если внизу появилось Привет, мир! — всё работает.
Плюсы Thonny
• Поддержка русского языка.
• Простота.
• Всё включено (Python встроен).
• Идеально для первых шагов.
Вариант 2 — Visual Studio Code (если хочешь чего-то
посерьёзнее)
Что это?
VS Code — это уже не просто «тетрадь», а целый «офис» для программиста. Он мощнее, но немного сложнее.
Как установить
1. Перейди на: https://code.visualstudio.com.
2. Скачай и установи программу.
3. Открой, зайди в Extensions (левая панель, иконка с кубиком)
и установи:
• Python,
• Pylance,
4. Убедись, что Python правильно подключён (в правом нижнем
углу должно быть что-то вроде Python 3.x).
VS Code хорошо подойдёт, если ты хочешь не просто учиться,
а создавать серьезные проекты позже.
30
Как настроить среду разработки Python
Шаг 4. Установка Pygame — чтобы делать игры
Pygame — это библиотека, которая помогает рисовать, двигать
объекты, добавлять звук и вообще превращать код в игру.
Как установить Pygame
1. Открой Thonny → Инструменты → Управление пакетами.
31
Введение
2. В строке поиска напиши pygame и нажми кнопку «Поиск PyPi».
3. Выбери первую строку и нажми «Установить».
32
Как настроить среду разработки Python
4. Обычно это не занимает много времени.
Всё готово!
ЧАСТЬ 1
ГЛАВА 1.1
Базовые типы данных,
арифметические операции.
Переменные
ВРЕМЯ НА ЧТЕНИЕ: 15 МИНУТ
ВРЕМЯ НА НАПИСАНИЕ КОДА: 15 МИНУТ
Сегодня мы погрузимся в мир программирования на языке Python.
Обычно это делают так же как и при изучении нового школьного
предмета, мы поступим немного иначе. Сначала мы создадим небольшую игру и на её примере будем изучать основы программирования.
Не беспокойся, пока тебе нужно только подготовить среду программирования (смотри главу «Как настроить среду разработки Python
для новичка») и переписать код ниже.
import pygame as pg, sys
pg.init()
screen = pg.display.set_mode((800, 600))
pg.display.set_caption("Лети к курсору!")
x, y = 400, 300
size = 60 # размер шарика. Хочешь Годзиллу? Напиши 200.
color = (255, 0, 0) # красный. Зелёный —
это (0, 255, 0).
while True:
for event in pg.event.get():
if event.type == pg.QUIT: sys.exit()
elif event.type == pg.MOUSEBUTTONDOWN:
x, y = pg.mouse.get_pos()
screen.fill((0, 0, 0))
36
Базовые типы данных, арифметические операции. Переменные
pg.draw.circle(screen, color, (x, y), size)
pg.display.flip()
pg.time.delay(10)
ЧАСТЬ 1
Если среду разработки подготовить верно, а код переписать
корректно, то ты получишь свою первую игру!
«Поздравляю! У тебя на экране красный шар летает за курсором. Это не Hello World. Это твоя первая настоящая игра.
Пусть и микроскопическая».
Конечно, она не пробуждает интереса, давайте потихонечку изменим это.
Для начала нам нужно изучить немного основ. Давайте познакомимся с переменными. Что это? Для чего они нужны? Скоро всё поймёте.
В каждой игре мы встретим множество характеристик игровых
объектов, начиная от здоровья игровых персонажей, количества
денег и заканчивая размерами игровых предметов. Естественно, эти
характеристики должны как-то храниться, меняться и обрабатываться компьютером. На примере нашей игры такими характеристиками
можно считать размер и цвет шарика, преследующего наш курсор.
Но для более детального разбора представим простую ситуацию:
у нас есть игрок, у которого имеется здоровье, некоторое количество
монет и имя. Переменные — это просто контейнеры, которые хранят
37
ЧАСТЬ 1
Глава 1.1
текущие значения конкретных характеристик. Эти значения могут
меняться, отсюда и название — переменные. Переменные бывают разными, как и контейнеры для вещей. В какие-то из них кладут одежду,
в какие-то — еду. Существует множество типов контейнеров, то же
самое касается и переменных. Давайте разберём некоторые из них.
Целые числа (int) — например, количество монет или размер шарика:
size = 60
Дробные числа (float) — например, урон в играх:
damage = 10.5
Строки (str) — например, для имен персонажей или предметов,
или диалоги:
name = "Игрок"
Важно, что для сохранения текста в переменных мы всегда используем одинаковые открывающие и закрывающие кавычки, можно
как " так и '.
СЛОВАРЬ ПЕРЕМЕННЫХ
38
ТИП
ПРИМЕР
ГДЕ ИСПОЛЬЗУЕТСЯ
int
60
Размер шарика
float
10.5
Урон, скорость
str
"Игрок"
Имя персонажа
bool
True/False
Включено/выключено
Базовые типы данных, арифметические операции. Переменные
Основные операции с числами: +, -, *, /, //,%.
складывает два числа
-
вычитает из числа 1 число 2
*
перемножает два числа
/
делит число 1 на число 2
//
делит число 1 на число 2 без остатка (5 // 2 = 2)
%
берёт остаток при делении числа 1 на число 2 (5% 2 = 1)
ЧАСТЬ 1
+
Основные операции со строками: +, *.
+
склеивает две строчки
*
(работает, если строку умножить на число) повторяет
строчку, перемноженное кол-во раз
Так, теперь можно вернуться к нашей игре, давайте сами изменим
размер шарика, а после и его цвет.
ЗАДАНИЕ 1
1) Измени переменную size (размер шарика)
на желаемый размер
39
Глава 1.1
ЧАСТЬ 1
2) Измени цвет шарика, для этого измени
переменную color
1. Подсказка: цвет хранится в формате RGB, три числа от 0
до 255. Для того чтобы найти желаемый цвет, можно использовать rgb палитру цветов.
• Хочешь жёлтый шар? Пробуй: (255, 255, 0)
• А теперь фиолетовый? (128, 0, 128)
Давайте сделаем игру интересней, дадим пользователю возможность порисовать!
Для этого удалите строчку scr
screen.fill((0,
een.fill((0, 0, 0)) и оцените текущую версию игры. Согласитесь, не хватает возможности очистить
экран игры. Для этого добавьте следующие строчки:
keys = pg.key.get_pressed()
if keys[pg.K_SPACE]: screen.fill((0, 0, 0))
ЗАДАНИЕ 2
Сделайте так, чтобы фон был оранжевого, а не чёрного цвета.
Подсказка: screen.fill((0, 0, 0)) — это команда, которая указывает компьютеру перекрасить экран в выбранный цвет. К примеру,
если написать screen.fill((255, 255, 255)), то фон станет белым.
ЗАДАНИЕ 3
Сделайте так, чтобы при нажатии на «+», увеличивался размер
создаваемого кружка, а при нажатии на «–» он уменьшался.
Подсказка
if keys[pg.K_KP_PLUS]: size = 100
if keys[pg.K_KP_MINUS]: size = 10
40
Базовые типы данных, арифметические операции. Переменные
ЗАДАНИЕ 4
ЗАДАНИЕ 5
Сделай баг — попробуй color = "зелёный" и поймай ошибку.
ЧАСТЬ 1
Сделай шарик ГИГАНТСКИМ (size = 300). Теперь он — злой босс.
ГЛАВА 1.2
Логические выражения
и операторы
ВРЕМЯ НА ЧТЕНИЕ: 20 МИНУТ
Сегодня мы начнём разбирать очень важный аспект в программировании, а именно — логические выражения. Логические выражения — это инструкции, при выполнении которых будет получен один
из двух ответов, «Да» или «Нет» («Правда» или «Ложь»). В Python есть
отдельный тип данных, который хранит результат подобных выражений, он называется bool и хранит либо значение True («Правда»),
либо False («Ложь»).
42
Логические выражения и операторы
ОПЕРАТОР
НАЗВАНИЕ
ПРИМЕР
РЕЗУЛЬТАТ
(ПОЯСНЕНИЕ)
==
Равно
5 == 5
True (5 равно 5)
!=
Не равно
3!= 2
True (3 не равно 2)
>
Больше
10 > 7
True (10 больше 7)
<
Меньше
4<6
True (4 меньше 6)
>=
Больше или равно
8 >= 8
True (8 равно 8)
<=
Меньше или равно
5 <= 3
False (5 не меньше
и не равно 3)
2. Составные утверждения.
Часто мы используем несколько утверждений вместе:
• «Я не сделал ДЗ» и «У меня нет времени сделать ДЗ».
• «На улице больше 15 градусов тепла» или «Мне разрешили
погулять».
Существует 3 логических оператора: not, or, and
and..
• and (и) — соединяет 2 утверждения, так что истиной (True) будет, только если оба утверждения верны;
• or (или) — соединяет 2 утверждения, так что истиной (True) будет, если хотя бы одно из утверждений верно;
• not (не) — идет перед утверждением, отрицая его. Если утверждение было ложным, оно становится верным, и наоборот.
43
ЧАСТЬ 1
Теперь понятно, что логическое выражение — это просто утверждение, которое компьютер проверяет на правдивость. Давайте разберём, как такие утверждения пишутся в python.
1. Часто в таких утверждениях мы сравниваем какие-то аспекты
(рост, вес). Так же мы можем делать и в Python. Для этого два
объекта сравнения должны быть одного типа. С некоторыми
типами объектов нельзя использовать определённые операторы сравнения. К примеру, невозможно однозначно сказать,
какая из двух строчек больше. Равны ли они — сказать легко,
а вот которая из них больше — нет, поскольку мы сравниваем
не строчки, а их длины или какие-то другие параметры.
ЧАСТЬ 1
Глава 1.2
ОПЕРАТОР
НАЗВАНИЕ
ПРИМЕР
КОГДА TRUE?
АНАЛОГ В ЖИЗНИ
and
И
A and B
Только если
оба True
«Купи хлеб и молоко» → купил
оба продукта
«Чай или
кофе?» → возможен любой
вариант
«Не закрыто» →
значит, открыто
or
ИЛИ
A or B
Если хотя бы
одно True
not
НЕ
not A
Если A —
False
ГЛАВА 1.3
Условия. Ветвление
ВРЕМЯ НА ЧТЕНИЕ: 20 МИНУТ
ВРЕМЯ НА НАПИСАНИЕ КОДА: 30 МИНУТ
В прошлой главе мы разбирали логические выражения, и сейчас нам
это очень поможет.
В программировании есть условные блоки, благодаря которым
в зависимости от результата выражения будут выполняться разные
инструкции.
К примеру:
• если воду не отключили, она течёт из крана, иначе — нет;
• если у игрока хватает игровой валюты — продать ему нужный
предмет.
И так далее.
В Python условия записываются следующим образом:
• сначала if логическое выражение 1:
» инструкция выполняется, если логическое выражение 1 истинно;
• elif логическое выражение 2:
» инструкция выполняется, если предыдущие логические выражения ложные, а логическое выражение 2 истинно;
• else:
» инструкция выполняется, если все предыдущие логические
выражения ложные.
Условные блоки всегда начинаются с if, остальные блоки elif,
else не обязательны. if и else не может быть больше одного в од-
45
Глава 1.3
ЧАСТЬ 1
ном блоке, т. к. if — начало нового условного блока, а else — конец
условного блока, однако elif может быть сколько угодно.
Надо заметить, что если условие не длинное, а выполняемые
инструкции занимают одну строчку, то можно использовать следующую конструкцию.
if логическое выражение 1: инструкция выполняется, если логическое выражение 1 истинно.
Теперь мы можем перейти к самому интересному — изменению
и развитию нашей игры, которую мы начали писать в 1 главе. Для
начала давайте вспомним, какой примерно код должен был получиться ранее.
46
Условия. Ветвление
import pygame as pg, sys
ЧАСТЬ 1
pg.init()
screen = pg.display.set_mode((800, 600))
pg.display.set_caption("Лети к курсору!")
x, y = 400, 300
size = 60
color = (255, 0, 0)
while True:
for event in pg.event.get():
if event.type == pg.QUIT: sys.exit()
elif event.type == pg.MOUSEBUTTONDOWN:
x, y = pg.mouse.get_pos()
pg.draw.circle(screen, color, (x, y), size)
keys = pg.key.get_pressed()
if keys[pg.K_SPACE]: screen.fill((255, 165, 0))
if keys[pg.K_MINUS]: size -= 1
if keys[pg.K_EQUALS]: size += 1
pg.display.flip()
pg.time.delay(10)
47
Глава 1.3
ЧАСТЬ 1
Давайте сделаем так, чтобы можно было менять цвет нашей кисти, для этого добавим несколько новых условий:
if keys[pg.K_1]: color = (255, 0, 0)
if keys[pg.K_2]: color = (0, 255, 0)
if keys[pg.K_3]: color = (0, 0, 255)
Условия довольно простые, если keys[pg.K_0] (нажата ли цифра 0), то изменить цвет на красный (это можно понять, если посмотреть в таблицу rgb).
48
Условия. Ветвление
ЗАДАНИЕ 1
ЗАДАНИЕ 2
Сейчас мы можем легко изменить размер нашей «кисти», но нужно установить какие-то границы. Сделайте так, чтобы размер кисти
не мог быть больше 100 и меньше 15.
Подсказка
Для этого нужно изменить логическое выражение в условии увеличения и уменьшения размера кисти.
ЗАДАНИЕ 3
Добавьте ещё 2 цвета кисти, которые можно будет выбрать при
нажатии на цифры 4 и 5.
Так, теперь мы можем рисовать, но всё-таки нам многого не хватает. Давайте сделаем небольшой интерфейс, чтобы было понятно,
какой цвет и размер у кисти сейчас!
49
ЧАСТЬ 1
Посчитайте, сколько условий в нашем коде и сколько условных
блоков (условный блок начинается с if, но может содержать еще
elif и else). Ответ для проверки будет в конце главы.
Глава 1.3
ЧАСТЬ 1
Ты можешь добавить любые цвета!
Например, жёлтый или фиолетовый. RGB-коды легко найти, например: жёлтый — (255, 255, 0)
А я поставил цвет (999,
-5, 300) — теперь у меня
чёрная дыра вместо кисти!
Так делать нельзя!
Все числа в RGB должны
быть от 0 до 255.
Код до выполнения заданий, но с новым интерфейсом:
import pygame as pg, sys
pg.init()
screen = pg.display.set_mode((800, 600))
pg.display.set_caption("Лети к курсору!")
x, y = 400, 300
size = 60
color = (255, 0, 0)
font = pg.font.SysFont('Arial', 24)
while True:
for event in pg.event.get():
if event.type == pg.QUIT: sys.exit()
elif event.type == pg.MOUSEBUTTONDOWN:
x, y = pg.mouse.get_pos()
pg.draw.circle(screen, color, (x, y), size)
keys = pg.key.get_pressed()
if keys[pg.K_1]: color = (255, 0, 0)
if keys[pg.K_2]: color = (0, 255, 0)
if keys[pg.K_3]: color = (0, 0, 255)
if keys[pg.K_SPACE]: screen.fill((255, 165, 0))
if keys[pg.K_MINUS]: size -= 1
50
Условия. Ветвление
if keys[pg.K_EQUALS]: size += 1
ЧАСТЬ 1
pg.draw.rect(screen, (50, 50, 50), (0, 550, 800, 50))
pg.draw.circle(screen, color, (50, 575), 15)
pg.draw.circle(screen, (200, 200, 200), (50, 575), 15, 1)
size_text = font.render(f'Размер: {size}', True, (255, 255, 255))
screen.blit(size_text, (80, 560))
pg.display.flip()
pg.time.delay(10)
Обрати внимание на то, что в строчке if event.type == pg.QUIT:
стоит два знака «==». Это очень частая ошибка: использовать один
знак «равно» в условия НЕЛЬЗЯ.
51
ЧАСТЬ 1
Глава 1.3
ДОПОЛНИТЕЛЬНОЕ
ЗАДАНИЕ 1
Просмотрите код, добавленный при создании интерфейса, и добавьте подсказки, при помощи которых можно понять:
1. как увеличить/уменьшить размер кисти;
2. как изменить цвет кисти.
ДОПОЛНИТЕЛЬНОЕ
ЗАДАНИЕ 2
Добавьте новую кисть, вместо круга должен рисоваться квадрат.
ГЛАВА 1.4
Логические выражения
и операторы
ВРЕМЯ НА ЧТЕНИЕ: 20 МИНУТ
Привет, юный программист!
Ты уже научился создавать простую игру, где красный кружок
появляется там, куда ты кликаешь мышкой. А ещё ты можешь менять
его размер и стирать всё, нажимая на пробел. Но что, если мы добавим новые возможности? Например, запретим кружку становиться
слишком маленьким или слишком большим?
Для этого нам понадобятся логические выражения и операторы!
Что такое логические выражения?
Логические выражения — это вопросы, на которые компьютер может
ответить только True (да) или False (нет).
Например:
• 5 > 3 → True (5 больше 3? Да!)
• 10 == 9 → False (10 равно 9? Нет!)
В этих двух примерах мы сравнивали два числа.
Основные операторы сравнения:
• «>» — больше;
• «<» — меньше;
• «==» — равно;
• «!=» — не равно;
• «>=» — больше или равно;
• «<=» — меньше или равно.
53
Глава 1.4
Логические операторы and, or, not
ЧАСТЬ 1
Иногда нам нужно проверить сразу несколько условий:
• and — «и» (оба условия должны быть True)
» (5 > 3) and (2 < 4) → True
» (5 == 3) and (2 < 4) → False
• or — «или» (хотя бы одно условие True)
» (5 == 3) or (2 < 4) → True (второе условие истинно)
• not — «не» (меняет True на False и наоборот)
» 5 == 5 → True
» not (5 == 5) → False
Применяем в игре!
Сейчас в нашем коде кружок может расти или уменьшаться бесконечно. Давай ограничим его размер!
Добавим проверки:
if keys[pg.K_MINUS] and size > 10: # Не дадим кружку стать
меньше 10
size -= 1
if keys[pg.K_EQUALS] and size < 100: # И больше 100
size += 1
Теперь кружок не исчезнет (если size не станет 0) и не заполнит
весь экран!
Новая фишка: меняем цвет!
Давай добавим возможность менять цвет кружка при нажатии
клавиш:
• R — красный
• G — зелёный
• B — синий
if keys[pg.K_r]: # Если нажать кнопку R
color = (255, 0, 0) # Меняем цвет на красный
54
Логические выражения и операторы
нажать
Меняем
нажать
Меняем
кнопку G
цвет на зелёный
кнопку B
цвет на синий
ЧАСТЬ 1
if keys[pg.K_g]: # Если
color = (0, 255, 0) #
if keys[pg.K_b]: # Если
color = (0, 0, 255) #
Полный код с новыми возможностями
import pygame as pg, sys
pg.init()
screen = pg.display.set_mode((800, 600))
pg.display.set_caption("Лети к курсору! (Теперь с логикой!)")
x, y = 400, 300
size = 60
color = (255, 0, 0) # Начинаем с красного
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
sys.exit()
elif event.type == pg.MOUSEBUTTONDOWN:
x, y = pg.mouse.get_pos()
keys = pg.key.get_pressed()
# Меняем размер (но не даём выйти за границы)
if keys[pg.K_MINUS] and size > 10:
size -= 1
if keys[pg.K_EQUALS] and size < 100:
size += 1
# Меняем цвет
if keys[pg.K_r]:
color = (255, 0, 0) # Красный
if keys[pg.K_g]:
color = (0, 255, 0) # Зелёный
if keys[pg.K_b]:
color = (0, 0, 255) # Синий
55
Глава 1.4
ЧАСТЬ 1
# Очищаем экран пробелом
if keys[pg.K_SPACE]:
screen.fill((255, 165, 0)) # Оранжевый фон
pg.draw.circle(screen, color, (x, y), size)
pg.display.flip()
pg.time.delay(10)
Как выглядит наша игра?
Что мы узнали?
• Логические выражения — вопросы, на которые компьютер
отвечает True или False.
• Операторы сравнения (>, <, == и др.) помогают сравнивать
значения.
• Логические операторы (and, or, not) позволяют комбинировать условия.
• Применили это в игре, чтобы ограничить размер кружка и добавить смену цвета!
ГЛАВА 1.5
Задачи на закрепление
материала
Привет, юный программист!
Ты уже узнал про логические выражения и операторы, а теперь
пришло время закрепить знания на практике. В этой главе мы не будем добавлять новые темы, а усовершенствуем нашу игру, решая
интересные задачи.
Каждая задача — это шаг к тому, чтобы игра стала ещё круче!
Задача 1. Добавляем радужный режим
Сейчас цвет круга меняется только на красный, зелёный или синий.
Давай сделаем так, чтобы он плавно переливался всеми цветами
радуги при нажатии на клавишу C!
Что нужно сделать?
1. Добавь переменную rainbow_mode = False (изначально выключен).
2. Если нажата клавиша C, переключай rainbow_mode между True
и False.
3. В основном цикле игры, если rainbow_mode == True, меняй color
на случайный.
Подсказка
Чтобы создать случайный цвет, используй библиотеку random,
в которой есть функция randint(a, b) (a и b — два числа), генерирующая случайное число от a до b:
import random
color = (random.randint(0, 255), random.randint(0, 255), random.
randint(0, 255))
57
Глава 1.5
ЧАСТЬ 1
Задача 2. Запрещаем выход за границы экрана
Сейчас, если кликнуть на пространство за пределами окна, круг
может «улететь» и исчезнуть. Давай исправим это!
Что нужно сделать?
1. При клике мышкой проверяй, что новые координаты (x, y)
не выходят за границы экрана.
2. Если x меньше 0, то ставь x = 0.
3. Если x больше 800, то ставь x = 800.
4. То же самое для y (высота экрана — 600).
Подсказка
Используй встроенные функции min() и max(), которые выбирают наибольшее и наименьшее число:
x = max(0, min(x, 800)) # Ограничиваем x от 0 до 800
y = max(0, min(y, 600)) # Ограничиваем y от 0 до 600
Задача 3. Добавляем невидимый режим
Давай сделаем так, чтобы при нажатии на клавишу V круг исчезал
и появлялся!
Что нужно сделать?
1. Добавь переменную visible = True (круг виден).
2. Если нажата клавиша V, меняй visible на not visible (переключатель).
3. Рисуй круг только если visible == True.
Подсказка
Используй if visible == True: перед 'pg.draw.circle()'.
Пример решения для одной из задач
Вот как может выглядеть решение задачи про радужный режим:
import pygame as pg, sys, random
# Добавили библиотеку random
58
Задачи на закрепление материала
pg.init()
screen = pg.display.set_mode((800, 600))
pg.display.set_caption("Улучшенная игра!")
ЧАСТЬ 1
x, y = 400, 300
size = 60
color = (255, 0, 0)
rainbow_mode = False # Новый флаг
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
sys.exit()
elif event.type == pg.MOUSEBUTTONDOWN:
x, y = pg.mouse.get_pos()
# Ограничиваем x и y (задача 2)
x = max(0, min(x, 800))
y = max(0, min(y, 600))
elif event.type == pg.KEYDOWN: # Обработка однократных
нажатий
if event.key == pg.K_c: # Переключаем радугу
rainbow_mode = not rainbow_mode
keys = pg.key.get_pressed()
if keys[pg.K_MINUS] and size > 10:
size -= 1
if keys[pg.K_EQUALS] and size < 100:
size += 1
if keys[pg.K_r]:
color = (255, 0, 0) # Красный
if keys[pg.K_g]:
color = (0, 255, 0) # Зелёный
if keys[pg.K_b]:
color = (0, 0, 255) # Синий
if rainbow_mode: # Если радуга включена
59
Глава 1.5
ЧАСТЬ 1
color = (random.randint(0, 255), random.randint(0, 255),
random.randint(0, 255))
if keys[pg.K_SPACE]:
screen.fill((255, 165, 0))
pg.draw.circle(screen, color, (x, y), size)
pg.display.flip()
pg.time.delay(10)
Как это выглядит на деле
Итоги главы
• Закрепили работу с логическими операторами.
• Добавили новые фичи в игру.
• Потренировались решать задачи.
Попробуй выполнить все задачи и сделай игру ещё лучше!
ГЛАВА 1.6
Ветвление.
Условный оператор
ВРЕМЯ НА ЧТЕНИЕ: 15 МИНУТ
Привет, юный программист!
В прошлых главах ты научился использовать логические выражения и операторы сравнения. Теперь пришло время познакомиться
с ветвлением — это когда программа выбирает, какой код выполнить,
в зависимости от условий.
В нашей игре мы добавим новые режимы и спецэффекты, которые будут включаться только при определённых условиях! Это уже
не просто набор команд — программа начинает «думать» и принимать
решения, как настоящий герой Коди, который всегда действует логично!
Что такое ветвление?
Ветвление — это возможность программы выполнять разные действия
в зависимости от условий.
Как это работает?
if условие:
# Код, который выполнится, если условие True
else:
# Код, который выполнится, если условие False
61
Глава 1.6
Пример
ЧАСТЬ 1
age = 12
if age >= 12:
print("Ты можешь играть в эту игру!")
else:
print("Извини, тебе пока рано")
Добавляем «защитный щит» в игре
Давай сделаем так, чтобы при нажатии на клавишу S вокруг круга
появлялся защитный щит (синий ободок). Но он должен работать,
только если круг красного или зелёного цвета!
Звучит просто, но будь осторожен — Багги мог бы сделать щит
активным всегда, даже когда он не нужен. Это испортило бы баланс
игры! Мы же с тобой сделаем правильно — добавим проверку условий
с помощью if.
Что нужно сделать?
1. Добавим переменную shield = False (щит выключен).
2. Если нажата клавиша S, переключаем щит.
3. Рисуем щит только если:
» shield == True и
» цвет круга красный или зелёный.
Код
if shield and (color == (255, 0, 0) or color == (0, 255, 0)):
# Если щит включён и цвет круга красный или зелёный
pg.draw.circle(screen, (0, 0, 255), (x, y), size + 10, 5)
# Синий ободок
Добавляем «режим хамелеона»
Сейчас цвет меняется только при нажатии на клавиши. Давай сделаем так, чтобы круг автоматически менял цвет при соприкосновении
с краями экрана!
62
Ветвление. Условный оператор
Что нужно сделать?
1. Проверяем, коснулся ли круг границы:
ЧАСТЬ 1
touch_left = x —
size <= 0 # Касается левой границы
touch_right = x + size >= 800 # Касается правой границы
touch_top = y —
size <= 0 # Касается верхней границы
touch_bottom = y + size >= 600 # Касается нижней границы
2. Если да — меняем цвет случайным образом:
if touch_left or touch_right or touch_top or touch_bottom:
color = (random.randint(0, 255), random.randint(0, 255), random.
randint(0, 255))
Полный код с новыми фишками
import pygame as pg, sys, random
pg.init()
screen = pg.display.set_mode((800, 600))
pg.display.set_caption("Умный круг!")
x, y = 400, 300
size = 60
color = (255, 0, 0)
shield = False # Щит выключен
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
sys.exit()
elif event.type == pg.MOUSEBUTTONDOWN:
x, y = pg.mouse.get_pos()
x = max(size, min(x, 800 —
size)) # Не даём выйти за границы
y = max(size, min(y, 600 —
size))
elif event.type == pg.KEYDOWN:
if event.key == pg.K_s: # Включаем/выключаем щит
63
Глава 1.6
shield = not shield
ЧАСТЬ 1
keys = pg.key.get_pressed()
# Меняем размер
if keys[pg.K_MINUS] and size > 10:
size -= 1
if keys[pg.K_EQUALS] and size < 100:
size += 1
# Меняем цвет
if keys[pg.K_r]:
color = (255, 0, 0)
if keys[pg.K_g]:
color = (0, 255, 0)
if keys[pg.K_b]:
color = (0, 0, 255)
# Проверяем, коснулся ли круг границ
touch_left = x —
size <= 0
touch_right = x + size >= 800
touch_top = y —
size <= 0
touch_bottom = y + size >= 600
if touch_left or touch_right or touch_top or touch_bottom:
color = (random.randint(0, 255), random.randint(0, 255),
random.randint(0, 255))
if keys[pg.K_SPACE]:
screen.fill((255, 165, 0))
# Рисуем щит (если можно)
if shield and (color == (255, 0, 0) or color == (0, 255, 0)):
pg.draw.circle(screen, (0, 0, 255), (x, y), size + 10, 5)
pg.draw.circle(screen, color, (x, y), size)
pg.display.flip()
pg.time.delay(10)
64
Ветвление. Условный оператор
Что получилось
ЧАСТЬ 1
Что мы узнали?
• Ветвление (if-else) помогает программе принимать решения.
• Условия могут быть сложными (с and, or).
• Мы добавили в игру:
» защитный щит, который работает только для определённых цветов;
» режим хамелеона — круг меняет цвет при соприкосновении
с границами.
Хочешь, чтобы Коди гордился твоим кодом? Всегда проверяй
условия внимательно, иначе Багги найдёт способ всё испортить!
ГЛАВА 1.7
«Случайные» числа —
random, randint, randrange
ВРЕМЯ НА ЧТЕНИЕ: 20 МИНУТ
Пришло время добавить в игру немного неожиданности и веселья —
познакомиться с темой случайных чисел и модулем random в Python.
Даже Коди сказал бы: «Настоящая игра должна удивлять!» А вот
Багги любит беспорядок, поэтому он с радостью вносит хаос при
помощи случайных чисел, — только вот у него всё выходит не по правилам. Мы же научимся использовать случайность осознанно.
Зачем нужны случайные числа в играх?
Случайность делает каждую игру уникальной: круг может появляться
в разных местах, менять цвет или размер, а значит — играть становится
интереснее! Благодаря случайным числам твоя программа перестаёт
быть предсказуемой, и каждый запуск приносит что-то новое.
Модуль random и его основные функции
В Python есть специальный модуль для работы со случайными числами — он так и называется: random. Ниже самые полезные функции,
которые пригодятся тебе в играх.
• random.randint(a, b)
Возвращает случайное целое число от a до b включительно.
Например, random.randint(1, 10) даст любое число от 1 до 10. Это
удобно, если нужно получить случайную координату или цвет.
66
«Случайные» числа — random, randint, randrange
Давай теперь попробуем написать код с этими функциями!
random.randint(a, b)
Генерирует случайное целое число от a до b включительно:
import random
number = random.randint(1, 10)
print("Случайное число от 1 до 10:", number)
Пример вывода
Случайное число от 1 до 10: допустим, 7.
random.randrange(start, stop[, step])
Генерирует случайное целое число из диапазона от start до stop
(за исключением stop), можно указать шаг:
import random
number = random.randrange(0, 10, 2)
print("Случайное чётное число от 0 до 8:", number)
Пример вывода
Случайное чётное число от 0 до 8: допустим, 6.
67
ЧАСТЬ 1
• random.randrange(start, stop[, step])
Возвращает случайное целое число из диапазона от start
до stop (не включая stop). Можно указать шаг, например выбрать
только чётные числа.
Пример
random.randrange(0, 10, 2) даст одно из чисел: 0, 2, 4, 6, 8.
• random.random()
Возвращает случайное число с плавающей точкой от 0 до 1
(например, 0.374). Это удобно, если тебе нужно дробное число — скажем, для прозрачности или скорости.
Глава 1.7
random.random()
ЧАСТЬ 1
Генерирует случайное число с плавающей точкой от 0.0 до 1.0:
import random
number = random.random()
print("Случайное число от 0 до 1:", number)
Пример вывода
Случайное число от 0 до 1: допустим, 0.374921485.
Соберем эти три функции в таблицу
ФУНКЦИЯ
randint(a, b)
randrange()
random()
ЧТО ДЕЛАЕТ
ПРИМЕР
целое число от A до B
попадание в цель
число с шагом
числа на линейке
дробное от 0 до 1
прозрачность
Как это выглядит в коде?
Давай изменим твой код так, чтобы круг появлялся в случайном месте
и со случайным цветом при каждом клике мышкой:
import pygame as pg, sys
import random
68
«Случайные» числа — random, randint, randrange
ЧАСТЬ 1
pg.init()
screen = pg.display.set_mode((800, 600))
pg.display.set_caption("Лети к курсору!")
x, y, size = 400, 300, 60
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
sys.exit()
elif event.type == pg.MOUSEBUTTONDOWN:
# Случайные координаты
x = random.randint(0, 800)
y = random.randint(0, 600)
# Случайный цвет
color = (
random.randint(0, 255),
random.randint(0, 255),
random.randint(0, 255)
)
else:
# Цвет по умолчанию, если мышь не нажата
color = (255, 0, 0)
screen.fill((0, 0, 0))
pg.draw.circle(screen, color, (x, y), size)
pg.display.flip()
pg.time.delay(10)
Результат
После написания этого кода при нажатии на мышь будет появляться круг в случайном месте. Сначала он будет иметь случайный
цвет, но если отпустить мышь, то круг станет красным.
Коди сказал бы: «Клик — новый шанс для круга проявить себя».
Багги просто ставил бы круги где попало, но мы зададим чёткие
правила!
69
Глава 1.7
ЧАСТЬ 1
Контрольные вопросы
1. Для чего нужен модуль random в Python и как подключить его
к программе?
2. Чем отличается функция random.randint(a, b) от random.
randrange(a, b)?
3. Какой диапазон значений возвращает функция random.
random()?
4. Как получить случайное чётное число от 0 до 10 включительно с помощью модуля random?
5. Можно ли использовать функции модуля random для генерации случайных цветов? Как это сделать?
Задачи на закрепление материала
1. Напиши программу, которая выводит на экран 5 случайных
целых чисел от 1 до 100 с помощью random.randint().
2. Сделай так, чтобы при каждом клике мышкой круг менял цвет
на случайный (используй три вызова random.randint(0, 255)
для каждого компонента цвета).
3. Используй random.randrange() с шагом 5, чтобы получить случайное число из ряда 0, 5, 10, 15… до 50.
Теперь ты умеешь управлять случайностью!
Коди тобой гордится. А вот Багги ворчит, ведь ты всё сделал
правильно.
ГЛАВА 1.8
Ошибки и исключения.
Обработка исключений
ВРЕМЯ НА ЧТЕНИЕ: 20 МИНУТ
ВРЕМЯ НА НАПИСАНИЕ КОДА: 25 МИНУТ
В этой главе мы попытаемся подробнее узнать об ошибках. При разработке программ на Python мы часто сталкиваемся с ситуациями,
когда что-то идёт не по плану: файл не найден, производится деление на ноль, введены некорректные данные и т. д. Такие ситуации
вызывают исключения. Исключения — это особые события, которые
прерывают нормальное выполнение программы.
Такой ситуации очень радуется Багги — он обожает, когда программа падает с ошибкой. А вот Коди знает, как справиться с ошибками
с помощью try-except, и он научит тебя писать устойчивый код.
Python предоставляет гибкий механизм обработки исключений,
который позволяет перехватывать и обрабатывать ошибки, не завершая выполнение программы аварийно.
Что такое ошибка и исключение?
Ошибка (Error)
Это любое отклонение от нормальной работы программы. В Python
можно выделить два типа ошибок.
• Синтаксические ошибки — ошибки в структуре кода.
• Исключения (Exceptions) — ошибки, возникающие во время
выполнения программы.
71
Глава 1.8
Исключение (Exception)
ЧАСТЬ 1
Это объект, который сообщает об ошибочной ситуации в программе.
Например:
print(10 / 0)
При обработке этой строки Python уведомит нас об этой ошибке:
ZeroDivisionError: division by zero
Ошибка деления на ноль: деление на ноль
В таблице ниже приведены наиболее частые примеры ошибок,
которые могут возникать на начальных этапах изучения языка Python.
ИСКЛЮЧЕНИЕ
ZeroDivisionError
Деление на ноль
TypeError
Операция между несовместимыми типами
переменных
ValueError
Неверное значение аргумента
IndexError
Обращение к несуществующему индексу
KeyError
FileNotFoundError
NameError
72
ОПИСАНИЕ
Отсутствие ключа в словаре
Попытка открыть несуществующий файл
Использование необъявленной переменной
Ошибки и исключения. Обработка исключений
Обработка исключений: конструкция try-except:
ЧАСТЬ 1
try
# код, который может вызвать исключение
except ИмяИсключения:
# обработка исключения
Пример
try:
number = int(input("Введите число: "))
print("100 /", number, "=", 100 / number)
except ZeroDivisionError:
print("Ошибка: деление на ноль!")
except ValueError:
print("Ошибка: вы ввели не число")
Несколько except и общее исключение.
Можно обрабатывать разные типы ошибок отдельно или сразу
несколько:
try:
f = open("data.txt")
content = f.read()
f.close()
except (FileNotFoundError, PermissionError):
print("Ошибка при работе с файлом.")
Если не указывать тип исключения, можно перехватить любую
ошибку:
try:
…
except:
print("Произошла неизвестная ошибка.")
Но Коди предупреждает: «Так лучше делать только в самом конце,
иначе ты можешь случайно “спрятать” важную ошибку!»
73
Глава 1.8
ЧАСТЬ 1
Обрати внимание на то, что не рекомендуется использовать except:
без указания типа, так как это может скрыть реальные ошибки и затруднить отладку.
Использование else и finally
Python поддерживает блоки else и finally для более точного управления потоком выполнения:
try:
number = int(input("Введите число: "))
except ValueError:
print("Это не число.")
else:
print("Вы ввели число:", number)
finally:
print("Завершение блока try-except.")
else выполняется, если не возникло исключений.
finally выполняется всегда, даже если возникло исключение — это
удобно для закрытия файлов, освобождения ресурсов и т. д.
Генерация исключений: raise
Можно самостоятельно вызывать исключения с помощью оператора raise.
def square_root(x):
if x < 0:
raise ValueError("Нельзя
"Нельзя извлекать корень из отрицательного числа.")
числа."
return x ** 0.5
Создание собственных исключений
Ты можешь определить собственные типы исключений, унаследовав
их от встроенного класса Exception:
class MyCustomError(Exception):
pass
74
Ошибки и исключения. Обработка исключений
def do_something():
raise MyCustomError("Это моя собственная ошибка!")
ЗАДАЧИ НА ЗАКРЕПЛЕНИЕ
МАТЕРИАЛА
Вот несколько задач для закрепления темы «Ошибки и исключения».
1. Напиши программу, которая делит два числа и обрабатывает:
1.1) деление на ноль;
1.2) ввод нечислового значения.
2. Напиши функцию, которая открывает файл и читает его
содержимое. Обработай исключения FileNotFoundError
и PermissionError.
3. Реализуй пользовательское исключение NegativeNumberError
и используй его в функции, которая принимает только положительные числа.
ЧАСТЬ 1
Исключения — это очень хороший инструмент для создания надёжных и устойчивых программ. Благодаря конструкции try-except
ты можешь контролировать поведение программы в случае ошибок
и принимать необходимые меры, не прерывая выполнение.
ГЛАВА 1.9
Циклы
в программировании:
цикл while
ВРЕМЯ НА ЧТЕНИЕ: 20 МИНУТ
Давай представим ситуацию: тебе нужно нарисовать на экране несколько объектов, например три круга. Можно просто написать
несколько одинаковых строк, вручную указывая координаты для
каждого круга.
Такой подход работает, если объектов немного, но он быстро
становится неудобным — ведь если понадобится изменить цвет или
размер, придётся переписывать каждую строку.
Коди наверняка подумал бы: «Хм, выглядит громоздко. А что, если
всё это можно сократить с помощью цикла?»
Теперь посмотрим, как выглядит такой «ручной» способ.
import pygame as pg
import sys
pg.init()
screen = pg.display.set_mode((800, 600))
pg.display.set_caption("Лети к курсору!")
# Координаты и размер круга
x, y, size = 400, 300, 60
# Рисуем несколько кругов вручную
screen.fill((0, 0, 0))
76
Циклы в программировании: цикл while
pg.draw.circle(screen, (255, 0, 0), (x - 100, y), size)
pg.draw.circle(screen, (0, 255, 0), (x, y), size)
pg.draw.circle(screen, (0, 0, 255), (x + 100, y), size)
ЧАСТЬ 1
pg.display.flip()
pg.time.delay(2000)
pg.quit()
Я просто скопировал строчку
с pg.draw.circle
три раза! Быстро и просто!
Хитро, но что, если кругов будет
не три, а сто? Или понадобится поменять цвет? При использовании цикла
ты меняешь одну строчку — и всё
работает! Программисты не копируют
по сто раз — они автоматизируют!
Отлично, теперь ты знаешь, как добавить на экран несколько
объектов, но наверняка уже заметил, что переписывать одинаковый код — не самое интересное занятие.
Пришло время автоматизировать этот процесс! На помощь приходит цикл while — он позволяет повторять нужные действия столько
раз, сколько захочешь, не дублируя код. Такой подход экономит время
и делает программу гораздо чище и понятнее. Сейчас ты увидишь,
насколько удобнее будет работать, если использовать цикл while
вместо копирования одних и тех же строк.
import pygame as pg
import sys
pg.init()
screen = pg.display.set_mode((800, 600))
pg.display.set_caption("Лети к курсору!")
77
Глава 1.9
# Координаты и размер круга
x, y, size = 400, 300, 60
ЧАСТЬ 1
# Рисуем круги с помощью цикла while
screen.fill((0, 0, 0))
offset = –100
colors = [(255, 0, 0), (0, 255, 0), (0, 0, 255)]
i = 0
while i < 3:
pg.draw.circle(screen, colors[i], (x + offset, y), size)
offset += 100
i += 1
pg.display.flip()
pg.time.delay(2000)
pg.quit()
Багги фыркнул бы: «Фу, скучно. Раньше было весело — кучу
строк вручную писать! А тут всё по порядку, да ещё и работает
как часы…»
В прошлых уроках тоже был цикл while True, он выполняет одну
и ту же последовательность шагов:
• проверяет, не кликнул ли кто мышкой или не попытался ли
выйти из игры;
• очищает экран;
• рисует круг на новом месте;
• обновляет картинку.
И так — бесконечно, пока не нажмёшь «выход».
ВОПРОСЫ ДЛЯ
САМОПРОВЕРКИ
1. Что произойдёт, если убрать строку while True из программы?
2. Что случится, если переместить строку screen.fill((0, 0, 0))
вверх, до цикла событий?
78
Циклы в программировании: цикл while
1. Измени программу с кругами так, чтобы каждый следующий
круг был меньше предыдущего на 10 пикселей.
2. Нарисуй «лесенку» из 7 красных прямоугольников, где каждый следующий прямоугольник смещён вправо и вниз.
3. Нарисуй 10 кругов случайного цвета. Для этого используй
функцию random.randint.
РАЗБОР ЗАДАЧИ № 1
«Круги разного размера»
Задача
Измени программу с кругами так, чтобы каждый следующий круг был
меньше предыдущего на 10 пикселей.
Решение
Давай подумаем, как это сделать. Нам нужно нарисовать, например,
5 кругов. Первый круг — самый большой, а каждый следующий — меньше на 10 пикселей. Значит, нам понадобится переменная, которая
будет хранить текущий размер круга и после каждого следующего
круга уменьшать его на 10.
Вот как это можно реализовать:
import pygame as pg
import sys
pg.init()
screen = pg.display.set_mode((800, 600))
pg.display.set_caption("Круги разного размера")
79
ЧАСТЬ 1
ЗАДАЧИ ДЛЯ
САМОСТОЯТЕЛЬНОЙ РАБОТЫ
Глава 1.9
ЧАСТЬ 1
x, y = 400, 300
size = 80 # Начальный размер круга
i = 0
screen.fill((0, 0, 0))
while i < 5:
pg.draw.circle(screen, (0, 255, 255), (x + i * 90, y), size)
size -= 10 # Уменьшаем размер круга
i += 1
pg.display.flip()
pg.time.delay(2000)
pg.quit()
Пояснение
• Мы начинаем с размера 80.
• Внутри цикла рисуем круг и сразу уменьшаем размер на 10.
• Каждый круг сдвигаем вправо (x + i * 90), чтобы избежать их
наложения друг на друга.
• Так мы получаем ряд из кругов, каждый из которых меньше
предыдущего!
Задачи с циклом while (без pygame)
1. Счётчик цифр
Запроси у пользователя любое натуральное число и посчитай, сколько в нём цифр.
2. Таблица умножения для числа
Запроси у пользователя число n и выведи таблицу умножения
для этого числа от 1 до 10.
3. Угадай число
Компьютер загадывает число от 1 до 100. Пользователь
пытается его угадать, вводя числа. После каждого ввода программа говорит, больше или меньше загаданное число. Цикл
продолжается, пока пользователь не угадает.
4. Все делители числа
Запроси у пользователя число и выведи все его делители.
80
Циклы в программировании: цикл while
Счётчик цифр
Задача
Попроси пользователя ввести любое натуральное число и посчитай,
сколько в этом числе цифр.
Решение
Давай разберёмся, как решить эту задачу с помощью цикла while. Нам
нужно «разбирать» число по одной цифре, пока оно не закончится.
Как это сделать? Очень просто: каждый раз будем делить число
на 10 (отбрасывать последнюю цифру), а перед этим увеличивать
счётчик на 1.
Вот пример кода:
n = int(input("Введи любое натуральное число: "))
count = 0
while n > 0:
n = n // 10 # Отбрасываем последнюю цифру
count += 1 # Увеличиваем счётчик
print("В этом числе цифр:", count)
Пояснение
• Пользователь вводит число, например 12345.
• Пока n больше нуля, цикл повторяется.
• В каждой итерации мы делим n на 10 (например, 12345 →
1234 → 123 → 12 → 1 → 0).
• Каждый раз при делении мы увеличиваем переменную count.
• Когда n становится равным 0, цикл заканчивается, и count содержит количество цифр.
81
ЧАСТЬ 1
РАЗБОР
ЗАДАЧИ № 2
Глава 1.9
ЧАСТЬ 1
Почему это работает?
Потому что каждое деление на 10 «съедает» одну цифру справа. Как
только число станет 0, это будет означать, что все цифры мы уже
«посчитали».
Вот так, шаг за шагом, ты учишься использовать цикл while для
самых разных задач. Не бойся экспериментировать — попробуй изменить цвета, размеры, количество объектов.
ГЛАВА 1.10
Циклы
в программировании:
цикл for
ВРЕМЯ НА ЧТЕНИЕ: 10 МИНУТ
Если ты уже использовал цикл while, то наверняка понял, насколько
это удобнее, чем бесконечно повторять одинаковый код. Но Python
даёт нам ещё один мощный инструмент — цикл for, который отлично
подходит для работы с наборами данных, списками координат или
цветов.
С помощью for можно легко создавать сложные сцены или анимации, а код станет ещё лаконичнее и нагляднее. Сейчас ты увидишь,
как просто и красиво можно управлять сразу несколькими объектами,
используя цикл for.
import pygame as pg
import sys
pg.init()
screen = pg.display.set_mode((800, 600))
pg.display.set_caption("Лети к курсору!")
# Координаты и размер круга
x, y, size = 400, 300, 60
# Рисуем круги с помощью цикла for
screen.fill((0, 0, 0))
colors = [(255, 0, 0), (0, 255, 0), (0, 0, 255)]
83
Глава 1.10
positions = [–100, 0, +100]
ЧАСТЬ 1
for pos_x, color in zip(positions, colors):
pg.draw.circle(screen, color, (x + pos_x, y), size)
pg.display.flip()
pg.time.delay(2000)
pg.quit()
ВОПРОСЫ ДЛЯ
САМОПРОВЕРКИ
1. Чем отличается цикл while от цикла for? В каких случаях удобнее использовать цикл while, а в каких — f or?
2. Попробуй догадаться, почему мы не объявляем переменныесчетчики до цикла for, как это было с циклом while?
ЗАДАЧИ ДЛЯ
САМОСТОЯТЕЛЬНОЙ РАБОТЫ
1. Нарисуй 6 зелёных квадратов в ряд с помощью цикла for.
2. Измени программу с кругами так, чтобы каждый круг был
на 10 пикселей меньше предыдущего.
3. Нарисуй «лесенку» из 8 синих прямоугольников, где каждый
следующий прямоугольник смещён вправо и вниз.
4. Нарисуй 12 кругов, у которых цвета выбираются случайно
(используй random.randint).
84
Циклы в программировании: цикл for
Пример с объяснением (pygame):
нарисуй 6 зелёных квадратов в ряд
Нарисуй 6 зелёных квадратов в ряд с помощью цикла for.
Решение
Давай подумаем, как это сделать. Нам нужно нарисовать 6 квадратов, расположенных в одну линию. Каждый квадрат будет зелёного
цвета, а их координаты по x будут увеличиваться на одинаковое
расстояние.
import pygame as pg
import sys
pg.init()
screen = pg.display.set_mode((800, 600))
pg.display.set_caption("Зелёные квадраты")
x, y, size = 100, 250, 60
screen.fill((0, 0, 0))
for i in range(6):
pg.draw.rect(screen, (0, 255, 0), (x + i * (size + 10), y,
size, size))
pg.display.flip()
pg.time.delay(2000)
pg.quit()
Пояснение
• Мы используем цикл for с функцией range(6), чтобы повторить действие 6 раз.
• Каждый раз рисуем квадрат на новой позиции: x + i *
(size + 10) — это координата по x, чтобы квадраты не накладывались друг на друга.
• Все квадраты одного цвета и размера.
• Код короткий, понятный и легко изменяемый!
85
ЧАСТЬ 1
Задача
Глава 1.10
ЧАСТЬ 1
Задачи без использования pygame
1. Выведи квадраты всех чисел от 1 до 15 с помощью цикла for.
2. Запроси у пользователя строку и выведи каждый символ этой
строки на новой строке.
3. Выведи таблицу умножения для числа, введённого пользователем (от 1 до 10).
4. Посчитай сумму всех нечётных чисел от 1 до 99.
5. Запроси у пользователя список чисел (через пробел) и выведи только те, что больше 10.
Пример с объяснением (без pygame):
выведи квадраты всех чисел от 1 до 15
Задача
Выведи квадраты всех чисел от 1 до 15 с помощью цикла for.
Решение
Цикл for отлично подходит для таких задач! Просто перебираем числа
от 1 до 15 и для каждого выводим его квадрат.
for n in range(1, 16):
print("Квадрат числа", n, "равен", n * n)
Пояснение
• range(1, 16) создаёт последовательность чисел от 1 до 15
включительно.
• На каждом шаге цикла переменная n принимает очередное
значение.
• Мы выводим само число и его квадрат (n * n).
• Такой код легко изменить под любой другой диапазон чисел!
ГЛАВА 1.11
Задачи на закрепление
материала
В этой главе тебя ждут задания, в которых тебе предстоит поэкспериментировать с повторяющимися действиями: нарисовать несколько
фигур, поменять параметры объектов, создать простую логику анимации.
Именно циклы — лучший помощник для таких задач. С их помощью
ты можешь создавать на экране целые узоры, динамичные эффекты
и даже элементы управления, которые легко можно добавить.
Помни: цикл — это словно команда повторить нужное действие
много раз.
Пример кода, на котором мы будем тренироваться и выполнять
задачи:
import pygame as pg, sys
pg.init()
screen = pg.display.set_mode((800, 600))
pg.display.set_caption("Лети к курсору!")
x, y, size = 400, 300, 60
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
sys.exit()
elif event.type == pg.MOUSEBUTTONDOWN:
x, y = pg.mouse.get_pos()
screen.fill((0, 0, 0))
pg.draw.circle(screen, (255, 0, 0), (x, y), size)
pg.display.flip()
pg.time.delay(10)
87
ЧАСТЬ 1
Глава 1.11
ЗАДАНИЯ ДЛЯ
САМОСТОЯТЕЛЬНОЙ ПРАКТИКИ
1. Нарисуй пять кругов подряд по горизонтали, используя
цикл for.
Попробуй изменить их цвет или размер так, чтобы они отличались друг от друга.
2. Создай «след» из кругов.
Не очищай экран внутри цикла — ты увидишь, как перемещающийся круг оставит за собой линию.
3. Задача посложнее.
Попробуй нарисовать сетку из кругов при помощи двух
вложенных циклов (for внутри for).
ГЛАВА 1.12
Строки
ВРЕМЯ НА ЧТЕНИЕ: 15 МИНУТ
Пришло время познакомиться с ещё одним важным инструментом
любого программиста — строками. Строки — это не просто текст,
который ты видишь на экране, а целые «контейнеры» для хранения
и обработки информации: имён, сообщений, подсказок, результатов
и даже кодов ошибок.
В программировании строки встречаются почти в каждом проекте.
Например, когда ты выводишь надпись «Лети к курсору!» в заголовке
окна или хочешь показать пользователю его счёт. Строки позволяют
делать программы понятнее и удобнее для людей.
Представь, что строки — это цепочка из букв, символов и даже
пробелов. Ты можешь «разбирать» эту цепочку, собирать новые слова, искать в ней нужные кусочки, заменять буквы и даже проверять,
сколько символов она содержит.
89
ЧАСТЬ 1
Глава 1.12
Давай посмотрим, как можно добавить работу со строками прямо
в твой проект на Pygame. Программа будет выводить на экран текст
с текущими координатами круга, и ты сможешь потренироваться
создавать и изменять строки в реальном времени!
import pygame as pg, sys
pg.init()
screen = pg.display.set_mode((800, 600))
pg.display.set_caption("Лети к курсору!")
x, y, size = 400, 300, 60
# Создаём объект шрифта для вывода текста
font = pg.font.SysFont(None, 36)
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
sys.exit()
elif event.type == pg.MOUSEBUTTONDOWN:
x, y = pg.mouse.get_pos()
screen.fill((0, 0, 0))
pg.draw.circle(screen, (255, 0, 0), (x, y), size)
90
Строки
ЧАСТЬ 1
# Создаём строку с координатами и выводим её на экран
coord_text = f"Координаты круга: x={x}, y={y}"
text_surface = font.render(coord_text, True, (255, 255, 255))
screen.blit(text_surface, (20, 20))
pg.display.flip()
pg.time.delay(10)
В этом примере мы использовали f-строку. f-строка — это особый
способ создавать строки, в которые прямо внутри текста можно
вставлять значения переменных, выражения или даже результаты
вычислений. Для этого перед кавычками строки нужно поставить
букву f, а внутри строки использовать фигурные скобки {} для подстановки переменных или выражений.
Вот как еще можно использовать f-строки:
name = "Аня"
score = 150
text = f"Игрок {name} набрал {score} очков!"
print(text)
# Выведет: Игрок Аня набрал 150 очков!
91
Глава 1.12
ЧАСТЬ 1
КОНТРОЛЬНЫЕ ВОПРОСЫ
ПО ТЕМЕ «СТРОКИ»
1. Что такое строка в Python и как её создать?
2. Как объединить две строки в одну? Приведи пример.
3. Как узнать длину строки? Какая функция для этого используется?
4. Как вывести на экран значение переменной вместе с текстом,
используя f-строку?
5. Как получить отдельный символ строки по его номеру (индексу)?
Задачи с использованием pygame
1. Добавь в свой код вывод строки с координатами круга в формате: "Координаты: x=400, y=300"
2. Используй f-строку и выведи этот текст на экран с помощью
Pygame.
3. Сделай так, чтобы в заголовке окна (через pg.display.set_
caption) отображалось количество кликов мышкой (используй преобразование числа в строку).
4. Пусть программа спрашивает у пользователя имя (через input() в начале) и выводит приветствие с этим именем
на экран игры.
Пример с объяснением (pygame):
вывод координат круга
Задача
Добавь в свой код вывод строки с координатами круга в формате:
"Координаты: x=400, y=300" — используй f-строку и выведи этот
текст на экран с помощью Pygame.
Решение
import pygame as pg, sys
92
Строки
ЧАСТЬ 1
pg.init()
screen = pg.display.set_mode((800, 600))
pg.display.set_caption("Лети к курсору!")
x, y, size = 400, 300, 60
font = pg.font.SysFont(None, 36)
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
sys.exit()
elif event.type == pg.MOUSEBUTTONDOWN:
x, y = pg.mouse.get_pos()
screen.fill((0, 0, 0))
pg.draw.circle(screen, (255, 0, 0), (x, y), size)
coord_text = f"Координаты: x={x}, y={y}"
text_surface = font.render(coord_text, True, (255, 255, 255))
screen.blit(text_surface, (20, 20))
pg.display.flip()
pg.time.delay(10)
Пояснение
В этом коде мы создаём строку с помощью f-строки, подставляя
значения переменных x и y прямо внутри текста. Затем рисуем эту
строку на экране с помощью Pygame. Теперь координаты всегда
видны пользователю!
Задачи без использования pygame
1. Запроси у пользователя строку и выведи её длину (количество символов).
2. Запроси у пользователя два слова и выведи их объединение
в одну строку.
3. Запроси у пользователя строку и выведи каждый символ этой
строки на новой строке.
4. Запроси у пользователя строку и выведи её задом наперёд.
93
Глава 1.12
ЧАСТЬ 1
5. Запроси у пользователя строку и выведи первый и последний
символ этой строки.
Пример с объяснением (без pygame):
вывести длину строки
Задача
Запроси у пользователя строку и выведи её длину (количество символов).
Решение
text = input("Введи любую строку: ")
length = len(text)
print(f"Длина строки: {length}")
Пояснение
Мы используем функцию len(), чтобы узнать, сколько символов
в строке, и выводим результат с помощью f-строки. Всё просто и очень
удобно!
ГЛАВА 1.13
Списки
ВРЕМЯ НА ЧТЕНИЕ: 25 МИНУТ
Теперь пришло время познакомиться с ещё одним очень полезным
инструментом программирования — списками. Списки помогают
хранить сразу много значений в одной переменной, а значит, делают
твой код чище, удобнее и мощнее.
Представь себе коробку, в которой лежат разные предметы: карандаши, ластики, линейки. В программировании список — это такая же
«коробка», только для чисел, строк, цветов или даже других списков!
Ты можешь добавлять, убирать и менять элементы в списке прямо
во время работы программы. Например, если ты хочешь нарисовать
не один, а сразу несколько кругов, будет гораздо удобнее хранить
их координаты и цвета в списках, а не в отдельных переменных.
95
Глава 1.13
ЧАСТЬ 1
Списки в Python создаются с помощью квадратных скобок, а элементы внутри разделяются запятыми. Вот пример списков с координатами и цветами:
# Списки координат и цветов для трёх кругов
positions = [(200, 300), (400, 300), (600, 300)]
colors = [(255, 0, 0), (0, 255, 0), (0, 0, 255)]
С помощью списков ты легко сможешь управлять сразу целой
коллекцией объектов, например нарисовать несколько кругов в разных местах экрана.
Пример кода с использованием списков
Давай изменим твой код так, чтобы программа рисовала сразу три
круга, используя списки для хранения их координат и цветов:
import pygame as pg, sys
pg.init()
screen = pg.display.set_mode((800, 600))
pg.display.set_caption("Лети к курсору!")
# Списки координат и цветов для трёх кругов
positions = [(200, 300), (400, 300), (600, 300)]
colors = [(255, 0, 0), (0, 255, 0), (0, 0, 255)]
size = 60
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
sys.exit()
elif event.type == pg.MOUSEBUTTONDOWN:
# Перемещаем все круги на позицию мыши
mouse_pos = pg.mouse.get_pos()
positions = [mouse_pos for _ in positions]
screen.fill((0, 0, 0))
96
Списки
Что важно знать о списках
• Список создаётся с помощью квадратных скобок: [элемент1,
элемент2, …].
• В списке можно хранить элементы любого типа: числа, строки, даже другие списки.
• К элементу списка можно обратиться по его номеру (индексу), начиная с нуля: список — это первый элемент.
• Списки можно изменять: добавлять, удалять и менять элементы прямо во время выполнения программы.
Попробуй еще запустить такой код в другом файле:
# Создаём список с разными фруктами
fruits = ["яблоко", "банан", "апельсин"]
# Добавляем новый элемент в список
fruits.append("груша")
# Выводим все элементы списка по очереди
for fruit in fruits:
97
ЧАСТЬ 1
for i in range(len(positions)):
pg.draw.circle(screen, colors[i], positions[i], size)
pg.display.flip()
pg.time.delay(10)
Глава 1.13
print(fruit)
ЧАСТЬ 1
# Узнаём длину списка
print("Всего фруктов:", len(fruits))
В этом примере
• Мы создали список fruits с тремя фруктами.
• С помощью метода .append() добавили ещё один фрукт.
• С помощью цикла for вывели все элементы списка по одному.
• В конце вывели количество элементов в списке с помощью
функции len().
КОНТРОЛЬНЫЕ ВОПРОСЫ
ПО ТЕМЕ «СПИСКИ»
1. Как создать список в Python? Приведи пример создания списка из нескольких элементов.
2. Как добавить элемент в конец списка? Как добавить элемент
по определённому индексу?
3. Чем отличаются методы remove() и pop() для удаления элементов из списка?
4. Как узнать длину списка? Как получить сумму всех чисел
в списке?
5. Как проверить, есть ли определённый элемент в списке, и как
объединить два списка в один?
Задачи с использованием pygame
1. Создай два списка: координаты и цвета для пяти кругов. Нарисуй все круги на экране, используя цикл.
2. Сделай так, чтобы при каждом клике мышкой все круги перемещались на новую случайную позицию (используй random).
3. Пусть программа запоминает все места, куда ты кликал мышкой, и рисует круги в этих точках (используй список для хранения координат).
98
Списки
Пример с объяснением (pygame):
нарисуй круги из списка
Задача
Создай два списка: координаты и цвета для пяти кругов. Нарисуй
все круги на экране, используя цикл.
Решение
import pygame as pg, sys
pg.init()
screen = pg.display.set_mode((800, 600))
pg.display.set_caption("Пять кругов")
positions = [(100, 300), (250, 300), (400, 300), (550, 300), (700, 300)]
colors = [(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 0), (255, 0, 255)]
size = 50
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
sys.exit()
screen.fill((0, 0, 0))
for i in range(len(positions)):
pg.draw.circle(screen, colors[i], positions[i], size)
pg.display.flip()
pg.time.delay(10)
Пояснение
Мы создали два списка: один для координат, другой для цветов.
С помощью цикла for рисуем каждый круг на своей позиции и своим
99
ЧАСТЬ 1
4. Измени цвета всех кругов на случайные при нажатии клавиши
пробел (используй списки для цветов).
5. Добавь возможность удалять последний круг из списка координат и цветов нажатием на клавишу Backspace.
Глава 1.13
ЧАСТЬ 1
цветом. Если захочешь добавить ещё круг — просто впиши координаты
и цвет в соответствующие списки!
Задачи без использования pygame
1. Создай список из пяти любых чисел. Добавь в него ещё одно
число и выведи итоговый список.
2. Дан список имён. Удали из него имя по значению и по индексу, а затем выведи результат.
3. Напиши программу, которая находит максимальное и минимальное число в списке из 10 случайных чисел.
4. Дан список чисел. С помощью цикла создай новый список,
в котором будут только чётные числа из исходного списка.
5. Даны два списка. Объедини их в один и отсортируй получившийся список по возрастанию.
Пример с объяснением (без pygame):
оставить только чётные числа
Задача
Дан список чисел. С помощью цикла создай новый список, в котором
будут только чётные числа из исходного списка.
Решение
numbers = [3, 8, 15, 22, 7, 10, 4, 13]
even_numbers = []
for num in numbers:
if num% 2 == 0:
even_numbers.append(num)
print("Чётные числа:", even_numbers)
Пояснение
Мы перебираем все числа из исходного списка. Если число делится
на 2 без остатка (num% 2 == 0), добавляем его в новый список even_
numbers. В итоге получаем список, состоящий только из чётных чисел!
ГЛАВА 1.14
Кортежи
ВРЕМЯ НА ЧТЕНИЕ: 15 МИНУТ
Ты уже умеешь работать со списками, переменными и строками,
а теперь пришло время узнать о кортежах — ещё одном важном типе
данных в Python. Кортежи часто встречаются в программах, особенно там, где нужно хранить несколько связанных между собой
значений, которые не должны изменяться. Например, координаты
точки на экране или цвет в формате RGB.
Что такое кортеж?
Кортеж — э то упорядоченная коллекция элементов, которую
нельзя изменить после создания. В отличие от списка, который
можно дополнять и редактировать, кортеж защищён от случайных
изменений.
Кортежи записываются в круглых скобках, а элементы внутри
разделяются запятыми. Например, координаты центра круга (x, y)
или цвет (255, 0, 0) в твоём Pygame-коде — это кортежи!
Кортежи отлично подходят для хранения данных, которые всегда
идут вместе и не должны меняться:
• координаты (x, y)
• цвет (R, G, B)
• дата (день, месяц, год)
• имя и возраст
101
ЧАСТЬ 1
Глава 1.14
Почему кортежи?
Кортежи делают код надёжнее и понятнее: если ты видишь кортеж,
значит, значения связаны и не будут изменены в программе случайным образом. Это помогает избежать ошибок и делает структуру
данных более логичной.
Пример кода с кортежами
Посмотри на свой код — ты уже использовал кортежи, даже не задумываясь об этом!
Вот пример, где координаты и цвет круга хранятся в виде кортежей:
import pygame as pg, sys
pg.init()
screen = pg.display.set_mode((800, 600))
pg.display.set_caption("Лети к курсору!")
# Кортеж для координат центра круга
center = (400, 300)
# Кортеж для цвета круга
color = (255, 0, 0)
size = 60
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
102
Кортежи
ЧАСТЬ 1
sys.exit()
elif event.type == pg.MOUSEBUTTONDOWN:
# Получаем позицию мыши как кортеж
center = pg.mouse.get_pos()
screen.fill((0, 0, 0))
pg.draw.circle(screen, color, center, size)
pg.display.flip()
pg.time.delay(10)
Что важно знать о кортежах
• Кортежи создаются с помощью круглых скобок: (элемент1,
элемент2, …).
• Элементы кортежа нельзя изменить, добавить или удалить
после создания.
• Кортежи могут содержать данные разных типов: числа, строки, даже другие кортежи или списки.
• К элементам кортежа можно обращаться по индексу, как
и в списках: center[0] — это x, center[1] — это y.
• Кортежи часто используют для передачи нескольких значений из функции или для хранения «неизменяемых наборов
данных».
103
ЧАСТЬ 1
Глава 1.14
С кортежами твои программы станут надёжнее и аккуратнее. Теперь
ты знаешь, как удобно хранить вместе связанные значения, которые
не должны меняться. Поэкспериментируй: попробуй использовать
кортежи для хранения других данных, например даты, настроек или
параметров объектов!
КОНТРОЛЬНЫЕ ВОПРОСЫ
ПО ТЕМЕ «КОРТЕЖИ»
1. Что такое кортеж в Python и чем он отличается от списка?
2. Как создать кортеж с одним элементом? Для чего нужна запятая?
3. Как получить доступ к элементу кортежа по индексу?
4. Какие встроенные функции можно применять к кортежам
(например, для определения длины, суммы, минимума, максимума)?
5. Можно ли изменить, добавить или удалить элемент в кортеже
после его создания? Почему?
ЗАДАЧИ НА ЗАКРЕПЛЕНИЕ
МАТЕРИАЛА
1. Создай кортеж из пяти любых чисел. Выведи на экран его
длину, минимальное и максимальное значение.
2. Преобразуй список ["яблоко", "банан", "груша"] в кортеж
и выведи его на экран.
3. Дан кортеж чисел. Сосчитай, сколько раз в нём встречается
число 7 (используй функцию count()).
4. Дан кортеж координат точки: (x, y). Напиши код, который распаковывает кортеж в две переменные и выводит их значения.
5. Проверь, есть ли в кортеже строка Python. Если есть — выведи «Нашёл!», если нет — «Не нашёл!» (используй оператор in).
ГЛАВА 1.15
Словари
ВРЕМЯ НА ЧТЕНИЕ: 20 МИНУТ
Ты уже умеешь работать со списками и кортежами, а теперь настало
время познакомиться с ещё одним очень полезным типом данных —
словарём. Словарь в Python — это как настоящий справочник или
телефонная книга: у каждого элемента есть свой «ключ» (например,
имя), по которому ты можешь быстро узнать нужную «информацию»
(например, номер телефона или адрес).
Что такое словарь?
Словарь — это коллекция пар «ключ: значение». Ключи должны быть
уникальными, а значения могут быть любыми: числами, строками,
списками, даже другими словарями! Словари очень удобны, когда
нужно хранить и быстро находить связанные данные по какому-то
признаку. Например, можно создать словарь, где каждому цвету будет
соответствовать своё имя, или хранить параметры разных объектов
по их идентификатору.
В Python словари записываются в фигурных скобках {}, а пары
ключ-значение разделяются двоеточием.
# Все параметры круга в одном словаре
circle_info = {
"color": (255, 0, 0),
"position": (400, 300),
105
Глава 1.15
"size": 60
}
ЧАСТЬ 1
Теперь ты можешь легко получить нужную информацию по ключу:
print(circle_info["color"]) # (255, 0, 0)
print(circle_info["position"]) # (400, 300)
Пример кода со словарём
Давай попробуем изменить твой код так, чтобы все параметры круга
хранились в одном словаре. Это удобно и пригодится, если ты захочешь добавить ещё свойства или создать несколько разных объектов:
import pygame as pg, sys
pg.init()
screen = pg.display.set_mode((800, 600))
pg.display.set_caption("Лети к курсору!")
# Все параметры круга в одном словаре
circle = {
"color": (255, 0, 0),
"position": (400, 300),
"size": 60
106
Словари
}
ЧАСТЬ 1
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
sys.exit()
elif event.type == pg.MOUSEBUTTONDOWN:
# Меняем позицию круга на позицию мыши
circle["position"] = pg.mouse.get_pos()
screen.fill((0, 0, 0))
pg.draw.circle(screen, circle["color"], circle["position"], circle["size"])
pg.display.flip()
pg.time.delay(10)
Почему словари так полезны?
• Можно быстро находить значения по ключу — не нужно помнить, в каком порядке что хранится.
• Легко добавлять новые свойства: нужно просто создать новую пару «ключ: значение».
• Словари делают код более читаемым и структурированным,
особенно если у объекта много параметров.
107
ЧАСТЬ 1
Глава 1.15
КОНТРОЛЬНЫЕ ВОПРОСЫ
ПО ТЕМЕ «СЛОВАРИ»
1. Как создать словарь в Python? Приведи пример с двумя парами «ключ: значение».
2. Как получить значение по ключу из словаря? Что произойдёт,
если ключа нет?
3. Как добавить новую пару «ключ: значение» в существующий
словарь?
4. Как перебрать все ключи и все значения в словаре с помощью цикла?
ЗАДАЧИ НА ЗАКРЕПЛЕНИЕ
МАТЕРИАЛА
1. Создай словарь, где ключ — имя ученика, а значение — его
оценка. Добавь ещё одну пару и выведи весь словарь.
2. Дан словарь с названиями предметов и их количеством. Увеличь количество одного из предметов на 5.
3. Напиши программу, которая выводит все ключи и все значения словаря по отдельности.
4. Проверь, есть ли в словаре определённый ключ (например,
имя ученика), и выведи соответствующее сообщение.
ГЛАВА 1.16
Параметры и аргументы
функции
ВРЕМЯ НА ЧТЕНИЕ: 20 МИНУТ
Теперь пришло время познакомиться с одной из самых мощных идей
в программировании — функциями, а именно с их параметрами и аргументами.
Что такое функция?
Функция — это как мини-программа внутри твоей программы. Она
может выполнять определённую задачу и возвращать результат.
Чтобы функция могла работать с разными данными, в неё можно
передавать значения. В определении функции эти «места для данных» называются параметрами — они как пустые коробки, которые
ждут, что ты в них что-то положишь. Когда ты вызываешь функцию
и передаёшь ей конкретные значения, эти значения называются
аргументами.
def greet(name):
print("Привет,", name)
greet("Аня")
109
ЧАСТЬ 1
Глава 1.16
В этом коде мы видим функцию greet, параметр name, и атрибут
«Аня».
Как ты думаешь, что произойдет, если запустить такой код?
Попробуй добавить к коду еще несколько строчек:
greet("Ваня")
greet("Миша")
Как ты мог заметить, после запуска нового кода мы получаем
приветствие еще и для других имен.
Давай теперь вернемся к нашему с тобой коду игры.
Модифицируем её с помощью функции:
import pygame as pg, sys
pg.init()
screen = pg.display.set_mode((800, 600))
pg.display.set_caption("Много кругов!")
# Функция для рисования всех кругов из списка
def draw_circles(screen, circles):
for circle in circles:
110
Параметры и аргументы функции
color, position, size = circle
pg.draw.circle(screen, color, position, size)
ЧАСТЬ 1
# Список кругов:
circles = [
((255, 0, 0),
((0, 255, 0),
((0, 0, 255),
]
каждый круг —
это кортеж (цвет, позиция, размер)
(200, 300), 50),
(400, 300), 60),
(600, 300), 40)
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
sys.exit()
screen.fill((0, 0, 0))
draw_circles(screen, circles)
pg.display.flip()
pg.time.delay(10)
Зачем тут функция?
Теперь ты можешь легко добавлять или убирать круги, менять их параметры, а функция draw_circles сама всё нарисует. Такой подход
111
Глава 1.16
ЧАСТЬ 1
делает код компактнее и позволяет переиспользовать одну функцию
для любых наборов кругов — вот тут параметры и аргументы действительно экономят время и делают твой проект гибче!
КОНТРОЛЬНЫЕ
ВОПРОСЫ
1. Чем отличаются параметры функции от аргументов функции?
Приведи пример.
2. Что произойдёт, если вызвать функцию с меньшим количеством аргументов, чем указано в определении?
3. Что произойдёт, если вызвать функцию с большим количеством аргументов, чем указано в определении?
ЗАДАЧИ
НА ЗАКРЕПЛЕНИЕ
Эти задачи нужно делать в отдельном файле.
1. Напиши функцию, которая принимает два числа и возвращает их сумму. Вызови её с разными аргументами.
2. Напиши функцию, которая принимает имя и фамилию как
ключевые аргументы и выводит их в формате «Фамилия Имя».
3. Задача со звездочкой. Придумай функцию, которая принимает список чисел и возвращает два значения: максимальное
и минимальное число из списка.
ГЛАВА 1.17
Возврат значений
из функции.
Оператор return
ВРЕМЯ НА ЧТЕНИЕ: 15 МИНУТ
Ты уже умеешь создавать свои функции, передавать им параметры
и использовать аргументы. Теперь пришло время узнать о том, как
функция может возвращать результат своей работы с помощью
специального оператора return.
Зачем нужен возврат значения из функции?
Когда ты вызываешь функцию, она может не только что-то делать
(например, рисовать круг), но и отдавать обратно результат своих
вычислений. Это очень удобно: ты можешь использовать результат
в других частях программы, сохранять его в переменную или сразу
подставлять в выражение. Такой подход делает код гибким, модульным и понятным.
Как работает оператор return?
Оператор return завершает выполнение функции и возвращает
значение, которое ты укажешь после него. Например:
def get_circle_area(radius):
area = 3.14 * radius * radius
return area # возвращаем вычисленную площадь круга
113
Глава 1.17
ЧАСТЬ 1
result = get_circle_area(10)
print(result) # выведет 314.0
Здесь функция возвращает площадь круга, мы сохраняем это
значение в переменную result и можем использовать его где угодно
в программе.
Что ещё важно знать?
• После оператора return выполнение функции сразу заканчивается — код после него не выполняется.
• Если не указать return, функция по умолчанию возвращает
None.
• Можно возвращать сразу несколько значений через запятую,
тогда они упакуются в кортеж.
Давай посмотрим, как будет работать этот код:
def get_center_and_size():
return 400, 300, 60
x, y, size = get_center_and_size()
print(x)
print(y)
print(size)
114
Возврат значений из функции. Оператор return
import pygame as pg, sys
pg.init()
screen = pg.display.set_mode((800, 600))
pg.display.set_caption("Лети к курсору!")
x, y, size = 400, 300, 60
# Функция, которая возвращает цвет в зависимости от координат
круга
def get_color(x, y):
r = x% 256
g = y% 256
b = (x + y)% 256
return (r, g, b) # возвращаем кортеж-цвет
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
sys.exit()
elif event.type == pg.MOUSEBUTTONDOWN:
x, y = pg.mouse.get_pos()
screen.fill((0, 0, 0))
color = get_color(x, y) # получаем цвет с помощью return
pg.draw.circle(screen, color, (x, y), size)
pg.display.flip()
pg.time.delay(10)
115
ЧАСТЬ 1
Попробуй запустить его у себя в новом файле, и ты увидишь, что
данные, которые передались с помощью return, в таком же порядке
записались в соответствующие переменные.
Теперь давай модифицировать код нашей игры. С помощью return
функция может возвращать результат, который мы потом используем
в основном цикле.
Например, сделаем функцию, которая рассчитывает новый цвет
круга в зависимости от координат и возвращает этот цвет. Мы будем
вызывать эту функцию каждый раз при рисовании круга.
ЧАСТЬ 1
Глава 1.17
Как это работает
• Функция get_color(x, y) вычисляет значения r, g и b на основе координат и возвращает их с помощью return.
• В основном цикле мы вызываем эту функцию, получаем результат и используем его для рисования круга.
• Теперь цвет круга будет меняться в зависимости от его положения, а ты на практике увидишь, как работает возврат значения из функции!
КОНТРОЛЬНЫЕ
ВОПРОСЫ
1. Для чего используется оператор return в функции?
2. Что произойдёт, если в функции не написать return? Какое
значение вернёт функция по умолчанию?
3. Можно ли вернуть из функции сразу несколько значений?
Как это сделать?
4. Как использовать результат, который возвращает функция,
в основном цикле программы?
ЗАДАЧИ НА ЗАКРЕПЛЕНИЕ
МАТЕРИАЛА
1. Сделай функцию, которая возвращает новые координаты круга (то есть значения x и y), и вызывай её кликом мышки. При
этом должен отрисовываться новый круг на этих координатах.
2. Реализуй функцию, которая возвращает True, если круг находится в левой половине экрана, и False — если в правой. Используй результат для смены цвета круга.
3. Задача со звездочкой. Напиши функцию, которая возвращает
строку с описанием позиции круга (например, "x=100, y=200"),
и выводи её на экран с помощью Pygame.
ДЛЯ ЗАМЕТОК
ЧАСТЬ 2
ГЛАВА 2.1
Знакомство с Pygame
ВРЕМЯ НА ЧТЕНИЕ: 15 МИНУТ
Привет, юный программист! Если ты дошел до этой главы, значит, ты
уже освоил основы Python: умеешь работать с переменными, циклами,
условиями и функциями. Но знаешь, что самое крутое в программировании? Создание собственных игр!
Совсем скоро ты сможешь:
• создать свой первый кликер (что-то вроде той самой тапалки
с хомяком),
• добавить взрывы, звуки и анимации — да всё, что подскажет
фантазия!
Вторая часть книги — это твой билет в мир настоящей игровой
разработки. Мы начнём с простого — с создания окна игры, а закончим… ну, скажем так: к концу ты удивишься, сколько всего сможешь
сделать своими руками!
И первая остановка на этом пути — библиотека Pygame. Это твой
новый лучший друг, волшебная палочка, которая превращает скучный
код в живые миры. Готов? Поехали!
Что такое Pygame?
Pygame — это набор инструментов для создания игр на Python. С его
помощью можно:
• рисовать графику (круги, прямоугольники, картинки);
• управлять персонажами с клавиатуры и мыши;
120
Знакомство с Pygame
• проигрывать звуки и музыку;
• создавать анимации и спецэффекты.
Звучит здорово, правда? Давай установим Pygame и сделаем наше
первое игровое окно!
Прежде чем начать, нужно установить Pygame. Открой терминал (или
командную строку) и введи:
Если у тебя Python 3.11 или новее и установка не работает, попробуй так:
(Флаг '—pre' позволяет установить тестовую версию, которая
поддерживает новые версии Python.)
После установки можно проверить, всё ли работает:
121
ЧАСТЬ 2
Установка Pygame
(если ты начал читать книгу со 2-й части)
Глава 2.1
Если ты видишь номер версии — отлично! Pygame готов к использованию.
Первое окно в Pygame
Любая игра начинается с окна. Давай создадим простейшее игровое
окно с черным фоном.
1. Импортируем Pygame и инициализируем его
ЧАСТЬ 2
Первым делом нужно подключить библиотеку в твою программу
и запустить её:
pygame.init() — это важная строка, она активирует все необходимые
модули Pygame (графику, звук, управление и т. д.).
2. Создаём окно игры
Теперь создадим окно размером 800 на 600 пикселей:
screen_width и screen_height — ширина и высота окна.
pygame.display.set_mode() — создаёт окно с указанными размерами.
3. Даем окну название
Чтобы окно не было безымянным, добавим заголовок:
4. Основной игровой цикл
Игры работают в бесконечном цикле, который обновляет экран
и обрабатывает события (например, нажатия клавиш). Создадим
такой цикл:
122
Знакомство с Pygame
ЧАСТЬ 2
Что здесь происходит?
1. while running: — главный цикл игры, который работает, пока
'running = True'.
2. pygame.event.get() —
проверяет события (например, клик
на крестик окна).
3. if event.type == pygame.QUIT: — если игрок закрыл окно, игра
завершается.
4. screen.fill((0, 0, 0)) — заливает экран чёрным цветом.
123
Глава 2.1
5. pygame.display.flip() — обновляет экран.
6. pygame.quit() — завершает работу Pygame при выходе.
Запускаем игру!
ЧАСТЬ 2
Сохрани код в файл my_first_game.py и запусти его.
Пока это просто пустое окно, но уже в следующей главе мы добавим графику: фигуры и фон!
Что запомнить?
• Pygame — библиотека для создания игр на Python.
• Любая игра начинается с инициализации Pygame (pygame.
init()).
• Главный цикл игры обрабатывает события и обновляет экран.
• screen.fill() заливает экран цветом, а pygame.display.flip()
обновляет изображение.
124
Знакомство с Pygame
МИНИ-ЗАДАНИЕ
Попробуй изменить:
1. размер окна (например, 1024×768);
2. цвет фона (вместо (0, 0, 0) используй (255, 0, 0) — это
будет красный).
В следующей главе мы начнём рисовать в этом окне фигуры,
картинки и создадим первого игрового персонажа!
ЧАСТЬ 2
ГЛАВА 2.2
Окно игры и графика
ВРЕМЯ НА ЧТЕНИЕ: 20 МИНУТ
Отлично! У нас уже есть игровое окно, но пока оно просто чёрное.
Давай научимся рисовать в нём разные объекты. Сегодня мы узнаем:
• как рисовать геометрические фигуры;
• как работать с цветами;
• как загружать картинки;
• как оживить нашу графику.
1. Рисуем прямоугольник
Вот наша первая команда для рисования:
pygame.draw.rect(screen, (255, 0, 0), (50, 50, 100, 80))
Разберём все параметры по порядку:
1. screen — это наше игровое окно, где мы рисуем
2. (255, 0, 0) — цвет прямоугольника (красный)
3. (50, 50, 100, 80) — параметры прямоугольника:
» Первые два числа 50, 50 — это координаты X и Y верхнего
левого угла прямоугольника. Проще говоря, мы отступаем
50 пикселей от верхней и от левой границ экрана, и именно
в этом месте начинаем рисовать наш прямоугольник
» 100 — ширина прямоугольника
» 80 — высота прямоугольника
126
Окно игры и графика
Представь, что экран — это тетрадный лист и ты
рисуешь на нём фигуры, отступив от края вправо
и вниз. Координаты (50, 50) — это как если бы ты
поставил карандаш в начальную точку и отступил
от неё на 50 клеток вправо и 50 — вниз, а потом
стал рисовать прямоугольник!
2. Рисуем другие фигуры
Теперь давай добавим ещё фигур. Вот как рисуется круг:
Здесь:
1. (0, 0, 255) — синий цвет
2. (200, 200) — координаты центра круга (точно так же мы отступаем 200 пикселей от верхней и от левой границ экрана,
и именно в этом месте будет располагаться центр круга)
3. 50 — радиус круга 50 пикселей
А вот линия:
pygame.draw.line(screen, (0, 255, 0), (300, 150), (400, 250), 5)
Тут:
1. (0, 255, 0) — зелёный цвет
2. (300, 150) — координаты начальной точки линии
3. (400, 250) — координаты конечной точки линии
4. 5 — толщина линии 5 пикселей
3. Работаем с цветами
Давай разберёмся с цветами подробнее, потому что это очень важная
основа для создания игр!
127
ЧАСТЬ 2
pygame.draw.circle(screen, (0, 0, 255), (200, 200), 50)
Глава 2.2
Что такое RGB?
RGB — это способ создания цветов путем смешивания трёх основных
цветов:
1. Red (красный)
2. Green (зелёный)
3. Blue (синий)
Каждый цвет задаётся тремя числами от 0 до 255, например:
• (255, 0, 0) — ярко-красный
• (0, 255, 0) — ярко-зелёный
• (0, 0, 255) — ярко-синий
Как работают эти числа?
ЧАСТЬ 2
Представь, что у тебя есть три фонарика:
Красный
Зелёный
Синий
Числа от 0 до 255 — это регуляторы яркости каждого фонарика:
• 0 — фонарик выключен
• 255 — фонарик светит на полную мощность
Примеры смешивания
1. (255, 0, 0) — только красный
2. (0, 255, 0) — только зелёный
3. (0, 0, 255) — только синий
4. (255, 255, 0) — красный + зелёный = жёлтый
5. (0, 255, 255) — зелёный + синий = бирюзовый
6. (255, 0, 255) — красный + синий = фиолетовый
7. (255, 255, 255) —
все три фонарика светят на максимум =
белый
8. (0, 0, 0) — все три фонарика выключены = чёрный
Можно экспериментировать с числами! Например:
• (255, 100, 0) — оранжевый
• (150, 0, 150) — тёмно-фиолетовый
• (50, 50, 50) — тёмно-серый
128
Окно игры и графика
Теперь давай создадим удобные переменные.
Добавь их в начало программы после строк с созданием экрана:
ЧАСТЬ 2
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
Теперь можно писать понятнее:
pygame.draw.rect(screen, RED, (50, 50, 100, 80))
4. Добавляем картинки
Чтобы добавить изображение
1. Создай папку images рядом с программой
2. Найди любое изображение в интернете или среди своих изображений на компьютере и положи в эту папку
3. Добавь код.
Этот код мы напишем в начале программы (после pygame.init())
hero = pygame.image.load('images/hero.png')
hero.png — название файла с картинкой, оно может отличаться,
необходимо написать название именно твоего файла!
129
Глава 2.2
4. Чтобы нарисовать картинку:
screen.blit(hero, (100, 100))
Здесь (100, 100) — координаты верхнего левого угла картинки
(точно так же, как с координатами прямоугольника).
5. Делаем анимацию
Давай заставим нашего героя двигаться.
1. Добавь переменные для позиции:
hero_x = 100
hero_y = 100
ЧАСТЬ 2
2. В игровом цикле изменяй позицию:
hero_x += 1 # Двигаем вправо
if hero_x > 800: # Если ушел за экран
hero_x = 0 # Возвращаем в начало
screen.blit(hero, (hero_x, hero_y))
130
Окно игры и графика
Полный код программы
import pygame
pygame.init()
# Настройки окна
WIDTH = 800
HEIGHT = 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Моя первая графика")
# Цвета
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
ЧАСТЬ 2
# Загрузка картинки
hero = pygame.image.load('images/hero.png')
hero_x = 100
hero_y = 100
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Заливаем фон
screen.fill(BLACK)
# Рисуем фигуры
pygame.draw.rect(screen, RED, (50, 50, 100, 80))
pygame.draw.circle(screen, BLUE, (200, 200), 50)
# Двигаем и рисуем героя
hero_x += 1
if hero_x > ширина:
131
Глава 2.2
hero_x = 0
screen.blit(hero, (hero_x, hero_y))
pygame.display.flip()
pygame.quit()
Что мы узнали
ЧАСТЬ 2
•
•
•
•
Как рисовать разные фигуры и понимать их параметры.
Как задавать цвета.
Как работать с изображениями.
Как создать простую анимацию.
Теперь попробуй сам!
1. Нарисуй треугольник (используй pygame.draw.polygon).
2. Сделай так, чтобы герой двигался по вертикали.
3. Добавь еще одну картинку, которая будет двигаться в другую
сторону.
Уже в следующей главе мы научимся управлять событиями, например будем управлять героем с клавиатуры!
ГЛАВА 2.3
Управление персонажем
ВРЕМЯ НА ЧТЕНИЕ: 15 МИНУТ
Отлично! Предыдущая глава закончилась на том, что наш герой
двигается сам по себе, но в настоящих играх герои должны реагировать на действия игрока. Давай научимся управлять персонажем
с клавиатуры!
Что нового мы узнаем?
•
•
•
•
Как обрабатывать нажатия клавиш
Как сделать плавное движение
Как ограничивать перемещение в рамках экрана
Как обрабатывать клики мышкой
1. Обработка нажатий клавиш
Давай модернизируем наш код. Вот как узнать, какая клавиша
нажата:
keys = pygame.key.get_pressed() # Получаем состояние всех клавиш
if keys[pygame.K_LEFT]: # Если нажата стрелка влево
hero_x -= 5
if keys[pygame.K_RIGHT]: # Если нажата стрелка вправо
hero_x += 5
133
Глава 2.3
ЧАСТЬ 2
if keys[pygame.K_UP]: # Если нажата стрелка вверх
hero_y -= 5
if keys[pygame.K_DOWN]: # Если нажата стрелка вниз
hero_y += 5
Что важно запомнить
• pygame.K_LEFT, pygame.K_RIGHT — это коды клавиш стрелок
влево и вправо
• Число 5 — это скорость движения (её можно менять)
• Код нужно поместить в игровой цикл, перед обновлением
экрана
2. Плавное движение с ограничениями
Чтобы герой не убегал за экран, добавим проверки:
# Ограничиваем движение по горизонтали
if hero_x < 0:
hero_x = 0
if hero_x > WIDTH —
50: # 50 —
примерная ширина спрайта
hero_x = WIDTH —
50
# Ограничиваем движение по вертикали
if hero_y < 0:
hero_y = 0
134
Управление персонажем
if hero_y > HEIGHT —
70: # 70 —
примерная высота спрайта
hero_y = HEIGHT —
70
3. Обработка кликов мышкой
Добавим реакцию на клики. В игровом цикле, где мы обрабатываем
события, добавим:
ЧАСТЬ 2
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN: # Если кликнули мышкой
if event.button == 1: # Левая кнопка мыши
print("Клик в координатах:", event.pos)
# Можно добавить действие, например:
pygame.draw.circle(screen, RED, event.pos, 20)
4. Полный обновлённый код
import pygame
pygame.init()
# Настройки окна
135
Глава 2.3
WIDTH = 800
HEIGHT = 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Управление героем")
# Цвета
BLACK = (0, 0, 0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
# Загрузка картинки
hero = pygame.image.load('images/hero.png')
hero_x = 100
hero_y = 100
speed = 5 # мы завели отдельную переменную для скорости
ЧАСТЬ 2
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1: # Левый клик
print("Клик в:", event.pos)
# Управление с клавиатуры
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
hero_x -= speed
if keys[pygame.K_RIGHT]:
hero_x += speed
if keys[pygame.K_UP]:
hero_y -= speed
if keys[pygame.K_DOWN]:
hero_y += speed
# Ограничение движения
hero_x = max(0, min(hero_x, WIDTH —
50))
136
Управление персонажем
hero_y = max(0, min(hero_y, HEIGHT —
70))
# Отрисовка
screen.fill(BLACK)
screen.blit(hero, (hero_x, hero_y))
pygame.display.flip()
pygame.quit()
Что мы узнали
•
•
•
•
Теперь наш герой двигается по нажатию клавиш ← → ↑ ↓.
Персонаж не может выйти за границы экрана.
Игра реагирует на клики мышкой.
Мы научились контролировать скорость движения.
1. Добавь новую клавишу для ускорения (например, Shift,
в Python это K_LSHIFT или K_RSHIFT).
2. Сделай так, чтобы при клике появлялся след из кружков.
ЧАСТЬ 2
ПОПРОБУЙ САМ!
ГЛАВА 2.4
Создание игры «Кликер»
ВРЕМЯ НА ЧТЕНИЕ: 120 МИНУТ
ВРЕМЯ НА НАПИСАНИЕ КОДА: 45 МИНУТ
Что такое кликер?
Кликер — это простая компьютерная игра, в которой основное действие игрока заключается в нажатии на кнопку (компьютерную мышку)
для того, чтобы накапливать очки, ресурсы или деньги. За эти ресурсы игрок может покупать улучшения, которые ускоряют процесс
накопления — автоматически или за каждое нажатие.
В этой главе мы создадим свою версию кликера. Коди уже всё
продумал — мы начнём с самого простого варианта, а затем постепенно будем добавлять новые возможности. Цель игры — набрать
138
Создание игры «Кликер»
как можно больше очков, кликая по кнопке. В процессе работы мы
добавим таймер, звук, эффекты и другие интересные детали. Но будь
внимателен — Багги не дремлет, он попытается подкинуть ошибки
и сбить с толку.
Первый шаг — простой кликер
Для начала сделаем простую версию кликера. В центре экрана расположена красная кнопка. Каждый раз, когда по ней кликают, счётчик
увеличивается на 1. Такой подход одобрил даже Коди, ведь с него
легко начать и постепенно двигаться к усложнениям. Код выглядит
вот так:
import pygame
import sys
ЧАСТЬ 2
pygame.init()
# Настройки окна
WIDTH, HEIGHT = 400, 400
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Кликер")
# Цвета
WHITE = (255, 255, 255)
RED = (255, 0, 0)
BLACK = (0, 0, 0)
# Кнопка
button_width, button_height = 100, 100
button_x = (WIDTH —
button_width) // 2
button_y = (HEIGHT —
button_height) // 2
button_rect = pygame.Rect(button_x, button_y, button_width,
button_height)
# Счётчик
counter = 0
font = pygame.font.Font(None, 36)
139
Глава 2.4
# Главный цикл
running = True
while running:
screen.fill(WHITE)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1: # Левая кнопка мыши
if button_rect.collidepoint(event.pos):
counter += 1
ЧАСТЬ 2
pygame.draw.rect(screen, RED, button_rect)
counter_text = font.render(str(counter), True, BLACK)
counter_rect = counter_text.get_rect(center=(WIDTH // 2, HEIGHT // 4))
screen.blit(counter_text, counter_rect)
pygame.display.flip()
pygame.quit()
sys.exit()
РИС. 2.4.1. НАЧАЛЬНЫЙ ВАРИАНТ ИГРЫ «КЛИКЕР»
140
Создание игры «Кликер»
Давай разберём этот код по частям, чтобы тебе стало понятно,
как он работает и что делает каждая строка.
Подключаем нужные библиотеки
import pygame
import sys
Сначала мы подключим две библиотеки:
• pygame — она нужна для работы с графикой, звуками и событиями (например, клики мышки), о ней мы подробно рассказали
выше.
• sys — с её помощью мы сможем закрыть игру полностью, когда она завершится.
Запуск Pygame
ЧАСТЬ 2
pygame.init()
Эта строка включает Pygame.
Настройки окна
WIDTH, HEIGHT = 400, 400
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Кликер")
141
Глава 2.4
• WIDTH и HEIGHT — это размеры окна игры. В данном случае —
400×400 пикселей.
• pygame.display.set_mode(…) — создаёт само окно с заданными
размерами.
• set_caption(…) — устанавливает название окна. Оно отображается в верхней части (где обычно пишется название программы).
Цвета
ЧАСТЬ 2
WHITE = (255, 255, 255)
RED = (255, 0, 0)
BLACK = (0, 0, 0)
Цвета в Pygame задаются через три числа: красный, зелёный и синий (RGB). Каждое число имеет обозначение от 0 до 255. Например:
• (255, 0, 0) —
это красный, потому что максимум только
у красного канала.
• (255, 255, 255) — белый (все цвета на максимуме).
• (0, 0, 0) — чёрный (все цвета выключены).
Эти переменные мы используем для того, чтобы нарисовать фон,
кнопку и текст.
Кнопка
button_width, button_height = 100, 100
button_x = (WIDTH —
button_width) // 2
button_y = (HEIGHT —
button_height) // 2
button_rect = pygame.Rect(button_x, button_y, button_width, button_height)
Здесь мы создаём прямоугольник, который будет кнопкой.
• Размер кнопки — 100×100 пикселей.
• Расположение — по центру окна. Для этого мы вычтем ширину кнопки из ширины окна и разделим пополам — так она
окажется ровно по центру.
• pygame.Rect(…) — создаёт прямоугольник, с которым мы можем
потом работать (проверять, кликнули ли по нему, и рисовать
его).
142
Создание игры «Кликер»
Счётчик и шрифт
font = pygame.font.Font(None, 36)
Главный цикл игры
running = True
while running:
Это главный цикл игры. Он повторяется снова и снова, пока игра
работает.
• running = True — переменная, которая управляет работой цикла.
• while running: — пока running истинно (то есть True), игра будет
работать.
Очистка экрана
screen.fill(WHITE)
Перед каждым новым кадром экран нужно очищать. Здесь мы
заливаем весь экран белым цветом.
143
ЧАСТЬ 2
• counter = 0 — это переменная, в которой будет храниться информация о том, сколько раз игрок нажал на кнопку.
• font = pygame.font.Font(None, 36) — создаёт шрифт для текста. 36 — это размер шрифта. None — значит, берётся шрифт
по умолчанию.
Глава 2.4
Обработка событий
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
Этот кусок кода проверяет, что делает игрок:
• pygame.event.get() —
получает список событий (движения
мышки, нажатия и т. д.);
• если event.type == pygame.QUIT — это значит, что игрок нажал
на крестик (закрыть окно). В этом случае мы ставим running =
False, чтобы выйти из цикла.
ЧАСТЬ 2
Проверка клика по кнопке
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1: # Левая кнопка мыши
if button_rect.collidepoint(event.pos):
counter += 1
Проверяем, нажал ли игрок на кнопку мыши.
• event.type == MOUSEBUTTONDOWN — нажата кнопка мыши.
• event.button == 1 — это левая кнопка.
• button_rect.collidepoint(event.pos) — проверяет, попадает ли
координата мышки в кнопку.
• Если всё совпадает, увеличиваем счётчик: counter += 1.
Рисуем кнопку
pygame.draw.rect(screen, RED, button_rect)
Теперь рисуем кнопку — красный прямоугольник на экране.
Рисуем счётчик
counter_text = font.render(str(counter), True, BLACK)
counter_rect = counter_text.get_rect(center=(WIDTH // 2, HEIGHT // 4))
screen.blit(counter_text, counter_rect)
144
Создание игры «Кликер»
• font.render(…) — создаёт текст из числа counter.
• True — означает, что используется сглаживание (чтобы текст
был красивым).
• BLACK — цвет текста.
• get_rect(center=…) —
размещает текст по центру (в данном
случае по горизонтали, а по вертикали — чуть выше центра).
• blit(…) — рисует текст на экране.
Обновляем экран
pygame.display.flip()
Эта строка обновляет экран, чтобы всё, что мы нарисовали, стало
видно. Без неё ничего не появится.
Закрытие игры
ЧАСТЬ 2
pygame.quit()
sys.exit()
• pygame.quit() — выключает Pygame.
• sys.exit() — завершает программу полностью.
Второй шаг — улучшаем наш кликер!
Добавляем таймер
Играть бесконечно — это скучно. Коди предложил добавить таймер
на 30 секунд, чтобы игрок чувствовал азарт и ограничение по времени. Когда время закончится, игра завершится и отобразится финальный результат. Это также даёт повод задуматься над улучшением
эффективности кликов.
import time
# До основного цикла добавляется:
start_time = time.time()
game_duration = 30 # секунд
145
Глава 2.4
ЧАСТЬ 2
time.time() возвращает текущее время в секундах с начала эпохи
(очень большое число).
Мы сохраняем это число в start_time, чтобы потом сравнивать,
сколько прошло времени.
game_duration — отображает время игры (здесь — 30 секунд).
Теперь в главном цикле нужно вычислить оставшееся время:
elapsed_time = time.time() —
start_time
remaining_time = max(0, int(game_duration —
elapsed_time))
• time.time() —
start_time — количество секунд, прошедших
с начала игры.
• game_duration — elapsed_time — количество секунд, оставшихся до конца игры.
• int(…) — округляем в меньшую сторону до целого числа (например, 29.8 → 29).
• max(0, …) — вводим, чтобы значение не стало отрицательным.
Даже если прошло больше 30 секунд, мы показываем 0.
Если время вышло, больше кликать нельзя. Добавим отображение
таймера:
# Отображение таймера
timer_text = font.render(f"Время: {remaining_time}", True, BLACK)
screen.blit(timer_text, (10, 10))
146
Создание игры «Кликер»
# Если время вышло, показываем сообщение
if remaining_time == 0:
game_over_text = font.render("Время вышло!", True, BLACK)
screen.blit(game_over_text, (WIDTH // 2–100, HEIGHT —
50))
Проверяем: если remaining_time == 0, значит, игра окончена. Создаём надпись «Время вышло!» Размещаем её ближе к нижней части
экрана, по центру.
WIDTH // 2–100 — вводим, чтобы надпись оказалась примерно
по центру (но можно подогнать точнее).
Также стоит запретить увеличение счёта после окончания времени:
if button_rect.collidepoint(event.pos) and remaining_time > 0:
counter += 1
Делаем кнопку красивее
По мнению Коди, визуальные детали важны — они делают игру эстетичнее. Прямоугольник — это скучно. Вместо него можно нарисовать
круг. Багги, конечно, возражает, мол «давай нарисуем треугольник»,
но мы не станем его слушать!
147
ЧАСТЬ 2
• button_rect.collidepoint(event.pos) —
нажатие мышкой
на кнопку.
• emaining_time > 0 — проверка, сколько времени ещё осталось.
Увеличивайте счёт только в том случае, если вы прошли обе
проверки.
Если убрать remaining_time > 0, то после окончания времени
всё ещё можно будет нажимать кнопку и накручивать счёт, но это
нечестно.
Глава 2.4
ЧАСТЬ 2
Изменим отрисовку кнопки:
pygame.draw.circle(screen, RED, (button_x + button_width // 2,
button_y + button_height // 2), 50)
Теперь кнопка круглая и более приятная на вид. Чтобы проверка
клика тоже работала, потребуется внести небольшое изменение,
но пока можно оставить проверку как для прямоугольника — это
не критично.
Добавляем звук
Чтобы игра ощущалась живой, добавим звук при нажатии. Для этого
нужен звуковой файл (например, click.wav), который должен лежать
в той же папке, где находится игра.
Добавим:
click_sound = pygame.mixer.Sound("click.wav")
А при нажатии кнопки:
click_sound.play()
Если звука нет, строку можно временно закомментировать, чтобы
не было ошибки.
148
Создание игры «Кликер»
Улучшаем интерфейс
Сделаем фон не белым, а чуть более гармоничным, например светло-серым:
GRAY = (200, 200, 200)
# Внутри цикла:
screen.fill(GRAY)
Также можно увеличить шрифт счётчика и таймера:
font = pygame.font.Font(None, 48)
Полный код с улучшениями:
ЧАСТЬ 2
import pygame
import sys
import time
pygame.init()
WIDTH, HEIGHT = 400, 400
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Кликер")
# Цвета
GRAY = (200, 200, 200)
RED = (255, 0, 0)
BLACK = (0, 0, 0)
# Шрифт
font = pygame.font.Font(None, 48)
# Кнопка
button_width, button_height = 100, 100
button_x = (WIDTH —
button_width) // 2
button_y = (HEIGHT —
button_height) // 2
button_rect = pygame.Rect(button_x, button_y, button_width,
button_height)
149
Глава 2.4
# Счётчик и таймер
counter = 0
start_time = time.time()
game_duration = 30
# Звук
# click_sound = pygame.mixer.Sound("click.wav")
# Раскомментировать, если есть файл
running = True
while running:
screen.fill(GRAY)
elapsed_time = time.time() —
start_time
remaining_time = max(0, int(game_duration —
elapsed_time))
ЧАСТЬ 2
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
if button_rect.collidepoint(event.pos) and remaining_time > 0:
counter += 1
# click_sound.play()
# Кнопка
pygame.draw.circle(screen, RED, (button_x + button_width // 2,
button_y + button_height // 2), 50)
# Счётчик
counter_text = font.render(f"Очки: {counter}", True, BLACK)
counter_rect = counter_text.get_rect(center=(WIDTH // 2,
HEIGHT // 4))
screen.blit(counter_text, counter_rect)
# Таймер
timer_text = font.render(f"Время: {remaining_time}", True, BLACK)
screen.blit(timer_text, (10, 10))
150
Создание игры «Кликер»
if remaining_time == 0:
game_over_text = font.render("Время вышло!", True, BLACK)
screen.blit(game_over_text, (WIDTH // 2–100, HEIGHT —
50))
pygame.display.flip()
pygame.quit()
sys.exit()
Проверь, не упустил ли ты что-то. Твой код должен быть похож
на пример выше. Коди наверняка похвалил бы тебя за аккуратную
работу, а Багги — ну, он сейчас злится из-за того, что у него не получилось испортить игру ошибкой! На этом урок подошёл к концу. Ты
можешь и дальше улучшать свою игру-кликер, добавляя всё больше
возможностей!
ЧАСТЬ 2
РИС. 2.4.2. ФИНАЛЬНЫЙ ВАРИАНТ ИГРЫ «КЛИКЕР»
151
Глава 2.4
ЧАСТЬ 2
Проверь, не упустил ли ты что-то. Код, который ты писал в ходе
урока, должен быть похож на код выше. На этом урок подошёл к концу. Ты можешь и дальше улучшать твою игру-кликер, добавляя ещё
больше возможностей!
ГЛАВА 2.5
Движение объектов
ВРЕМЯ НА ЧТЕНИЕ: 15 МИНУТ
ВРЕМЯ НА НАПИСАНИЕ КОДА: 10 МИНУТ
Почти в каждой игре персонаж или объект может двигаться. Управление обычно производится с клавиатуры или мышки. Давайте начнём
с простого — сделаем так, чтобы наш персонаж двигался по экрану
с помощью стрелок на клавиатуре.
Простое движение
На экране есть квадрат, который можно двигать стрелками:
import pygame
pygame.init()
WIDTH, HEIGHT = 600, 400
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Движение объекта")
# Цвета и координаты
WHITE = (255, 255, 255)
RED = (255, 0, 0)
x, y = 300, 200
size = 50
speed = 5
153
Глава 2.5
clock = pygame.time.Clock()
running = True
while running:
screen.fill(WHITE)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
ЧАСТЬ 2
# Проверка клавиш
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
x -= speed
if keys[pygame.K_RIGHT]:
x += speed
if keys[pygame.K_UP]:
y -= speed
if keys[pygame.K_DOWN]:
y += speed
# Рисуем квадрат
pygame.draw.rect(screen, RED, (x, y, size, size))
pygame.display.flip()
clock.tick(60)
pygame.quit()
Пояснение к коду
• pygame.key.get_pressed() — спрашивает, какие клавиши сейчас нажаты.
• pygame.K_LEFT — это стрелка влево. Также есть K_RIGHT, K_UP, K_DOWN.
• Мы изменяем координаты x и y — и объект «едет».
• Всё это находится внутри основного цикла, который обновляется 60 раз в секунду.
154
Движение объектов
Ограничим выход за экран
Если игрок продолжит нажимать стрелки, квадрат может «уползти» за пределы экрана. Чтобы этого не случилось, добавим границы:
# Перед рисованием ограничим координаты
x = max(0, min(WIDTH —
size, x))
y = max(0, min(HEIGHT —
size, y))
Теперь квадрат не выйдет за пределы окна.
Багги, конечно, был бы не в восторге: «Ну почему нельзя дать
квадрату сбежать за экран?! Было бы веселее!»
Управление скоростью
ЧАСТЬ 2
Скорость движения — это просто число. Можно:
speed = 3 # медленнее
speed = 10 # быстрее
А можно даже менять скорость прямо в игре:
if keys[pygame.K_LSHIFT]:
speed = 10 # ускорение
else:
speed = 5
Что ещё можно добавить
1. Движение по диагонали (если нажать сразу две стрелки).
2. Анимацию персонажа — например, смену картинки при движении.
3. Плавное замедление — для того, чтобы объект мог «скользить».
4. Физику — для учёта ускорения, массы, сопротивления.
155
ЧАСТЬ 2
Глава 2.5
ГЛАВА 2.6
Работа с графикой
ВРЕМЯ НА ЧТЕНИЕ: 45 МИНУТ
ВРЕМЯ НА НАПИСАНИЕ КОДА: 30 МИНУТ
Pygame — это не просто библиотека для создания прямоугольников
и кругов. С её помощью можно добавлять в игру настоящие картинки: фон, персонажей, предметы и даже анимацию. Это делает игры
более живыми и интересными. Когда Коди впервые узнал об этом,
он сразу заменил все квадраты в своей игре на героев из любимого
мультфильма. В этой главе — всё самое нужное для того, чтобы ты
мог использовать изображения в своих проектах на Pygame.
Подготовка: картинки в проекте
Перед тем как загрузить изображение, нужно положить его в ту же
папку, что и файл с программой. Например:
папка_проекта/
|---- game.py
---- button.png
В этом примере button.png — это изображение кнопки.
'
157
Глава 2.6
Главное — не перепутай имя файла!
Button.PNG, BUTTON.png
и button.png — это разные файлы.
А я назвал свой файл кнопка(новая) (1) finall.png и не могу
понять, почему он не работает…
Нужно
слушать меня!
Загрузка и отображение изображения
ЧАСТЬ 2
Начнём с самого простого — отобразим изображение на экране.
import pygame
import sys
pygame.init()
WIDTH, HEIGHT = 500, 500
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Картинка на экране")
# Загружаем изображение
image = pygame.image.load("button.png")
# Главный цикл
running = True
while running:
screen.fill((255, 255, 255)) # Белый фон
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
158
Работа с графикой
# Отображаем изображение
screen.blit(image, (150, 150)) # Координаты: x=150, y=150
pygame.display.flip()
pygame.quit()
sys.exit()
ЧАСТЬ 2
РИС. 2.6.1 РЕЗУЛЬТАТ ВЫВОДА ИЗОБРАЖЕНИЯ В ОКНО PYGAME
Пояснение
• pygame.image.load("button.png") — загружает картинку.
• screen.blit(image, (150, 150)) — рисует картинку на экране,
начиная с точки (150, 150).
• fill(…) заливает экран белым цветом перед отрисовкой (иначе старое изображение не исчезнет).
Багги однажды забыл вызывать fill() и не понял, почему персонаж
оставляет «шлейф», — теперь он это называет «фантомным режимом».
Масштабирование изображений
Иногда изображение слишком большое или маленькое. Его можно
изменить с помощью pygame.transform.scale().
# Масштабируем изображение до 100x100 пикселей
image = pygame.image.load("button.png")
image = pygame.transform.scale(image, (100, 100))
159
Глава 2.6
Теперь картинка точно поместится туда, куда нужно. Это очень
удобно, если ты используешь чужие картинки из интернета.
Отображение фона
Фон можно тоже сделать изображением, а не просто цветом. Например:
background = pygame.image.load("background.jpg")
background = pygame.transform.scale(background, (WIDTH, HEIGHT))
И в главном цикле:
ЧАСТЬ 2
screen.blit(background, (0, 0)) # Покрывает весь экран
Персонажи и спрайты
Картинки можно использовать не только как фон, но и как персонажей или кнопки. Коди, кстати, часто рисует своих персонажей
сам, а Багги всё время тащит странные PNG с прозрачным фоном
и жалуется, что они «потерялись на общем фоне». Давай сделаем
простую игру, где персонаж двигается по экрану.
Файлы в папке
• game.py
• character.png — изображение персонажа
Пример игры: двигаем персонажа клавишами
import pygame
import sys
pygame.init()
WIDTH, HEIGHT = 600, 400
160
Работа с графикой
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Двигающийся персонаж")
# Загружаем и масштабируем персонажа
player = pygame.image.load("character.png")
player = pygame.transform.scale(player, (80, 80))
x, y = 300, 200 # Начальные координаты
clock = pygame.time.Clock()
running = True
ЧАСТЬ 2
while running:
screen.fill((200, 200, 255)) # Нежно-голубой фон
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Управление с клавиатуры
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
x -= 5
if keys[pygame.K_RIGHT]:
x += 5
if keys[pygame.K_UP]:
y -= 5
if keys[pygame.K_DOWN]:
y += 5
# Рисуем персонажа
screen.blit(player, (x, y))
pygame.display.flip()
clock.tick(60) # Ограничение до 60 кадров в секунду
pygame.quit()
sys.exit()
161
Глава 2.6
ЧАСТЬ 2
РИС. 2.6.2. ПРИ НАЖАТИИ НА СТРЕЛКИ КЛАВИАТУРЫ ПЕРСОНАЖ
БУДЕТ ПЕРЕМЕЩАТЬСЯ ПО ОКНУ НАШЕЙ ИГРЫ
Разберёмся в коде подробнее
Что делает программа?
•
•
•
•
Загружает картинку персонажа.
Рисует его на экране.
С помощью клавиш ←, ↑, →, ↓ позволяет двигать его по экрану.
Всё это происходит внутри игрового цикла, который обновляется 60 раз в секунду.
Обработка событий
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
• Проверяем все события (нажатия, закрытие окна и т. д.).
• Если пользователь нажмёт крестик, то игра завершится.
Управление персонажем
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
162
Работа с графикой
x -= 5
if keys[pygame.K_RIGHT]:
x += 5
if keys[pygame.K_UP]:
y -= 5
if keys[pygame.K_DOWN]:
y += 5
• pygame.key.get_pressed() возвращает список всех клавиш: какие нажаты, какие нет.
• Если нажата клавиша ←, то координата x уменьшается, и персонаж двигается влево.
• То же самое и для клавиш →, ↑ и ↓.
Скорость движения — 5 пикселей за кадр.
Что можно добавить
Проверку, чтобы персонаж не выходил за границы экрана.
Анимацию (движение ног и рук).
Столкновение с другими объектами.
Прыжки, гравитацию, бег и т. д.
ЧАСТЬ 2
•
•
•
•
ГЛАВА 2.7
Игра
«Крестики-нолики»
ВРЕМЯ НА ЧТЕНИЕ: 45 МИНУТ
ВРЕМЯ НА НАПИСАНИЕ КОДА: 45 МИНУТ
«Крестики-нолики» — классическая игра, в которую играют миллионы. Это отличная возможность потренироваться в работе с мышью,
логикой и отрисовкой поля. В этой главе мы шаг за шагом будем
создавать изначально простую, но постепенно усложняющуюся
версию этой весёлой игры.
«Крестики-нолики» —
это не просто весёлая игра.
Это отличная возможность
потренироваться в Pygame!
Ну-ну, весёлая… Пока ты
не дашь игроку поставить
«X» в каждую клетку
и не испортишь всё.
Первый шаг:
простая игровая доска и клики по клеткам
На первом шаге создадим
• Игровое окно.
• Поле 3 × 3.
164
Игра «Крестики-нолики»
• Возможность щёлкать по клеткам.
• Отображение хода (чей сейчас ход).
Начальный код игры будет выглядеть следующим образом:
import pygame
import sys
# Инициализация Pygame
pygame.init()
# Размер окна и клетки
WIDTH, HEIGHT = 300, 300
CELL_SIZE = WIDTH // 3
ЧАСТЬ 2
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Крестики-Нолики")
# Цвета
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
# Шрифт
font = pygame.font.Font(None, 100)
# Игровое поле: 3 строки, в каждой по 3 клетки
board = [["" for _ in range(3)] for _ in range(3)]
# Игрок, который делает ход: X или O
current_player = "X"
# Главный цикл
running = True
while running:
screen.fill(WHITE)
# Отрисовка сетки
for i in range(1, 3):
165
Глава 2.7
pygame.draw.line(screen, BLACK, (0, i * CELL_SIZE), (WIDTH,
i * CELL_SIZE), 3)
pygame.draw.line(screen, BLACK, (i * CELL_SIZE, 0), (i *
CELL_SIZE, HEIGHT), 3)
# Отрисовка крестиков и ноликов
for row in range(3):
for col in range(3):
if board[row][col]!= "":
text = font.render(board[row][col], True, BLACK)
rect = text.get_rect(center=(col * CELL_SIZE + CELL_SIZE // 2,
row * CELL_SIZE + CELL_SIZE // 2))
screen.blit(text, rect)
ЧАСТЬ 2
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
x, y = event.pos
row = y // CELL_SIZE
col = x // CELL_SIZE
if board[row][col] == "":
board[row][col] = current_player
current_player = "O" if current_player == "X" else "X"
pygame.display.flip()
pygame.quit()
sys.exit()
Из чего будет состоять наша игра?
Игровое поле
board = [["" for _ in range(3)] for _ in range(3)]
166
Игра «Крестики-нолики»
РИС. 2.7.1. ИГРОВАЯ ДОСКА С КРЕСТИКАМИ И НОЛИКАМИ
Что такое board[row][col]
board — это таблица 3 × 3 (список списков), в которой хранятся ходы
игроков. Каждая строка — это список из трёх клеток, и каждая клетка
может быть:
• пустой строкой "" — если туда ещё никто не ходил;
• "X" — если туда сходил игрок X;
• "O" — если туда сходил игрок O.
Когда мы пишем board[row][col], мы получаем содержимое определённой клетки:
• row — номер строки (0, 1 или 2),
• col — номер столбца (тоже 0, 1 или 2).
Например:
board[1][2] = "X"
Это значит: «поставить крестик во вторую строку, в третью колонку».
Или так:
if board[0][0] == "": — Проверяем: пуста ли левая верхняя клетка.
167
ЧАСТЬ 2
Создаём двухмерный список (таблицу) 3 × 3. Каждая клетка в начале пустая ("").
Глава 2.7
Отображение сетки
pygame.draw.line(screen, BLACK, (0, i * CELL_SIZE), (WIDTH,
i * CELL_SIZE), 3)
Рисуем горизонтальные и вертикальные линии, разделяющие
поле на 9 клеток.
Ходы игроков
if board[row][col] == "":
board[row][col] = current_player
current_player = "O" if current_player == "X" else "X"
ЧАСТЬ 2
• При клике мышью вычисляем, в какую клетку мы попали.
• Если клетка пустая, то ставим туда символ текущего игрока.
• Меняем игрока.
Видишь, когда игрок кликает
мышкой, программа точно определяет, в какую клетку он попал.
А если кликнуть за пределами поля? Что будет?
Сейчас ничего страшного, но ты
прав — позже можно добавить
проверку координат.
В этом коде уже можно играть вдвоём на одном компьютере!
Но пока не хватает главного — проверки победы.
Второй шаг:
проверка победы
Добавим функцию, которая будет определять победителя:
168
Игра «Крестики-нолики»
def check_winner(board):
# Проверка строк
for row in board:
if row[0] == row[1] == row[2]!= "":
return row[0]
# Проверка столбцов
for col in range(3):
if board[0][col] == board[1][col] == board[2][col]!= "":
return board[0][col]
# Диагонали
if board[0][0] == board[1][1] == board[2][2]!= "":
return board[0][0]
if board[0][2] == board[1][1] == board[2][0]!= "":
return board[0][2]
ЧАСТЬ 2
return None
Эта функция — как арбитр в матче:
строго и честно определяет, кто
выиграл. Если ты видишь три одинаковых символа в строке, столбце или
диагонали у нас есть победитель!
Теперь в главном цикле после каждого хода можно проверить:
winner = check_winner(board)
if winner:
print(f"Победил: {winner}")
running = False
Для начала просто напечатаем победителя в консоли. Позже
покажем это на экране.
169
Глава 2.7
Третий шаг: блокировка ходов после победы
Сейчас можно продолжать кликать даже после победы. Добавим
переменную:
game_over = False
Перед каждым ходом будем проверять:
if not game_over and board[row][col] == "":
board[row][col] = current_player
current_player = "O" if current_player == "X" else "X"
ЧАСТЬ 2
winner = check_winner(board)
if winner:
game_over = True
А что, если я всё равно
попытаюсь кликнуть?
Извини, Багги! После
победы всё блокируется.
Правила есть правила.
Четвёртый шаг: показать победителя на экране
Добавим текст прямо в окно:
if game_over:
text = font.render(f"{winner} победил!", True, (0, 128, 0))
rect = text.get_rect(center=(WIDTH // 2, HEIGHT // 2))
screen.blit(text, rect)
Теперь после победы игра останавливается и на экране появляется сообщение о победе.
170
Игра «Крестики-нолики»
Конечная версия игры «Крестики-нолики»
import pygame
import sys
# Инициализация Pygame
pygame.init()
# Размеры окна и клеток
WIDTH, HEIGHT = 300, 300
CELL_SIZE = WIDTH // 3
# Создание окна
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Крестики-Нолики")
ЧАСТЬ 2
# Цвета
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GREEN = (0, 128, 0)
# Шрифт для символов и сообщений
font = pygame.font.Font(None, 100)
result_font = pygame.font.Font(None, 40)
# Игровое поле: таблица 3x3
board = [["" for _ in range(3)] for _ in range(3)]
# Игрок, который сейчас ходит
current_player = "X"
# Флаг окончания игры
game_over = False
winner = None
# Проверка победителя
def check_winner(board):
171
Глава 2.7
# Проверка строк
for row in board:
if row[0] == row[1] == row[2]!= "":
return row[0]
# Проверка столбцов
for col in range(3):
if board[0][col] == board[1][col] == board[2][col]!= "":
return board[0][col]
# Диагонали
if board[0][0] == board[1][1] == board[2][2]!= "":
return board[0][0]
if board[0][2] == board[1][1] == board[2][0]!= "":
return board[0][2]
return None
ЧАСТЬ 2
# Основной цикл игры
running = True
while running:
screen.fill(WHITE)
# Отрисовка сетки
for i in range(1, 3):
pygame.draw.line(screen, BLACK, (0, i * CELL_SIZE), (WIDTH,
i * CELL_SIZE), 3) # Горизонтали
pygame.draw.line(screen, BLACK, (i * CELL_SIZE, 0), (i *
CELL_SIZE, HEIGHT), 3) # Вертикали
# Отрисовка символов (X и O)
for row in range(3):
for col in range(3):
symbol = board[row][col]
if symbol!= "":
text = font.render(symbol, True, BLACK)
rect = text.get_rect(center=(col * CELL_SIZE + CELL_SIZE
// 2, row * CELL_SIZE + CELL_SIZE // 2))
screen.blit(text, rect)
# Проверка событий
for event in pygame.event.get():
172
Игра «Крестики-нолики»
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
if not game_over:
x, y = event.pos
row = y // CELL_SIZE
col = x // CELL_SIZE
if board[row][col] == "":
board[row][col] = current_player
winner = check_winner(board)
if winner:
game_over = True
else:
current_player = "O" if current_player == "X" else "X"
ЧАСТЬ 2
# Если игра закончилась - показать сообщение
if game_over:
result_text = result_font.render(f"{winner} победил!", True, GREEN)
result_rect = result_text.get_rect(center=(WIDTH // 2, HEIGHT // 2))
screen.blit(result_text, result_rect)
pygame.display.flip()
pygame.quit()
sys.exit()
РИС. 2.7.2
ПОЛНОЦЕННАЯ ИГРА
«КРЕСТИКИ-НОЛИКИ».
КРЕСТИКИ ПОБЕДИЛИ
173
Глава 2.7
Что реализовано в нашей игре
•
•
•
•
•
•
Сетка поля.
Возможность кликать по клеткам.
Два игрока — X и O.
Проверка победы.
Сообщение о победе.
Блокировка новых ходов после победы.
Вот какие улучшения можно ещё легко добавить в игру
ЧАСТЬ 2
•
•
•
•
•
Цветные крестики и нолики.
Кнопка «Сыграть снова».
Простенький бот, который играет за второго игрока.
Адаптация под телефон (большие кнопки).
Искусственный интеллект (алгоритм minimax — для старших).
ГЛАВА 2.8
Анимация в Pygame
ВРЕМЯ НА ЧТЕНИЕ: 30 МИНУТ
ВРЕМЯ НА НАПИСАНИЕ КОДА: 30 МИНУТ
Анимация — это когда объекты на экране двигаются плавно и естественно, без резких скачков и без нажатия на клавиши. Для того
чтобы освоить работу с анимациямми в Pygame, сначала создадим
очень простую мини-игру. По ходу работы будем добавлять в эту
игру разные фишки, чтобы сделать её увлекательной и полноценной.
Анимация — это как мультик! Чтобы всё
выглядело живо и плавно, нужно показывать кадры один за другим, двигая
объекты понемногу. В этом примере
шарик «оживает» благодаря правильно
настроенному циклу обновлений экрана.
Начальный код: мячик катится по экрану
import pygame
import sys
175
Глава 2.8
pygame.init()
WIDTH, HEIGHT = 600, 400
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Анимация")
WHITE = (255, 255, 255)
BLUE = (0, 102, 255)
x = 100
y = HEIGHT // 2
radius = 30
speed = 3
ЧАСТЬ 2
clock = pygame.time.Clock()
running = True
while running:
screen.fill(WHITE)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Движение
x += speed
if x > WIDTH + radius:
x = –radius
# Рисуем мяч
pygame.draw.circle(screen, BLUE, (x, y), radius)
pygame.display.flip()
clock.tick(60)
pygame.quit()
sys.exit()
176
Анимация в Pygame
ЧАСТЬ 2
РИС. 2.8.1. СИНИЙ ШАРИК ПЛАВНО ДВИЖЕТСЯ СЛЕВА НАПРАВО
ПО ОКНУ ПРОГРАММЫ
Что тут происходит
• Шарик (circle) в каждом кадре сдвигается немного вправо.
177
Глава 2.8
• Когда он уходит за правую границу, мы возвращаем его влево.
• Это и есть анимация — объект сам по себе двигается по экрану, кадр за кадром.
Добавим фон и счёт
А теперь давайте сделаем так, чтобы после каждого пройденного
круга (то есть когда шарик возвращается влево), к счёту у нас добавлялось +1.
Сначала создадим переменную:
score = 0
font = pygame.font.Font(None, 36)
Теперь добавим проверку, когда шарик выходит за край:
ЧАСТЬ 2
if x > WIDTH + radius:
x = –radius
score += 1
И отрисуем счёт:
score_text = font.render(f"Счёт: {score}", True, (0, 0, 0))
screen.blit(score_text, (10, 10))
Теперь игра уже выглядит интереснее: шарик не просто катается,
а игрок может следить за прогрессом.
Управление клавишами
Вдруг игрок захочет двигать мячик вверх-вниз? Давайте дадим ему
такую возможность.
Добавим в цикл:
keys = pygame.key.get_pressed()
if keys[pygame.K_UP] and y > radius:
y -= speed
if keys[pygame.K_DOWN] and y < HEIGHT —
radius:
178
Анимация в Pygame
y += speed
Теперь мячом можно управлять — передвигать его вверх и вниз! Он
всё так же катится сам, но мы можем корректировать его траекторию.
Добавим препятствие
А теперь будет ещё интереснее. Добавим прямоугольник-препятствие,
который движется навстречу мячу. Будьте осторожны: Багги бы точно
сказал, что столкновения необязательны… но мы-то знаем, что без
них не будет вызова!
В начале:
ЧАСТЬ 2
import random
obstacle_x = WIDTH
obstacle_y = random.randint(0, HEIGHT —
40)
obstacle_width = 40
obstacle_height = 40
obstacle_speed = 4
В цикле:
obstacle_x -= obstacle_speed
if obstacle_x < -obstacle_width:
obstacle_x = WIDTH
obstacle_y = random.randint(0, HEIGHT —
obstacle_height)
И отрисовка:
pygame.draw.rect(screen, (255, 0, 0), (obstacle_x, obstacle_y,
obstacle_width, obstacle_height))
Столкновение
Теперь надо проверить — врезался ли мяч в препятствие. Для этого
удобно использовать pygame.Rect:
179
Глава 2.8
player_rect = pygame.Rect(x - radius, y —
radius, radius * 2,
radius * 2)
obstacle_rect = pygame.Rect(obstacle_x, obstacle_y, obstacle_
width, obstacle_height)
if player_rect.colliderect(obstacle_rect):
running = False
ЧАСТЬ 2
Если столкновение происходит, то игра завершается. Получилась
уже полноценная аркадная мини-игра с анимацией.
colliderect — это удобный способ проверить, пересекаются ли
два прямоугольника. Функция возвращает True, если прямоугольники каким-то образом накладываются друг на друга, даже частично.
Когда мы создаём pygame.Rect(…), мы фактически говорим: «вот
область, которую занимает объект». После этого мы можем спросить:
if player_rect.colliderect(obstacle_rect):
Это значит: «пересекается ли прямоугольник игрока с прямоугольником препятствия?»
Если да — значит, объекты столкнулись. Даже если область наложения объектов совсем небольшая — это всё равно будет считаться
столкновением.
Такой подход отлично работает для простых игр и аркад, где точная форма не так важна. Главное — чтобы область прямоугольника
более-менее соответствовала объекту.
Вот финальный код, который получился в результате постепенных
улучшений нашей анимационной мини-игры:
import pygame
import sys
import random
pygame.init()
WIDTH, HEIGHT = 600, 400
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Анимация и столкновения")
180
Анимация в Pygame
WHITE = (255, 255, 255)
BLUE = (0, 102, 255)
RED = (255, 0, 0)
BLACK = (0, 0, 0)
x = 100
y = HEIGHT // 2
radius = 30
speed = 3
obstacle_x = WIDTH
obstacle_y = random.randint(0, HEIGHT —
40)
obstacle_width = 40
obstacle_height = 40
obstacle_speed = 4
ЧАСТЬ 2
score = 0
font = pygame.font.Font(None, 36)
clock = pygame.time.Clock()
running = True
while running:
screen.fill(WHITE)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Движение шарика
x += speed
if x > WIDTH + radius:
x = –radius
score += 1
# Управление вверх-вниз
keys = pygame.key.get_pressed()
if keys[pygame.K_UP] and y > radius:
181
Глава 2.8
y -= speed
if keys[pygame.K_DOWN] and y < HEIGHT —
radius:
y += speed
# Движение препятствия
obstacle_x -= obstacle_speed
if obstacle_x < -obstacle_width:
obstacle_x = WIDTH
obstacle_y = random.randint(0, HEIGHT —
obstacle_height)
ЧАСТЬ 2
# Отрисовка объектов
pygame.draw.circle(screen, BLUE, (x, y), radius)
pygame.draw.rect(screen, RED, (obstacle_x, obstacle_y,
obstacle_width, obstacle_height))
# Проверка столкновений
player_rect = pygame.Rect(x - radius, y —
radius, radius *
2, radius * 2)
obstacle_rect = pygame.Rect(obstacle_x, obstacle_y, obstacle_
width, obstacle_height)
if player_rect.colliderect(obstacle_rect):
game_over_text = font.render("Столкновение! Игра окончена",
True, RED)
screen.blit(game_over_text, (WIDTH // 2–150, HEIGHT // 2))
pygame.display.flip()
pygame.time.delay(2000)
running = False
# Отображение счёта
score_text = font.render(f"Счёт: {score}", True, BLACK)
screen.blit(score_text, (10, 10))
pygame.display.flip()
clock.tick(60)
pygame.quit()
sys.exit()
182
Анимация в Pygame
ЧАСТЬ 2
РИС. 2.8.2. СИНИЙ ШАРИК ПЛАВНО ДВИЖЕТСЯ СЛЕВА НАПРАВО,
А КРАСНЫЙ КВАДРАТ — С ПРАВА НАЛЕВО, ПОКА ОНИ НЕ СТОЛКНУТСЯ.
ПОСЛЕ ЧЕГО ИГРА ЗАВЕРШАЕТСЯ, И ОКНО ЗАКРЫВАЕТСЯ
Что реализовано в финальной версии
•
•
•
•
•
Плавное движение мяча (анимация).
Управление вверх и вниз.
Счёт за каждый пройденный круг.
Препятствие, двигающееся навстречу.
Проверка на столкновение и завершение игры.
ГЛАВА 2.9
Звуковое
сопровождение
ВРЕМЯ НА ЧТЕНИЕ: 15 МИНУТ
ВРЕМЯ НА НАПИСАНИЕ КОДА: 15 МИНУТ
Музыка и звуки делают игру живой. Даже простые звуковые эффекты
помогают игроку чувствовать себя «внутри игры»: звук удара, щелчка,
победы или проигрыша делает каждое действие значимым.
В этой главе разберём
1. Как добавлять фоновую музыку.
2. Как воспроизводить звуки по событиям.
3. Как управлять громкостью.
4. Как загружать и воспроизводить разные звуки.
Воспроизведение
фоновой музыки
Для начала — простой пример, где во время игры звучит музыка
на фоне.
import pygame
import sys
pygame.init()
# Инициализация микшера (модуля звука)
pygame.mixer.init()
184
Звуковое сопровождение
# Загружаем фоновую музыку
pygame.mixer.music.load("background.mp3") # Убедитесь, что
файл рядом
pygame.mixer.music.play(–1) # –1 означает бесконечный цикл
# Создание окна
screen = pygame.display.set_mode((400, 300))
pygame.display.set_caption("Фоновая музыка")
running = True
while running:
screen.fill((200, 200, 200)) # Светло-серый фон
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
ЧАСТЬ 2
pygame.display.flip()
pygame.quit()
sys.exit()
Что тут происходит?
• pygame.mixer.init() — включает аудиосистему.
• pygame.mixer.music.load(…) — загружает музыкальный файл.
• play(–1) — воспроизводит музыку бесконечно.
• Музыка играет в фоне, пока работает главный цикл
Когда запускаешь игру, начинает сразу звучать музыка, и она
не останавливается. Это создаёт такую же атмосферу, как в настоящей игре!
Форматы: лучше использовать .mp3 или .ogg. WAV тоже работает,
но занимает больше места.
background.mp3 необходимо создать самостоятельно, скачав
из интернета музыку и переименовав файл, либо записать аудиофайл
посредством микрофона.
185
Глава 2.9
Когда запускаешь игру, начинает
сразу звучать музыка, и она не
останавливается. Это создаёт такую
же атмосферу, как в настоящей игре!
Я поставил музыку из
ужастика. Теперь даже
меню пугает!
ЧАСТЬ 2
Добавляем звук на событие
(например, клик)
Теперь добавим звук действия — как только пользователь нажимает
пробел, звучит короткий «пик».
Дополнение к предыдущему коду:
# Загружаем звуковой эффект
click_sound = pygame.mixer.Sound("click.wav")
И в цикл событий добавим:
python
CopyEdit
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
click_sound.play()
Теперь при нажатии пробела проигрывается звук click.wav, который также необходимо создать самостоятельно, сохранив в файл
с проектом.
186
Звуковое сопровождение
Управление громкостью
Можно изменять громкость
click_sound.set_volume(0.5) # От 0.0 до 1.0
pygame.mixer.music.set_volume(0.2)
Громкость можно задавать и во время воспроизведения.
ЧАСТЬ 2
ГЛАВА 2.10
Создание игры
«Змейка»
ВРЕМЯ НА ЧТЕНИЕ: 45 МИНУТ
ВРЕМЯ НА НАПИСАНИЕ КОДА: 45 МИНУТ
«Змейка» — это классическая игра, в которую играли на старых телефонах. Игрок управляет длинным хвостом, старается съесть как
можно больше еды и не врезаться в стену или в самого себя. Сегодня
мы создадим эту игру шаг за шагом.
Шаг 1. Простенькая змейка
Сначала создадим змейку, которая просто двигается по экрану. Без
еды, без хвоста, только голова.
import pygame
import sys
pygame.init()
# Размеры
WIDTH, HEIGHT = 600, 400
CELL_SIZE = 20
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Змейка")
188
Создание игры «Змейка»
# Цвета
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
# Начальные координаты змейки
x = WIDTH // 2
y = HEIGHT // 2
# Направление
dx = CELL_SIZE
dy = 0
clock = pygame.time.Clock()
running = True
ЧАСТЬ 2
while running:
screen.fill(BLACK)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Управление
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
dx, dy = 0, -CELL_SIZE
elif keys[pygame.K_DOWN]:
dx, dy = 0, CELL_SIZE
elif keys[pygame.K_LEFT]:
dx, dy = –CELL_SIZE, 0
elif keys[pygame.K_RIGHT]:
dx, dy = CELL_SIZE, 0
# Движение змейки
x += dx
y += dy
pygame.draw.rect(screen, GREEN, (x, y, CELL_SIZE, CELL_SIZE))
189
Глава 2.10
pygame.display.flip()
clock.tick(10)
ЧАСТЬ 2
pygame.quit()
sys.exit()
РИС. 2.10.1. ЗЕЛЁНЫЙ КВАДРАТ, ЯВЛЯЮЩИЙСЯ ЗМЕЙКОЙ, ДВИЖЕТСЯ
ПО ЭКРАНУ И УПРАВЛЯЕТСЯ НАЖАТИЕМ НА КЛАВИШИ СО СТРЕЛКАМИ
Пояснение
• Змейка пока состоит из одного квадратика.
• При каждой итерации она сдвигается в выбранном направлении.
• Управляется клавишами со стрелками на клавиатуре.
Управление с клавиатуры:
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
dx, dy = 0, -CELL_SIZE
190
Создание игры «Змейка»
Проверяем, нажата ли клавиша. Например, стрелка вверх означает,
что нужно идти вверх.
Движение и отрисовка
x += dx
y += dy
Координаты головы змейки обновляются
pygame.draw.rect(screen, GREEN, (x, y, CELL_SIZE, CELL_SIZE))
Рисуем один зелёный прямоугольник по новым координатам.
ЧАСТЬ 2
Шаг 2. Добавляем еду
Теперь давайте добавим еду, которую змейка сможет «съедать».
В начало кода добавим:
import random
food_x = random.randint(0, (WIDTH - CELL_SIZE) // CELL_SIZE)
* CELL_SIZE
food_y = random.randint(0, (HEIGHT - CELL_SIZE) // CELL_SIZE)
* CELL_SIZE
Перед pygame.display.flip() рисуем еду:
RED = (255, 0, 0)
pygame.draw.rect(screen, RED, (food_x, food_y, CELL_SIZE, CELL_SIZE))
И проверяем, съела ли змейка еду:
if x == food_x and y == food_y:
food_x = random.randint(0, (WIDTH - CELL_SIZE) // CELL_SIZE)
* CELL_SIZE
food_y = random.randint(0, (HEIGHT - CELL_SIZE) // CELL_SIZE)
* CELL_SIZE
191
Глава 2.10
Пока что хвост не растёт, но еда появляется в новых местах — это
уже похоже на игру!
Теперь наша змейка может
кушать! Она будет рада
каждой вкусной клеточке.
ЧАСТЬ 2
Я бы сделал так, чтобы еда
исчезала, как только к ней
приближаешься!
Шаг 3. Растущий хвост
Теперь змейка будет расти при поедании еды. Мы сохраним её тело
в списке.
В начало добавим:
snake = [(x, y)] # список всех сегментов змейки
length = 1
В цикле после движения:
snake.append((x, y))
# добавляем новую голову
if len(snake) > length: # если змейка длиннее, чем нужно —
убираем хвост
del snake[0]
При поедании еды:
if x == food_x and y == food_y:
length += 1
food_x = random.randint(0, (WIDTH —
CELL_SIZE) // CELL_SIZE)
* CELL_SIZE
192
Создание игры «Змейка»
food_y = random.randint(0, (HEIGHT —
CELL_SIZE) // CELL_SIZE)
* CELL_SIZE
И отрисовка всего тела змейки:
for segment in snake:
pygame.draw.rect(screen, GREEN, (*segment, CELL_SIZE, CELL_SIZE))
Шаг 4. Столкновение с собой
Теперь нужно проверить, не столкнулась ли змейка с самой собой —
если голова попадёт в один из сегментов тела, то игра закончится.
Сразу после snake.append((x, y)):
snake[:-1] — это всё тело змейки, кроме головы. Если голова по-
пала в тело — это значит, что змейка врезалась в себя.
Мы храним змейку в виде списка координат — snake, где каждая
часть тела — это кортеж (x, y). Например, у нас есть вот такая змейка
из четырёх сегментов:
snake = [(5, 5), (5, 6), (5, 7), (5, 8)]
Здесь (5, 8) — это голова змейки, а всё остальное — её тело. Мы
каждый раз добавляем новую голову в конец списка с помощью snake.
append((x, y)). А чтобы змейка двигалась, удаляем хвост (например,
с помощью snake.pop(0)).
Что такое snake[:-1]?
Срез [:-1] означает: взять всё из списка с начала и до предпоследнего
элемента (не включая его).
Если у нас:
snake = [(5, 5), (5, 6), (5, 7), (5, 8)],
193
ЧАСТЬ 2
if (x, y) in snake[:-1]:
running = False
Глава 2.10
то snake[:-1] будет:
[(5, 5), (5, 6), (5, 7)]
Это и есть тело змейки без головы. А snake[–1] — это сама голова (5, 8).
Шаг 5. Столкновение со стенами
Если змейка выйдет за пределы экрана, то игра тоже завершится.
После движения головы:
ЧАСТЬ 2
if x < 0 or x >= WIDTH or y < 0 or y >= HEIGHT:
running = False
Шаг 6. Добавим счёт
В начало:
font = pygame.font.Font(None, 36)
И перед pygame.display.flip():
score_text = font.render(f"Счёт: {length —
1}", True, (255, 255, 255))
screen.blit(score_text, (10, 10))
Финальный код нашей змейки будет выглядеть следующим образом:
import pygame
import sys
import random
pygame.init()
# Параметры окна и клетки
WIDTH, HEIGHT = 600, 400
CELL_SIZE = 20
194
Создание игры «Змейка»
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Змейка")
# Цвета
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
WHITE = (255, 255, 255)
# Шрифт
font = pygame.font.Font(None, 36)
# Начальные координаты головы
x = WIDTH // 2
y = HEIGHT // 2
ЧАСТЬ 2
# Направление движения
dx = CELL_SIZE
dy = 0
# Список сегментов змейки
snake = [(x, y)]
length = 1
# Позиция еды
food_x = random.randint(0, (WIDTH —
CELL_SIZE) // CELL_SIZE)
* CELL_SIZE
food_y = random.randint(0, (HEIGHT —
CELL_SIZE) // CELL_SIZE)
* CELL_SIZE
clock = pygame.time.Clock()
running = True
while running:
screen.fill(BLACK)
# Обработка событий
for event in pygame.event.get():
195
Глава 2.10
if event.type == pygame.QUIT:
running = False
ЧАСТЬ 2
# Управление стрелками
keys = pygame.key.get_pressed()
if keys[pygame.K_UP] and dy == 0:
dx, dy = 0, -CELL_SIZE
elif keys[pygame.K_DOWN] and dy == 0:
dx, dy = 0, CELL_SIZE
elif keys[pygame.K_LEFT] and dx == 0:
dx, dy = –CELL_SIZE, 0
elif keys[pygame.K_RIGHT] and dx == 0:
dx, dy = CELL_SIZE, 0
# Движение головы
x += dx
y += dy
# Проверка столкновения со стенами
if x < 0 or x >= WIDTH or y < 0 or y >= HEIGHT:
running = False
# Добавляем голову в список
snake.append((x, y))
# Проверка столкновения с собой
if (x, y) in snake[:-1]:
running = False
# Если змейка ест еду
if x == food_x and y == food_y:
length += 1
food_x = random.randint(0, (WIDTH —
CELL_SIZE) // CELL_SIZE)
* CELL_SIZE
food_y = random.randint(0, (HEIGHT —
CELL_SIZE) // CELL_
SIZE) * CELL_SIZE
# Ограничиваем длину змейки
196
Создание игры «Змейка»
if len(snake) > length:
del snake[0]
# Рисуем еду
pygame.draw.rect(screen, RED, (food_x, food_y, CELL_SIZE,
CELL_SIZE))
# Рисуем змейку
for segment in snake:
pygame.draw.rect(screen, GREEN, (*segment, CELL_SIZE, CELL_
SIZE))
# Рисуем счёт
score_text = font.render(f"Счёт: {length —
1}", True, WHITE)
screen.blit(score_text, (10, 10))
ЧАСТЬ 2
pygame.display.flip()
clock.tick(10)
pygame.quit()
sys.exit()
РИС. 2.10.2 ПОЛНОСТЬЮ
ФУНКЦИОНАЛЬНАЯ
ИГРА «ЗМЕЙКА».
ПРИ ПОЕДАНИИ
ЕДЫ ЗМЕЙКА БУДЕТ
РАСТИ, А СЧЁТЧИК —
УВЕЛИЧИВАТЬСЯ. ЕСЛИ
ЗМЕЙКА КОСНЁТСЯ
КРАЁВ ИГРОВОГО ПОЛЯ
ИЛИ СВОЕГО ХВОСТА,
ИГРА ЗАКОНЧИТСЯ
197
ЧАСТЬ 2
Глава 2.10
Поздравляю! Ты собрал
настоящую змейку. А теперь
давай придумаем, как сделать
игру ещё интереснее.
Что можно улучшить дальше?
При желании можно добавить
• Главное меню и кнопку «Начать игру».
• Таблицу рекордов.
• Паузы по клавише P.
• Выбор уровня сложности.
• Графику и звук.
Коди предложил бы добавить милую анимацию, чтобы змейка
моргала глазами.
ГЛАВА 2.11
Физика в играх
ВРЕМЯ НА ЧТЕНИЕ: 15 МИНУТ
ВРЕМЯ НА НАПИСАНИЕ КОДА: 15 МИНУТ
Во многих играх объекты ведут себя так же, как и в реальном мире.
Они падают, ускоряются, отскакивают, не могут проходить сквозь
землю. Всё это — простейшая игровая физика.
Давай разберёмся, как это можно реализовать вручную в Pygame
без специальных библиотек.
Что такое гравитация?
В играх гравитация — это постепенное увеличение вертикальной
скорости объекта при движении вниз:
velocity_y += gravity
y += velocity_y
Если делать это в каждом кадре, объект ускоряется при движении
вниз — будто падает.
199
Глава 2.11
Это как если бы ты прыгнул с лестницы: сначала ты летишь вниз медленно, а потом всё быстрее и быстрее.
Именно это мы и делаем — увеличиваем скорость движения вниз.
А я сделал gravity = -1
и теперь кубик взлетает в космос!
Привет, инопланетяне!
Прыжок
ЧАСТЬ 2
Чтобы подпрыгнуть, достаточно задать отрицательную вертикальную
скорость:
if нажатие_клавиши_прыжка:
velocity_y = –10 # резко вверх
Дальше гравитация всё равно вернёт объект вниз.
Прыжок — это просто резкое
движение вверх, но потом
гравитация снова тянет нас вниз.
Я нажимаю пробел 100 раз
в секунду — кубик дёргается,
как желе! Кто сказал, что физика
должна быть серьёзной?
Столкновение с полом
Если просто увеличивать скорость движения объекта вниз — он пролетит сквозь пол. Нужно задать проверку:
200
Физика в играх
if y >= ground_level:
y = ground_level
velocity_y = 0
on_ground = True
Это значит: если ниже нельзя — не двигаем объект.
Пример: прыгающий кубик
import pygame
pygame.init()
WIDTH, HEIGHT = 600, 400
screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
ЧАСТЬ 2
# Кубик
x, y = 100, 300
width, height = 50, 50
velocity_y = 0
gravity = 0.5
jump_power = –10
on_ground = False
running = True
while running:
screen.fill((220, 220, 255))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Прыжок
keys = pygame.key.get_pressed()
if keys[pygame.K_SPACE] and on_ground:
velocity_y = jump_power
201
Глава 2.11
on_ground = False
# Гравитация
velocity_y += gravity
y += velocity_y
ЧАСТЬ 2
Гравитация — это постоянное ускорение, а не просто сила, которая двигает объект вниз. Это значит, что в каждом кадре скорость
объекта по вертикали увеличивается. Сначала он еле движется вниз,
потом быстрее, ещё быстрее — и так далее.
Такой эффект очень легко получить с помощью прибавки к скорости. Это как в реальной жизни: если прыгнуть с высоты, ты сначала полетишь медленно, но с каждой секундой будешь ускоряться.
В играх мы просто добавляем к скорости небольшое число в каждом
кадре и получаем реалистичное падение.
# Столкновение с полом
ground = HEIGHT —
height
if y >= ground:
y = ground
velocity_y = 0
on_ground = True
pygame.draw.rect(screen, (255, 100, 100), (x, y, width, height))
pygame.display.flip()
clock.tick(60)
pygame.quit()
Подведём итоги
• Простая физика в Pygame — это математика с переменными
скорости.
• Чтобы объект падал — увеличиваем скорость его движения вниз.
• Чтобы прыгал — резко уменьшаем вертикальную скорость.
• Чтобы не проваливался — проверяем столкновения с полом.
• Всё это делается внутри главного цикла игры.
ГЛАВА 2.12
Парящая птичка
ВРЕМЯ НА ЧТЕНИЕ: 45 МИНУТ
ВРЕМЯ НА НАПИСАНИЕ КОДА: 30 МИНУТ
Во многих аркадных играх нужно управлять персонажем так, чтобы он прыгал или избегал препятствий. Один из самых известных
примеров — Flappy Bird. Там игрок управляет птичкой, которая летит
между трубами.
Сейчас мы сделаем свою версию этой игры. Она будет простой,
но при этом весёлой, а ещё мы добавим в неё элементы физики.
Первый шаг — летающая птичка
Сначала сделаем так, чтобы птичка взлетала вверх по нажатию
на пробел, а потом падала вниз. Это основа для всей игры.
import pygame
import sys
pygame.init()
WIDTH, HEIGHT = 400, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Парящая птичка")
# Цвета
WHITE = (255, 255, 255)
203
Глава 2.12
BLUE = (50, 150, 255)
# Загрузка птички
bird = pygame.image.load("bird.png")
bird = pygame.transform.scale(bird, (50, 50))
# Начальные координаты
x = 100
y = 300
velocity = 0
gravity = 0.5
jump_strength = –10
ЧАСТЬ 2
clock = pygame.time.Clock()
running = True
while running:
screen.fill(BLUE)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
velocity = jump_strength
# Физика
velocity += gravity
y += velocity
# Отображение птички
screen.blit(bird, (x, y))
pygame.display.flip()
clock.tick(60)
pygame.quit()
sys.exit()
204
Парящая птичка
Что здесь происходит
• Птичка «падает», потому что каждый кадр увеличивается
velocity.
• При нажатии на пробел velocity резко уменьшается, и птичка
взлетает.
• Таким образом получается «прыгающее» движение.
Следующий шаг — трубы.
Начальные параметры для труб и счёта
Сразу после clock = pygame.time.Clock() добавим переменные для
труб и счёта:
pipe_width = 80
pipe_gap = 200
pipe_speed = 3
pipes = [] # Список всех труб
pipe_timer = 0
# Таймер для генерации труб
205
ЧАСТЬ 2
РИС. 2.12.1. ПТИЧКА, ВЗЛЕТАЮЩАЯ В НЕБО ПО НАЖАТИЮ НА ПРОБЕЛ
Глава 2.12
score = 0 # Счёт
font = pygame.font.Font(None, 36)
Генерация труб
Внутри игрового цикла, после clock.tick(60) добавим код, который
каждые 1.5 секунды создаёт новую трубу случайной высоты:
ЧАСТЬ 2
pipe_timer += clock.get_time()
if pipe_timer > 1500:
pipe_height = random.randint(100, 300)
pipes.append({"x": WIDTH, "height": pipe_height})
pipe_timer = 0
Движение и отрисовка труб
Теперь пройдёмся по всем трубам в цикле, чтобы:
• сдвинуть их влево,
• нарисовать верхнюю и нижнюю трубы,
• проверить столкновения,
• посчитать очки.
Этот код вставляется после y += velocity, перед screen.blit():
bird_rect = pygame.Rect(x, y, 50, 50)
for pipe in pipes:
pipe["x"] -= pipe_speed
top_rect = pygame.Rect(pipe["x"], 0, pipe_width,
pipe["height"])
bottom_y = pipe["height"] + pipe_gap
bottom_rect = pygame.Rect(pipe["x"], bottom_y, pipe_width,
HEIGHT —
bottom_y)
206
Парящая птичка
# Отрисовка труб
pygame.draw.rect(screen, (0, 200, 0), top_rect)
pygame.draw.rect(screen, (0, 200, 0), bottom_rect)
# Проверка столкновений
if bird_rect.colliderect(top_rect) or bird_rect.
colliderect(bottom_rect) or y > HEIGHT:
print("Game Over")
running = False
# Подсчёт очков (когда птичка пролетела трубу)
if pipe["x"] + pipe_width == x:
score += 1
bird_rect = pygame.Rect(x, y, 50, 50)
for pipe in pipes: f
Перебираем все трубы на экране.
pipe["x"] -= pipe_speed
Двигаем трубу влево.
Создаём прямоугольники труб:
top_rect —
верхняя труба.
bottom_rect —
нижняя труба, начинается после зазора.
Рисуем трубы:
• зелёные прямоугольники на экране.
Проверка столкновений:
• если птичка врезалась в трубу или вылетела вниз, то завершаем игру.
Подсчёт очков:
• если птичка пролетела трубу, увеличиваем счёт на 1.
207
ЧАСТЬ 2
Создаём прямоугольник вокруг птички для проверки столкновений.
Глава 2.12
Удаление труб за экраном
Добавим после цикла отрисовки труб:
pipes = [pipe for pipe in pipes if pipe["x"] + pipe_width > 0]
Отображение счёта
Сразу перед pygame.display.flip():
text = font.render(f"Очки: {score}", True, WHITE)
screen.blit(text, (10, 10))
ЧАСТЬ 2
Финальный объединённый код
import sys
import random
import pygame
pygame.init()
WIDTH, HEIGHT = 400, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Парящая птичка")
# Цвета
WHITE = (255, 255, 255)
BLUE = (50, 150, 255)
GREEN = (0, 200, 0)
# Загрузка птички
bird = pygame.image.load("bird.png")
bird = pygame.transform.scale(bird, (50, 50))
# Начальные координаты
x = 100
y = 300
208
Парящая птичка
velocity = 0
gravity = 0.5
jump_strength = –10
# Трубы и счёт
pipe_width = 80
pipe_gap = 200
pipe_speed = 3
pipes = []
pipe_timer = 0
score = 0
font = pygame.font.Font(None, 36)
clock = pygame.time.Clock()
running = True
ЧАСТЬ 2
while running:
dt = clock.tick(60)
screen.fill(BLUE)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
velocity = jump_strength
# Физика птички
velocity += gravity
y += velocity
bird_rect = pygame.Rect(x, y, 50, 50)
# Генерация новых труб
pipe_timer += dt
if pipe_timer > 1500:
pipe_height = random.randint(100, 300)
pipes.append({"x": WIDTH, "height": pipe_height})
pipe_timer = 0
209
Глава 2.12
# Обработка труб
for pipe in pipes:
pipe["x"] -= pipe_speed
top_rect = pygame.Rect(pipe["x"], 0, pipe_width, pipe["height"])
bottom_y = pipe["height"] + pipe_gap
bottom_rect = pygame.Rect(pipe["x"], bottom_y, pipe_width,
HEIGHT —
bottom_y)
ЧАСТЬ 2
pygame.draw.rect(screen, GREEN, top_rect)
pygame.draw.rect(screen, GREEN, bottom_rect)
# Проверка столкновений (птичка не должна выходить за экран)
if bird_rect.colliderect(top_rect) or bird_rect.colliderect(bottom_
rect) or y > HEIGHT or y < 0:
print("Game Over")
running = False
Если игра неожиданно закончилась, а птичка вроде бы не касалась
труб, значит, Багги снова прокрался в код! Он обожает устраивать
неприятности в проверках границ. Проверь: есть ли условие y < 0?
Без него птичка может улететь наверх и сломать игру.
# Подсчёт очков
if pipe["x"] + pipe_width < x and not pipe.get("passed", False):
score += 1
В нашей игре есть список труб (прямоугольников), через которые
должна пролететь птичка. Каждая труба представлена в виде словаря
(например, pipe = {"x": 300, "height": 200, "passed": False}), где
поле "passed" показывает, пролетела птичка мимо этой трубы или нет.
Когда птичка пролетает мимо трубы (то есть её координата x становится больше, чем координата x трубы), игра проверяет: "passed"
у этой трубы ещё False? Если да, значит, это первый раз, когда птичка
её прошла. Мы добавляем очко к счёту и ставим pipe["passed"] =
True, чтобы второй раз за ту же трубу очко уже не начислялось.
pipe["passed"] = True # Помечаем трубу как пройденную
210
Парящая птичка
Без этого флага "passed" очки могли бы прибавляться каждую
итерацию, пока птичка остаётся правее трубы. Это привело бы к багу:
например, +100 очков за одну трубу за пару секунд. А с этим флажком игра точно понимает: труба пройдена один раз — и всё, очко уже
дали, повторять не надо.
# Удаление старых труб
pipes = [pipe for pipe in pipes if pipe["x"] + pipe_width > 0]
# Отображение птички и счёта
screen.blit(bird, (x, y))
text = font.render(f"Очки: {score}", True, WHITE)
screen.blit(text, (10, 10))
pygame.display.flip()
Если всё работает правильно и птичка уверенно пролетает между
трубами, знай, это Коди постарался. Он любит, когда код чистый,
а очки начисляются только один раз. Не забудь про pipe["passed"] =
True — это его любимый приём для избежания двойного счёта!
Ура! Теперь птичка умеет прыгать
и уклоняться от труб! Нужно только
следить за тем, чтобы она не врезалась!
А если сделать гравитацию
в 5 раз сильнее? Хе-хе… Птичка
даже прыгнуть не успеет!
Не смеши. Игроки должны побеждать благодаря своим навыкам, а не
твоим пакостям. Уходи к своим багам!
211
ЧАСТЬ 2
pygame.quit()
sys.exit()
ЧАСТЬ 2
Глава 2.12
РИС. 2.12.2. ПТИЧКА ПО НАЖАТИЮ НА КЛАВИШУ ПРОБЕЛА ПЕРЕЛЕТАЕТ
ЧЕРЕЗ ТРУБЫ, А ОЧКИ УВЕЛИЧИВАЮТСЯ. КОГДА ПТИЧКА КАСАЕТСЯ
ТРУБ ИЛИ ПАДАЕТ, ИГРА ЗАКАНЧИВАЕТСЯ
Что потребуется
• Помести изображение птички bird.png в ту же папку, где находится скрипт.
• Если хочешь заменить птичку просто на цветной прямоугольник — замени screen.blit(bird_img, (x, y)) на pygame.draw.
rect(screen, (255, 255, 0), bird_rect).
Если всё работает, ты — молодец! Коди доволен. А вот Багги уже
точит зуб на следующий уровень — может, добавим движущиеся
трубы или монетки?
212
ГЛАВА 2.13
Рисование фигур
ВРЕМЯ НА ЧТЕНИЕ: 30 МИНУТ
ВРЕМЯ НА НАПИСАНИЕ КОДА: 20 МИНУТ
Иногда в играх и приложениях хочется не загружать картинки, а просто нарисовать что-то прямо на экране: круг, прямоугольник, линию
или даже многоугольник. Pygame делает это очень просто!
Основы рисования
Pygame предоставляет функцию pygame.draw, в которой есть несколько полезных методов:
pygame.draw.rect(screen, цвет, (x, y, ширина, высота)) # прямоугольник
pygame.draw.circle(screen, цвет, (центр_x, центр_y), радиус) # круг
pygame.draw.line(screen, цвет, (x1, y1), (x2, y2), толщина) # линия
pygame.draw.polygon(screen, цвет, [список_точек]) # многоугольник
Прежде чем рисовать фигуры, давай разберёмся, как работает
координатная сетка в Pygame. Представь, что экран — это лист бумаги, у которого верхний левый угол считается началом координат.
Именно от этой точки отсчитываются все позиции. Координата (0, 0)
находится в самом верхнем левом углу, и если двигаться вправо,
увеличивается значение по оси X, а если вниз — по оси Y. Это может
показаться немного непривычным, ведь в школьной математике ось Y
идёт вверх, но в графике всё наоборот: при движении вниз значение
увеличивается.
213
Глава 2.13
ЧАСТЬ 2
Например, если ты укажешь точку (100, 100), то Pygame нарисует
фигуру немного правее и ниже начала экрана. А если ты хочешь нарисовать что-то точно по центру, то сначала нужно узнать размеры
экрана, например 800 на 600 пикселей, и тогда центр будет находиться примерно в точке (400, 300).
Когда ты рисуешь прямоугольник, его координаты определяют
верхний левый угол. У круга — центр, а у многоугольника — все углы,
которые ты задаёшь вручную. Если ты случайно укажешь координаты,
которые выходят за пределы экрана, фигура может не отобразиться — так что с координатами стоит обращаться аккуратно.
Чтобы лучше понимать, где находятся на экране объекты, иногда
полезно нарисовать сетку — например, линии через каждые 100 пикселей. Тогда станет видно, где проходят ключевые точки, и тебе будет
легче размещать объекты в нужных местах.
Создадим небольшую программу, которая рисует разные фигуры:
import pygame
pygame.init()
WIDTH, HEIGHT = 600, 400
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Рисуем фигуры")
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 200, 0)
BLUE = (0, 0, 255)
clock = pygame.time.Clock()
running = True
while running:
screen.fill(WHITE)
# Прямоугольник
pygame.draw.rect(screen, RED, (50, 50, 150, 100))
214
Рисование фигур
# Круг
pygame.draw.circle(screen, GREEN, (300, 100), 50)
# Линия
pygame.draw.line(screen, BLUE, (400, 50), (550, 150), 5)
# Многоугольник (треугольник)
pygame.draw.polygon(screen, (0, 100, 255), [(200, 300), (250,
200), (300, 300)])
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pygame.display.flip()
clock.tick(60)
ЧАСТЬ 2
pygame.quit()
РИС. 2.13.1 ПРЕДСТАВЛЕНИЕ РАЗЛИЧНЫХ ФИГУР В PYGAME
215
Глава 2.13
В чём разница между rect, circle и polygon?
В pygame.draw есть несколько способов рисования фигур. Вот в чём
их различия:
pygame.draw.rect(…) — прямоугольник
Рисует прямоугольник по координатам верхнего левого угла.
Нужно указать: (x, y, ширина, высота).
Удобен для создания окон, домов, кнопок, тел и т. д.
pygame.draw.circle(…) — круг
ЧАСТЬ 2
Рисует круг по координатам центра и радиусу.
Удобен для рисования солнца, колёс, голов, мячей и других круглых объектов.
pygame.draw.polygon(…) — многоугольник
Рисует любой многоугольник по списку точек (углов).
Гибкий способ — можно сделать треугольник, ромб, звезду и вообще всё что угодно!
Удобен для рисования крыш домов, ракет, листьев, сложных форм.
А теперь давай при помощи этих фигур нарисуем свой первый
рисунок. Это будет домик на фоне природы.
import pygame
pygame.init()
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Домик и природа")
# Цвета
SKY = (135, 206, 235)
GRASS = (34, 139, 34)
BROWN = (139, 69, 19)
GRAY = (180, 180, 180)
216
Рисование фигур
YELLOW = (255, 255, 0)
GREEN = (0, 200, 0)
WHITE = (255, 255, 255)
RED = (200, 0, 0)
ЧАСТЬ 2
clock = pygame.time.Clock()
running = True
while running:
screen.fill(SKY)
pygame.draw.rect(screen, GRASS, (0, 400, WIDTH, 200)) # Трава
pygame.draw.circle(screen, YELLOW, (700, 100), 50) # Солнце
pygame.draw.rect(screen, RED, (300, 300, 200, 200))
# Домик - основание
pygame.draw.polygon(screen, GRAY, [(280, 300), (400, 200),
(520, 300)]) # Крыша
pygame.draw.rect(screen, BROWN, (375, 400, 50, 100)) # Дверь
pygame.draw.rect(screen, WHITE, (320, 340, 40, 40)) # Окно
pygame.draw.rect(screen, WHITE, (440, 340, 40, 40)) # Окно
pygame.draw.rect(screen, BROWN, (150, 350, 20, 80)) # Дерево 1 - ствол
pygame.draw.circle(screen, GREEN, (160, 330), 40)) # Дерево 1 - крона
pygame.draw.rect(screen, BROWN, (600, 350, 20, 80)) # Дерево 2 - ствол
pygame.draw.circle(screen, GREEN, (610, 330), 40) # Дерево 2 - крона
# Обработка выхода
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pygame.display.flip()
clock.tick(60)
pygame.quit()
217
ЧАСТЬ 2
Глава 2.13
РИС. 2.13.2 ИЗОБРАЖЕНИЕ ДОМА, СОЗДАННОЕ ЧЕРЕЗ
ГЕОМЕТРИЧЕСКИЕ ОБЪЕКТЫ PYGAME
Смотри, как классно! Мы не
использовали ни единой картинки, а получили настоящий пейзаж
с домиком, солнцем и деревьями.
Фу, скукотища. Лучше бы всё
чёрным нарисовали, или
сделали солнце квадратным!
Ха! А ты попробуй сам
сделать красиво. У тебя
точно получится… криво.
218
Рисование фигур
ЗАДАЧИ НА ЗАКРЕПЛЕНИЕ
МАТЕРИАЛА
Задание 1. Нарисуй робота
Используй прямоугольники, круги и линии, чтобы нарисовать забавного робота. У него должны быть:
• тело и голова (прямоугольники),
• глаза (круги),
• руки (линии),
• ноги (прямоугольники или линии).
Задание 2. Нарисуй ракету
Задание 3. Нарисуй машину
Создай простую машинку:
• корпус — прямоугольник,
• окна — маленькие прямоугольники,
• колёса — круги,
• фары — маленькие круги или прямоугольники.
Задание 4. Нарисуй ночной город
Сделай фон тёмно-синим, добавь:
• несколько прямоугольников — здания,
• жёлтые прямоугольники — окна,
• жёлтый круг — луна.
Задание 5. Нарисуй свой герб
Используй разные фигуры и цвета, чтобы придумать и нарисовать
герб своей команды или семьи. Можно использовать:
219
ЧАСТЬ 2
Сделай ракету из треугольника (нос), прямоугольника (тело) и кругов (окна). Можно добавить огонь снизу (многоугольник).
Глава 2.13
• щит — многоугольник,
• украшения — круги, звёзды, линии,
• надпись или инициалы (можно пока не текстом, а фигурами).
Что дальше?
ЧАСТЬ 2
Ты можешь улучшить код и сделать:
• рисование по клику мышкой,
• движущиеся или исчезающие фигуры,
• собственные «инструменты» рисования — как в Paint.
ДЛЯ ЗАМЕТОК
ЧАСТЬ 3
ГЛАВА 3.1
Знакомство с 3D
В этой главе ты отправишься в удивительное путешествие — в мир
программирования настоящих игр, где двухмерные картинки превращаются в объёмные трёхмерные миры. Ты познакомишься с очень
интересной техникой, которая называется псевдо‑3D. С её помощью даже на простом 2D-экране можно создать эффект объёма
и глубины.
Наверняка ты знаешь, что такое настоящая 3D-графика. Это когда
объекты в игре имеют ширину, высоту и глубину — ты можешь поворачивать камеру, ходить вокруг зданий, прыгать и смотреть на вещи
под разными углами. Для создания настоящего 3D нужны сложные
программы и математические формулы.
Но не всегда есть возможность делать настоящее 3D — иногда
нужно уметь создавать трёхмерный мир на плоском экране, используя
2D-графику. Вот тут и приходит на помощь псевдо‑3D. Это способ
нарисовать мир так, чтобы он выглядел объёмным, хотя на самом
деле все объекты плоские.
Самый известный пример — игра Wolfenstein 3D из 90-х. Там герой
бегает по коридорам, которые выглядят как настоящие, но на самом
деле — это просто хитрый рисунок.
Как это работает — секреты raycasting
Представь, что ты стоишь в комнате и смотришь вперёд. Перед тобой
стена. Ты видишь, что стены ближе — выше и ярче, а стены дальше —
ниже и тусклее. Этот эффект называется перспектива.
Чтобы нарисовать такой мир на экране, мы будем использовать
метод под названием raycasting — «бросание лучей». Вот как это
работает.
1. Мы ставим точку — это место, где стоит игрок.
224
Знакомство с 3D
2. Из этой точки «выстреливаем» множеством невидимых лучей — как если бы ты светил фонариком в разные стороны.
3. Каждый луч летит прямо вперёд, пока не столкнётся со стеной.
4. Чем ближе стена, тем длиннее на экране рисуется вертикальная полоска, которая её изображает.
5. Если стена далеко — полоска будет ниже и темнее, и таким
образом создастся ощущение глубины.
Именно так получается иллюзия трёхмерного пространства.
Давай приступим к созданию твоего первого 3D-мира.
import pygame
import math
import sys
Здесь мы подключаем нужные библиотеки:
• pygame — для создания окна и рисования,
• math —
для математических функций (синусы, косинусы
и т. д.),
• sys — для корректного завершения игры.
WIDTH = 800
HEIGHT = 600
HALF_HEIGHT = HEIGHT // 2
Задаём размеры окна — ширина 800 пикселей, высота 600.
HALF_HEIGHT — половина высоты, она понадобится для рисования
пола и потолка.
TILE = 64
MAP =
[1,
[1,
[1,
[1,
[
1,
0,
0,
0,
1,
0,
1,
0,
1,
0,
1,
0,
1,
0,
1,
1,
1,
0,
0,
0,
1,
0,
0,
0,
1], # 1 —
стена
1], # 0 —
пустое пространство
1],
1],
225
ЧАСТЬ 3
Карта будет состоять из квадратов (тайлов), каждый размером
64 пикселя.
Глава 3.1
[1, 0, 1, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 1, 1, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1],
]
Карта — это наш лабиринт. Цифра 1 — стена, через неё нельзя
пройти.
Цифра 0 — пустое пространство, где можно ходить.
player_x = 3
player_y = 3
player_angle
player_speed
*
*
=
=
TILE + TILE // 2
TILE + TILE // 2
0
3
Игрок стоит в клетке с индексом (3, 3), по центру тайла.
Угол взгляда — 0 радиан (смотрит вправо).
Скорость — количество пикселей, необходимое для движения
за один кадр.
ЧАСТЬ 3
FOV = math.pi / 3
NUM_RAYS = 120
MAX_DEPTH = 800
DELTA_ANGLE = FOV / NUM_RAYS
DIST = (NUM_RAYS / (2 * math.tan(FOV / 2)))
PROJ_COEFF = 3 * DIST * TILE
SCALE = WIDTH // NUM_RAYS
Поле зрения — угол обзора игрока.
Мы «бросаем» 120 лучей, чтобы получить изображение. Чем больше
лучей, тем картинка точнее, но медленнее.
Максимальная дальность — расстояние, на которое «смотрит»
каждый луч.
• DELTA_ANGLE — угол между лучами.
• PROJ_COEFF — помогает правильно вычислять высоту стен.
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
226
Знакомство с 3D
Инициализируем библиотеку Pygame.
Создаём окно с заданными размерами.
Создаём объект clock, чтобы игра работала плавно.
def mapping(x, y):
return int(x // TILE), int(y // TILE)
Функция mapping переводит координаты в пикселях в номер
клетки на карте.
def ray_casting(player_pos, player_angle):
cur_angle = player_angle —
FOV / 2
xo, yo = player_pos
for ray in range(NUM_RAYS): # Перебираем каждый луч
sin_a = math.sin(cur_angle)
cos_a = math.cos(cur_angle)
for depth in range(0, MAX_DEPTH, 5):
x = xo + depth * cos_a
y = yo + depth * sin_a
map_x, map_y = mapping(x, y)
# Проверяем, не вышли ли за карту
if 0 <= map_x < len(MAP[0]) and 0 <= map_y < len(MAP):
# Если луч встретил стену
if MAP[map_y][map_x] == 1:
depth *= math.cos(player_angle —
cur_angle)
# Высота стены на экране —
чем ближе, тем выше
proj_height = PROJ_COEFF / (depth + 0.0001)
227
ЧАСТЬ 3
# Цвет стены зависит от расстояния —
дальше темнее
color_intensity = 255 / (1 + depth * depth * 0.0001)
color = (color_intensity, color_intensity, color_intensity)
pygame.draw.rect(screen, color,
(ray * SCALE, HALF_HEIGHT —
proj_height // 2,
SCALE, proj_height))
break
cur_angle += DELTA_ANGLE
Глава 3.1
Здесь происходит главное — мы «бросаем» лучи. Для каждого
луча ищем точку, в которой он упирается в стену. Высота стены
на экране зависит от расстояния. Цвет тоже меняется — чем дальше,
тем стена темнее. Рисуем много узких полосок — вместе они создают
изображение.
def move_player():
Здесь мы объявляем функцию move_player. Она отвечает за то,
чтобы наш игрок мог двигаться и поворачиваться. Всё управление —
внутри этой функции.
global player_x, player_y, player_angle
Эта строка говорит о том, что внутри функции мы собираемся изменять переменные player_x, player_y и player_angle,
которые объявлены вне функции, в основной части программы.
То есть позиция и угол игрока — глобальные, и функция может
их обновлять.
keys = pygame.key.get_pressed()
Здесь мы вызываем функцию pygame.key.get_pressed(), которая
возвращает список всех нажатых клавиш на клавиатуре в текущий
момент. Это позволит нам проверить, какие клавиши сейчас нажаты,
чтобы мы могли двигать игрока соответствующим образом.
ЧАСТЬ 3
sin_a = math.sin(player_angle)
cos_a = math.cos(player_angle)
Здесь мы заранее вычисляем синус и косинус угла взгляда игрока. Эти значения помогут нам правильно определить направление
движения игрока в пространстве.
dx = 0
dy = 0
speed = player_speed
228
Знакомство с 3D
Обнуляем переменные dx и dy — это приращение (изменение)
по координатам X и Y, то есть значения, на которые мы сместим игрока
по горизонтали и вертикали.
speed — скорость передвижения игрока, её должно быть удобно
менять в одном месте.
# Движение вперёд и назад
if keys[pygame.K_w]:
dx += cos_a * speed
dy += sin_a * speed
Здесь мы смотрим, нажата ли клавиша W (вперёд). Если да, то двигаем игрока вперёд в направлении его взгляда.
Для этого к dx прибавляем cos(player_angle) * speed, а к dy —
sin(player_angle) * speed.
Почему так? Потому что угол зрения игрока показывает, куда он
смотрит, а cos и sin помогают нам взять правильную составляющую
движения по осям X и Y.
if keys[pygame.K_s]:
dx -= cos_a * speed
dy -= sin_a * speed
Если нажата клавиша S (назад), то двигаем игрока назад — просто
идём в противоположную сторону угла взгляда.
Поэтому вычитаем cos_a * speed и sin_a * speed из dx и dy.
Боковое движение (странный ход)
if keys[pygame.K_a]:
dx += sin_a * speed
dy -= cos_a * speed
Нажата клавиша A (влево) — мы хотим, чтобы игрок шагнул влево
относительно направления взгляда.
Для этого мы используем sin и cos, но меняем знаки и порядок,
чтобы сдвинуться перпендикулярно углу взгляда — влево.
Вот почему к dx прибавляем sin_a * speed, а к dy вычитаем cos_a *
speed.
229
ЧАСТЬ 3
#
Глава 3.1
if keys[pygame.K_d]:
dx -= sin_a * speed
dy += cos_a * speed
Нажата клавиша D (вправо) — делаем то же самое, но в другую
сторону — сдвигаем игрока вправо.
Поэтому из dx вычитаем sin_a * speed, а к dy прибавляем cos_a * speed.
# Проверяем, не упираемся ли в стену
if not MAP[int((player_y + dy) // TILE)][int((player_x + dx)
// TILE)]:
player_x += dx
player_y += dy
ЧАСТЬ 3
Важная часть!
После того как мы рассчитали расстояние, на которое нужно сместить игрока (dx, dy), необходимо проверить, не врежется ли он в стену.
Для этого мы смотрим в массив MAP.
• Сначала вычисляем новые координаты игрока — (player_x + dx,
player_y + dy).
• Потом переводим их из пикселей в индекс карты, используя
целочисленное деление на TILE.
• Если в этом месте в карте стоит 0 (то есть пустое пространство), значит, игрок может туда пойти.
Если там находится стена (1), мы не двигаем игрока.
Если стены нет, то прибавляем dx и dy к координатам игрока.
# Повороты игрока влево и вправо
if keys[pygame.K_LEFT]:
player_angle -= 0.03
if keys[pygame.K_RIGHT]:
player_angle += 0.03
Теперь проверяем, нажаты ли стрелки «влево» или «вправо». Если
нажата стрелка «влево» — уменьшаем угол взгляда на 0.03 радиана,
чтобы повернуть влево. Если нажата стрелка «вправо» — увеличиваем
угол, чтобы повернуть вправо. Значение 0.03 — скорость поворота,
можно менять для плавности.
230
Знакомство с 3D
Полный код
import pygame
import math
import sys
# Инициализация Pygame
pygame.init()
# Размер окна
WIDTH, HEIGHT = 640, 480
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Псевдо‑3D —
движение игрока")
# Размер одной клетки карты
TILE = 50
# Простая карта: 1 —
стена, 0 —
пустое пространство
MAP = [
[1,1,1,1,1,1,1,1,1,1],
[1,0,0,0,0,0,0,0,0,1],
[1,0,1,0,1,1,0,1,0,1],
[1,0,1,0,0,0,0,1,0,1],
[1,0,1,1,1,1,0,1,0,1],
[1,0,0,0,0,0,0,1,0,1],
[1,0,1,1,1,1,0,1,0,1],
[1,0,0,0,0,0,0,0,0,1],
[1,1,1,1,1,1,1,1,1,1],
]
ЧАСТЬ 3
# Начальная позиция игрока (в пикселях)
player_x = 100
player_y = 100
# Начальный угол взгляда игрока (в радианах)
player_angle = 0
231
Глава 3.1
# Скорость движения игрока
player_speed = 3
clock = pygame.time.Clock()
def move_player():
global player_x, player_y, player_angle
keys = pygame.key.get_pressed()
sin_a = math.sin(player_angle)
cos_a = math.cos(player_angle)
dx = 0
dy = 0
speed = player_speed
# Движение вперёд и назад
if keys[pygame.K_w]:
dx += cos_a * speed
dy += sin_a * speed
if keys[pygame.K_s]:
dx -= cos_a * speed
dy -= sin_a * speed
ЧАСТЬ 3
# Боковое движение (влево и вправо)
if keys[pygame.K_a]:
dx += sin_a * speed
dy -= cos_a * speed
if keys[pygame.K_d]:
dx -= sin_a * speed
dy += cos_a * speed
# Проверяем, не упираемся ли в стену
new_x = player_x + dx
new_y = player_y + dy
# Проверяем позицию по карте, учитываем размер клетки
if MAP[int(new_y // TILE)][int(new_x // TILE)] == 0:
232
Знакомство с 3D
player_x = new_x
player_y = new_y
# Повороты игрока влево и вправо
if keys[pygame.K_LEFT]:
player_angle -= 0.04
if keys[pygame.K_RIGHT]:
player_angle += 0.04
def draw_map():
# Рисуем карту сверху вниз, клетки размером TILE
for y, row in enumerate(MAP):
for x, cell in enumerate(row):
color = (200, 200, 200) if cell == 1 else (50, 50, 50)
pygame.draw.rect(screen, color, (x * TILE, y * TILE, TILE, TILE))
def draw_player():
# Рисуем игрока в виде круга и линию направления взгляда
pygame.draw.circle(screen, (255, 255, 0), (int(player_x),
int(player_y)), 10)
# Линия взгляда длиной 30 пикселей
end_x = player_x + math.cos(player_angle) * 30
end_y = player_y + math.sin(player_angle) * 30
pygame.draw.line(screen, (255, 0, 0), (player_x, player_y),
(end_x, end_y), 3)
ЧАСТЬ 3
# Основной цикл программы
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
move_player()
screen.fill((0, 0, 0))
draw_map()
draw_player()
233
Глава 3.1
pygame.display.flip()
clock.tick(60)
ЧАСТЬ 3
Отлично! Мы только что создали своего первого игрока, который
может свободно передвигаться по двухмерной карте и даже чувствовать препятствия — стены, через которые пройти нельзя. Пусть
на экране всё ещё вид сверху, и никакого «настоящего 3D» пока нет,
но ты уже сделал огромный шаг: ты научился управлять движением,
обрабатывать нажатия клавиш, учитывать повороты и проверять
столкновения. Это настоящая база для того, чтобы начать строить
псевдо‑3D-мир.
ГЛАВА 3.2
Вид от первого лица
В этой главе приготовься к самому волшебному превращению: ты
научишься создавать настоящий «вид от первого лица». Тебе покажется, будто ты находишься в игровом мире. Это будет почти как
в Minecraft, Doom или Wolfenstein — только ты сделаешь всё своими
руками!
До сих пор мы смотрели сверху…
В прошлой главе мы создали карту, поставили на неё игрока и научили его двигаться. Всё это выглядело так, будто ты паришь где-то
над игрой и видишь карту сверху, словно она нарисована на бумаге.
Это полезно, но очень отличается от того, что ощущаешь в настоящих играх.
Когда ты играешь в шутер или приключение от первого лица, ты
не смотришь на карту сверху. Ты идёшь вперёд, видишь стены, которые
становятся выше, когда ты к ним приближаешься, и поворачиваешь
голову, чтобы заглянуть за угол. Это и есть псевдо‑3D, и оно работает
благодаря особой технике — raycasting.
Что такое raycasting?
Давай представим, что у тебя есть фонарик, и ты включаешь его
в темноте. Свет от фонарика — это луч. Он «идёт» вперёд и рано или
поздно сталкивается с чем-то — например, со стеной.
Raycasting (от английских слов ray — луч, casting — бросать) — это
как будто ты бросаешь много лучей перед собой, чтобы узнать, где
находятся стены и насколько они далеко. Чем ближе стена — тем
более высокой ты её видишь. Чем дальше находится стена, тем она
ниже.
235
Глава 3.2
Именно так раньше делали игры, когда компьютеры были слабенькие. Это простой способ показать 3D-будто-графику, даже если
на самом деле всё остаётся в 2D.
Как это работает?
Твой персонаж (тот самый жёлтый кружок с красной стрелочкой)
смотрит вперёд под каким-то углом. Мы хотим, чтобы он «видел»
перед собой мир. Для этого мы делаем следующее.
1. Пускаем один луч под тем же углом, под которым смотрит
персонаж.
2. Проверяем, когда этот луч столкнётся со стеной на карте.
3. Замеряем расстояние до стены.
4. Рисуем на экране вертикальную полоску — чем ближе стена,
тем выше полоска.
Но если мы пустим всего один луч, получится только одна полоска по центру. Поэтому мы пускаем сотни лучей под разными углами, чтобы охватить «угол зрения» игрока — например, 60°. Эти лучи
дают нам широкую «картинку» мира, как будто мы смотрим на него
своими глазами.
ЧАСТЬ 3
Что будет в этой главе?
Ты научишься:
• пускать лучи по карте;
• находить место, в котором луч врезается в стену;
• вычислять расстояние до столкновения;
• рисовать стены на экране по этим расстояниям;
• получать красивую псевдо‑3D-сцену, в которой можно двигаться!
В конце главы ты получишь простую 3D-сцену с коридорами,
по которым можно ходить и оглядываться. Она будет выглядеть как
что-то из старых игр 90-х, но ты всё сделаешь сам — и даже поймёшь, как это работает. Если ты готов, включай своё воображение,
запускай Python — и поехали! В следующем разделе мы напишем
основу raycasting-движка и разберём её построчно. Тебе всё будет
понятно, обещаю.
236
Вид от первого лица
Настройка Raycasting:
создаём зрение игрока
Теперь мы напишем первую версию raycasting — пускание лучей
и определение расстояния от игрока до стены. Начнём с основ: рисование стен псевдо‑3D-способом.
import pygame
import math
WIDTH, HEIGHT = 800, 600 # Размер окна
HALF_HEIGHT = HEIGHT // 2
FPS = 60
TILE = 100 # Размер одного квадратика на карте
FOV = math.pi / 3 # Угол зрения игрока (60°)
NUM_RAYS = 120 # Количество лучей
MAX_DEPTH = 800 # Насколько далеко мы "смотрим"
DELTA_ANGLE = FOV / NUM_RAYS # Шаг между лучами
DIST = NUM_RAYS / (2 * math.tan(FOV / 2)) # Для коррекции
искажения перспективы
PROJ_COEFF = 3 * DIST * TILE
MAP = [
[1, 1, 1, 1, 1],
[1, 0, 0, 0, 1],
[1, 0, 1, 0, 1],
[1, 0, 0, 0, 1],
[1, 1, 1, 1, 1],
]
ЧАСТЬ 3
player_x, player_y = 150, 150
player_angle = 0
player_speed = 2
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
font = pygame.font.SysFont('Arial', 30)
237
Глава 3.2
Что мы здесь сделали?
•
•
•
•
WIDTH, HEIGHT — размеры окна.
TILE — ширина и высота одной клетки карты.
FOV (Field of View) — широта угла зрения игрока.
NUM_RAYS — количество «лучей зрения», выпущенных перед
игроком.
• MAP — наша простая карта, где 1 — это стена, а 0 — свободное
место.
• Игрок находится внутри карты, и мы задаём для него угол
зрения (направление, куда он смотрит).
Теперь давай создадим движение игрока и главный цикл игры:
def draw_background():
pygame.draw.rect(screen, (100, 100, 100), (0, 0, WIDTH, HALF_
HEIGHT)) # небо
pygame.draw.rect(screen, (50, 50, 50), (0, HALF_HEIGHT, WIDTH,
HALF_HEIGHT)) # земля
def movement():
global player_x, player_y, player_angle
keys = pygame.key.get_pressed()
sin_a = math.sin(player_angle)
cos_a = math.cos(player_angle)
ЧАСТЬ 3
dx, dy = 0, 0
if keys[pygame.K_w]:
dx += cos_a * player_speed
dy += sin_a * player_speed
if keys[pygame.K_s]:
dx -= cos_a * player_speed
dy -= sin_a * player_speed
if keys[pygame.K_a]:
dx += sin_a * player_speed
dy -= cos_a * player_speed
if keys[pygame.K_d]:
238
Вид от первого лица
dx -= sin_a * player_speed
dy += cos_a * player_speed
if MAP[int((player_y + dy) // TILE)][int((player_x + dx)
// TILE)] == 0:
player_x += dx
player_y += dy
if keys[pygame.K_LEFT]:
player_angle -= 0.03
if keys[pygame.K_RIGHT]:
player_angle += 0.03
Теперь raycasting:
def ray_casting():
cur_angle = player_angle —
FOV / 2
for ray in range(NUM_RAYS):
sin_a = math.sin(cur_angle)
cos_a = math.cos(cur_angle)
for depth in range(MAX_DEPTH):
x = player_x + depth * cos_a
y = player_y + depth * sin_a
color = 255 / (1 + depth * depth * 0.0001)
pygame.draw.rect(screen, (color, color, color),
(ray * (WIDTH // NUM_RAYS),
HALF_HEIGHT —
proj_height // 2,
WIDTH // NUM_RAYS, proj_height))
239
ЧАСТЬ 3
i = int(y / TILE)
j = int(x / TILE)
if 0 <= i < len(MAP) and 0 <= j < len(MAP[0]):
if MAP[i][j] == 1:
# коррекция перспективы
depth *= math.cos(player_angle —
cur_angle)
proj_height = min(int(PROJ_COEFF / (depth + 0.0001)), HEIGHT)
Глава 3.2
break
cur_angle += DELTA_ANGLE
Когда мы запускаем ray_casting(), начинается настоящее волшебство. Эта функция отвечает за то, как игрок видит мир. Она берёт
угол зрения игрока и выпускает из его глаз множество лучей — мы
как будто светим фонариком вперёд, немного вправо, немного влево
и так далее.
Сначала мы создаём переменную cur_angle. Это угол первого
луча — крайнего левого. Он начинается с поворота игрока (player_
angle), но чтобы получить край поля зрения, нужно отнять половину
угла зрения (FOV / 2).
Для каждого луча расчитываем синус и косинус текущего угла.
Это нужно для того, чтобы определить направление — куда именно
пойдёт луч по осям X и Y. Косинус и синус превращают угол в движение по горизонтали и вертикали.
sin_a = math.sin(cur_angle)
cos_a = math.cos(cur_angle)
Здесь начинается внутренний цикл: мы увеличиваем глубину (расстояние от игрока до конца луча) шаг за шагом — от 0 до MAX_DEPTH.
Это выглядит так, будто мы двигаемся вдоль луча маленькими шажками, чтобы проверить, во что он упрётся.
ЧАСТЬ 3
for depth in range(MAX_DEPTH):
На каждом шаге мы вычисляем, где сейчас находится наш луч
по X и Y. Мы берём координаты игрока и добавляем шаг в нужном
направлении — с помощью косинуса и синуса.
i = int(y / TILE)
j = int(x / TILE)
Теперь нужно проверить, не вышли ли мы за границы карты, и если
мы всё ещё на карте, давайте посмотрим — это стена (1) или пустое
место (0). Если мы упёрлись в стену, то пора рисовать!
240
Вид от первого лица
if 0 <= i < len(MAP) and 0 <= j < len(MAP[0]):
if MAP[i][j] == 1:
Но перед тем как рисовать, мы должны исправить искажение
перспективы. Без этого стены по бокам будут казаться дальше, чем
в центре, и мы получим эффект, называемый «рыбьим глазом». Умножаем расстояние (depth) на косинус разницы между направлением
игрока и направлением луча.
depth *= math.cos(player_angle —
cur_angle)
Теперь можно расчитать высоту стены. Чем ближе — тем выше.
Мы используем специальный коэффициент (PROJ_COEFF) и делим его
на глубину. Чтобы не делить на ноль, прибавляем к глубине очень
маленькое число (0.0001).
proj_height = min(int(PROJ_COEFF / (depth + 0.0001)), HEIGHT)
Цвет стены мы делаем светлее или темнее в зависимости от расстояния. Чем дальше — тем тусклее. Просто разделим 255 (максимально
яркий цвет) на что-то, зависящее от глубины. Это создаст красивый
эффект затенения.
color = 255 / (1 + depth * depth * 0.0001)
И вот, наконец, мы рисуем вертикальную полоску на экране. Каждому лучу соответствует своя полоска. Мы рисуем прямоугольник
шириной в один луч и высотой proj_height и размещаем его по горизонтали в зависимости от номера луча.
ЧАСТЬ 3
pygame.draw.rect(screen, (color, color, color),
(ray * (WIDTH // NUM_RAYS),
HALF_HEIGHT —
proj_height // 2,
WIDTH // NUM_RAYS, proj_height))
После того как мы нашли стену, прерываем внутренний цикл —
больше идти по лучу не нужно, ведь мы уже «врезались» в стену.
241
Глава 3.2
Главный цикл игры
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill((0, 0, 0))
draw_background()
movement()
ray_casting()
pygame.display.flip()
clock.tick(FPS)
pygame.quit()
ЧАСТЬ 3
Ты создал свою первую систему raycasting — ту самую, которая
использовалась в классических играх вроде Wolfenstein 3D! В следующей главе мы научимся добавлять объекты, и ты сможешь создавать, например, аптечки, врагов или просто бочки, стоящие в углу.
Всё — по тому же принципу.
ГЛАВА 3.3
Улучшаем вид сцены
В прошлой главе ты уже создал свою первую псевдо‑3D-сцену. Стены
мы нарисовали с помощью raycasting, и это уже очень круто. Но ты,
наверное, заметил: что-то не так. Стены словно висят в воздухе. Нет
пола. Нет потолка. Всё выглядит… плоско и странно.
В этой главе мы всё исправим и добавим настоящую «опору» под
ногами — пол и «крышу» — потолок. Ты увидишь, как всего несколько
строчек кода могут сильно улучшить восприятие игры.
На самом деле мы просто закрашиваем нижнюю половину экрана
одним цветом (это будет пол), а верхнюю половину — другим цветом
(потолок). Это называется floor & ceiling casting, и пока мы сделаем
его в самом простом виде — без сложных вычислений.
Это похоже на то, как ты рисуешь небо и землю на листе бумаги:
сверху — голубой, снизу — зелёный.
Добавим пол и потолок
Сначала определим цвета. В самом начале программы, рядом с настройками, добавь следующие переменные:
FLOOR_COLOR = (30, 30, 30) # тёмно-серый пол
CEILING_COLOR = (100, 100, 130) # светло-серое небо с синеватым
оттенком
Теперь, перед тем как запустить ray_casting(), заполним фон
экрана. Это можно сделать вот так:
pygame.draw.rect(screen, CEILING_COLOR, (0, 0, WIDTH, HALF_HEIGHT))
pygame.draw.rect(screen, FLOOR_COLOR, (0, HALF_HEIGHT, WIDTH,
HALF_HEIGHT))
243
Глава 3.3
Приведённые выше две строчки просто рисуют два больших
прямоугольника — верх и низ экрана. Мы делаем это перед тем, как
отрисовать стены, чтобы они располагались поверх.
Полный пример с полом и потолком
Вот как теперь будет выглядеть основной цикл отрисовки (внутри
while True):
pygame.draw.rect(screen, CEILING_COLOR, (0, 0, WIDTH, HALF_
HEIGHT))
pygame.draw.rect(screen, FLOOR_COLOR, (0, HALF_HEIGHT, WIDTH,
HALF_HEIGHT))
ray_casting()
Это всего несколько строк, а игра уже начинает выглядеть как
настоящее 3D. Вместо «белого фона» появляется ощущение, что ты
стоишь на земле, а над тобой небо.
Подведём итог
ЧАСТЬ 3
• Мы научились рисовать пол и потолок.
• Это сильно улучшило внешний вид сцены.
• Мы добавили всего две простые строчки, а эффект получился невероятным.
Теперь твой псевдо‑3D-мир выглядит так, будто ты действительно
идёшь по полу, а не паришь в пустоте.
ГЛАВА 3.4
Мини-карта
Ты уже сделал невероятно крутой шаг — научился с помощью raycasting
рисовать стены, пол и потолок в нашей псевдо‑3D-игре. Мир игры
начал оживать, и тебе кажется, что ты уже действительно бродишь
по настоящему лабиринту. Но есть одна очень важная штука, без
которой сложно работать и тестировать твой мир — это мини-карта.
Мини-карта — это как твой личный дрон, который летит над головой
твоего персонажа и показывает карту сверху. С её помощью ты видишь,
где именно находишься, куда идёшь и что происходит вокруг тебя.
Почему мини-карта так важна?
Представь, что ты бегаешь по лабиринту, а перед тобой стены, коридоры,
повороты — всё как в настоящей игре. Но если ты видишь только то, что
находится перед глазами (то есть стены в режиме псевдо‑3D), иногда
очень трудно понять, где именно ты оказался, в какую сторону надо идти,
не заблудился ли ты в какой-то части карты. Мини-карта помогает тебе
не потеряться. Она показывает, как твой персонаж движется по карте,
и позволяет увидеть всю структуру лабиринта одним взглядом.
Для разработчика, который создаёт игру, мини-карта — это незаменимый инструмент. Она помогает отладить логику, проверить, что
стены стоят правильно, что персонаж не выходит за пределы карты,
а также увидеть направление взгляда игрока — всё это очень важно
при работе с raycasting.
Как сделать мини-карту?
Мини-карта — это просто небольшое изображение сверху, в котором
каждая клетка карты представлена в виде маленького квадратика.
Стены будут светлыми квадратами, а пустое пространство — тёмными.
245
Глава 3.4
Твой персонаж — точка или кружок, а направление взгляда — стрелочка или линия.
Чтобы сделать мини-карту, нам нужно решить:
• где она будет находиться на экране;
• какой размер будет у карты и каждой её клетки;
• как мы нарисуем стены, пустое пространство и персонажа.
Сначала размер и масштаб
В нашей карте игрового мира каждая клетка — это квадрат размером
TILE (например, 50 пикселей). На мини-карте мы хотим отобразить
всё, но в гораздо меньшем масштабе — чтобы она помещалась в угол
экрана и не мешала.
Поэтому мы зададим масштаб — величину, которая показывает,
во сколько раз мини-карта будет меньше основной карты. Например,
если мы выберем масштаб 5, значит, размер каждой клетки на мини-карте будет в 5 раз меньше, чем в реальном мире.
Вот так мы задаём масштаб и размеры:
MINIMAP_SCALE = 5 # Мини-карта в 5 раз меньше настоящей карты
MAP_WIDTH = len(MAP[0])
MAP_HEIGHT = len(MAP)
MINIMAP_TILE = TILE // MINIMAP_SCALE # Размер клетки мини-карты
ЧАСТЬ 3
Рисуем стены и пустые клетки
Теперь, когда у нас есть размеры, мы можем пройтись по всей нашей
карте — двухмерному списку MAP. В каждой ячейке либо 0 (пусто),
либо 1 (стена). Мы будем рисовать маленькие квадратики разных
цветов в зависимости от того, что находится в клетке.
Вот функция, которая это делает:
def draw_minimap():
for y in range(MAP_HEIGHT): # Проходим по каждой строке карты
for x in range(MAP_WIDTH): # Проходим по каждому столбцу в строке
if MAP[y][x] == 1: # Если в клетке стена
color = (200, 200, 200) # Светло-серый цвет для стен
else:
246
Мини-карта
color = (50, 50, 50) # Тёмно-серый для пустых клеток
rect = pygame.Rect(
x * MINIMAP_TILE, # Позиция по X с учётом масштаба
y * MINIMAP_TILE, # Позиция по Y с учётом масштаба
MINIMAP_TILE, # Ширина клетки на мини-карте
MINIMAP_TILE # Высота клетки на мини-карте
)
pygame.draw.rect(screen, color, rect) # Рисуем клетку
Каждый квадратик — это маленький кусочек твоей карты. Благодаря такой функции ты сможешь увидеть общий вид лабиринта сверху.
Всё очень просто — мы закрашиваем квадрат светлым или тёмным
цветом, в зависимости от того, что там находится — стена или пустота.
Добавляем игрока на мини-карту
Представь, что ты смотришь на карту сверху и видишь, где находишься. Для этого мы нарисуем игрока как маленький красный кружочек.
Его координаты — это реальные координаты в мире, но уменьшенные
в 5 раз (то есть в масштабе мини-карты).
Добавим в функцию draw_minimap() такой код:
Здесь мы рисуем на экране красный кружок, который показывает
точное местонахождение игрока на мини-карте. Чтобы понять, где
рисовать этот кружок, нам нужно взять текущие координаты игрока
в игровом мире — это переменные player_x и player_y. Но поскольку
мини-карта уменьшена по сравнению с настоящим миром (в нашем
247
ЧАСТЬ 3
# Рисуем игрока
pygame.draw.circle(
screen,
(255, 0, 0), # Красный цвет
(int(player_x / MINIMAP_SCALE), # Координата X игрока на миникарте
int(player_y / MINIMAP_SCALE)), # Координата Y игрока на миникарте
3 # Радиус кружочка
)
Глава 3.4
случае в 5 раз), мы делим эти координаты на масштаб MINIMAP_
SCALE. Так мы получаем правильное место для кружка на мини-карте.
Цвет кружка выбран красным — это (255, 0, 0) в формате RGB,
где 255 — это максимальное значение красного цвета, а зелёного
и синего цветов здесь нет.
Наконец, мы задаём размер кружка — его радиус равен 3 пикселям,
он должен быть достаточно маленьким, но заметным на мини-карте.
Показываем направление взгляда игрока
ЧАСТЬ 3
Важно не только знать, где ты находишься, но и куда смотришь.
Направление взгляда — это та самая линия или стрелка, которая
показывает, куда смотрит твой персонаж.
Для этого мы возьмём угол взгляда player_angle, найдём направление в виде вектора и нарисуем линию от позиции игрока в этом
направлении.
Добавь в draw_minimap() следующий код:
dx = math.cos(player_angle) * 20 # Смещение по X, длиной
20 пикселей на миникарте
dy = math.sin(player_angle) * 20 # Смещение по Y
pygame.draw.line(
screen,
(0, 255, 0), # Зелёный цвет линии
(int(player_x / MINIMAP_SCALE), int(player_y / MINIMAP_
SCALE)), # Начало —
позиция игрока
(int((player_x + dx) / MINIMAP_SCALE), int((player_y + dy)
/ MINIMAP_SCALE)), # Конец —
направление взгляда
2 # Толщина линии
)
Теперь на мини-карте будет зелёная стрелка, которая указывает
направление твоего взгляда. Это очень полезно и круто!
Как всё это собрать вместе?
В основном игровом цикле после отрисовки стен и пола нужно просто вызвать draw_minimap() — и мини-карта появится у тебя на экране.
248
Мини-карта
Вот пример:
# Отрисовка потолка и пола
pygame.draw.rect(screen, CEILING_COLOR, (0, 0, WIDTH, HALF_
HEIGHT))
pygame.draw.rect(screen, FLOOR_COLOR, (0, HALF_HEIGHT, WIDTH,
HALF_HEIGHT))
# Отрисовка стен
ray_casting()
# Отрисовка мини-карты
draw_minimap()
Немного о масштабах и расположении
Пока мини-карта находится в левом верхнем углу. Ты можешь поменять расположение и сдвинуть её в любой угол экрана — для этого
нужно изменить координаты отрисовки pygame.Rect и рисования
круга и линии. Это отличная практика — попробуй сделать мини-карту
справа или внизу!
Зачем вообще усложнять мини-карту?
Подведём итоги
Мини-карта помогает видеть весь уровень сверху. Мы научились
рисовать на ней не только стены и пустоты, но и самого игрока с направлением его взгляда. Это отличный инструмент для отладки и улучшения игры, ведь с её помощью намного проще ориентироваться
249
ЧАСТЬ 3
В будущем мы научимся рисовать не только стены, но и врагов, предметы и другие объекты на мини-карте. Ты сможешь видеть, где находятся твои цели и опасности. Кроме того, когда ты будешь создавать
большие уровни и лабиринты, мини-карта поможет не заблудиться.
Мини-карта — это маленькое окно в большой мир, и именно с неё
начинается настоящий контроль над игрой.
Глава 3.4
в пространстве и понимать, что происходит вокруг. Мини-карту легко
расширять и делать ещё круче, добавляя новые элементы и улучшая
визуальное восприятие мира.
Что дальше?
ЧАСТЬ 3
В следующей главе мы добавим спрайты — настоящих персонажей,
монеты, врагов, которые будут двигаться в нашем мире и реагировать
на действия игрока. Ты узнаешь, как правильно их рисовать, чтобы
они выглядели «живыми», а не казались просто плоскими пятнами.
А пока попробуй нарисовать мини-карту, поэкспериментировать
с цветами, размерами и расположением. Попробуй сделать так, чтобы мини-карта выглядела уникальной, а потом расскажи, что у тебя
получилось!
ГЛАВА 3.5
Движение игрока
и столкновение
со стенами — как стать
настоящим героем
Привет! Теперь, когда ты умеешь рисовать стены и даже нашего героя
на мини-карте, самое время научиться… ходить! Да-да, без движения
наша игра была бы похожа на картинку — красивую, но скучную.
Мы же хотим сделать настоящее приключение, где ты сможешь бегать по коридорам, исследовать игровое пространство, разгадывать
тайны и прятаться от врагов.
Почему движение — это важно?
Движение — это то, что оживляет игру. Без него мы просто смотрим
на стены и игрока, который стоит на месте. Представь, что ты заходишь в комнату, а твой персонаж не двигается — это странно, правда? А когда ты можешь управлять им, всё сразу становится намного
интереснее!
Движение — это не просто смена координат. Персонаж должен
идти туда, куда он смотрит. Повернул голову направо — значит, шаг
вперёд отправит его вправо. Чтобы это реализовать, придётся применить немного математики.
def move_player():
global player_x, player_y, player_angle
keys = pygame.key.get_pressed()
Сначала мы создаём функцию move_player, которая будет отвечать
за движение нашего героя. Слово global значит, что мы хотим использовать переменные player_x, player_y и player_angle, объявленные
где-то вне функции, чтобы менять их внутри.
Далее мы вызываем команду pygame.key.get_pressed(). Это специальная функция — она возвращает список всех клавиш, которые сейчас
251
Глава 3.5
нажаты на клавиатуре. Мы сохраним этот список в переменную keys,
чтобы потом проверить, какие кнопки нажал игрок.
sin_a = math.sin(player_angle)
cos_a = math.cos(player_angle)
Здесь мы используем математические функции синус (sin) и косинус (cos), которые помогают нам понять направление взгляда игрока. Переменная player_angle — это угол зрения игрока, измеренный
в радианах (единицах измерения углов в математике).
• sin_a — определяет движение по вертикали (ось Y).
• cos_a — определяет движение по горизонтали (ось X).
Почему именно синус и косинус? Представь, что ты стоишь и смотришь в определённом направлении. Чтобы шагнуть вперёд, тебе
нужно пройти некоторое расстояние по оси X и по оси Y — и именно
эти функции помогают вычислить движение в нужную сторону.
dx = 0
dy = 0
speed = player_speed
ЧАСТЬ 3
Здесь мы создаём две переменные dx и dy — это будет наше смещение по осям X и Y, то есть расстояние, на которое игрок передвинется вправо/влево и вверх/вниз за один шаг.
Мы начинаем с нуля, потому что пока не знаем, куда именно игрок
хочет пойти.
speed — это скорость игрока, то есть количество пикселей, на которое он перемещается за один вызов функции. Эта переменная задана
в программе и отвечает за то, насколько быстро движется персонаж.
if keys[pygame.K_w]:
dx += cos_a * speed
dy += sin_a * speed
Здесь мы проверяем, нажата ли клавиша W — она обычно отвечает
за движение вперёд.
При нажатии на клавишу W мы увеличиваем смещение dx и dy
в сторону взгляда игрока:
252
Движение игрока и столкновение со стенами — как стать настоящим героем
• cos_a * speed — расстояние, которое нужно пройти по горизонтали;
• sin_a * speed — расстояние, которое нужно пройти по вертикали.
То есть мы как бы говорим: двигайся именно туда, куда смотришь.
if keys[pygame.K_s]:
dx -= cos_a * speed
dy -= sin_a * speed
Нажата клавиша S — игрок хочет идти назад. Тогда мы делаем наоборот — уменьшаем dx и dy, двигаясь в сторону, противоположную
взгляду.
if keys[pygame.K_a]:
dx += sin_a * speed
dy -= cos_a * speed
Клавиша A отвечает за движение влево, перпендикулярное направлению взгляда игрока.
Почему тут используются синус и косинус, но в другой последовательности и с разными знаками? Потому что движение вбок — это
поворот направления взгляда на 90 градусов. Синус и косинус помогают нам вычислить это смещение.
Так что при нажатии A мы добавляем смещение по оси X и Y, которое соответствует движению влево.
Клавиша D отвечает за движение вправо. Здесь меняются знаки,
потому что нам нужно двигаться в противоположную сторону.
if not MAP[int((player_y + dy) // TILE)][int(player_x // TILE)]:
player_y += dy
Теперь важная часть — проверка столкновений со стенами!
253
ЧАСТЬ 3
if keys[pygame.K_d]:
dx -= sin_a * speed
dy += cos_a * speed
Глава 3.5
Мы хотим узнать: можно ли двигаться на новое место по вертикали
(ось Y)? Для этого нужно посмотреть, что находится на карте (MAP)
по координате, куда мы хотим прийти.
player_y + dy — новая позиция игрока по Y.
player_x — позиция по X остаётся прежней, мы делаем проверку
только по вертикали.
Делим координаты на размер тайла (TILE), чтобы узнать, в какой
именно квадрат карты мы попадём. Приводим к целому числу — это
индекс в массиве.
Если в этом месте нет стены (то есть значение равно 0), значит,
можно двигаться — и мы добавляем смещение к player_y.
if not MAP[int(player_y // TILE)][int((player_x + dx) // TILE)]:
player_x += dx
Похожим образом проверяем движение по горизонтали (ось X).
Если там пусто — обновляем координату игрока.
ЧАСТЬ 3
if keys[pygame.K_LEFT]:
player_angle -= 0.04
if keys[pygame.K_RIGHT]:
player_angle += 0.04
В конце мы обрабатываем повороты игрока — налево и направо.
При нажатии стрелки влево уменьшаем угол взгляда на небольшое
значение (0.04 радиана). При нажатии стрелки вправо — увеличиваем
угол.
Так игрок поворачивается плавно, меняя направление взгляда.
При каждом вызове эта функция проверяет, какие клавиши нажаты,
и обновляет позицию и угол игрока с учётом столкновений со стенами. Благодаря этому ты сможешь бегать по карте, не сталкиваясь
со стенами, и поворачиваться, чтобы осматривать мир вокруг.
Полный код
import pygame
import math
import sys
254
Движение игрока и столкновение со стенами — как стать настоящим героем
# Инициализация Pygame
pygame.init()
# Настройки окна
WIDTH, HEIGHT = 800, 600
HALF_HEIGHT = HEIGHT // 2
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Псевдо‑3D-игра на Python")
# Карта (1 —
стена, 0 —
пустое пространство)
MAP = [
[1,1,1,1,1,1,1,1],
[1,0,0,0,0,0,0,1],
[1,0,1,0,1,0,0,1],
[1,0,1,0,1,0,0,1],
[1,0,0,0,0,1,0,1],
[1,0,1,1,0,0,0,1],
[1,0,0,0,0,0,0,1],
[1,1,1,1,1,1,1,1]
]
TILE = 100 # размер клетки карты (в пикселях)
player_x, player_y = TILE + TILE//2, TILE + TILE//2 # начальная
позиция игрока (в пикселях)
player_angle = 0 # угол взгляда игрока (в радианах)
player_speed = 3 # скорость перемещения игрока
ЧАСТЬ 3
FOV = math.pi / 3 # угол обзора —
60 градусов
NUM_RAYS = 120 # количество лучей для raycasting
MAX_DEPTH = 800 # максимальная дальность прорисовки луча
DELTA_ANGLE = FOV / NUM_RAYS # угол между соседними лучами
PROJ_COEFF = 3 * 300 # коэффициент для высоты проекции стены
SCALE = WIDTH // NUM_RAYS # ширина одного луча (полоски)
clock = pygame.time.Clock()
def move_player():
255
Глава 3.5
global player_x, player_y, player_angle
keys = pygame.key.get_pressed()
sin_a = math.sin(player_angle)
cos_a = math.cos(player_angle)
dx, dy = 0, 0
speed = player_speed
# Движение вперёд и назад
if keys[pygame.K_w]:
dx += cos_a * speed
dy += sin_a * speed
if keys[pygame.K_s]:
dx -= cos_a * speed
dy -= sin_a * speed
# Боковое движение влево и вправо
if keys[pygame.K_a]:
dx += sin_a * speed
dy -= cos_a * speed
if keys[pygame.K_d]:
dx -= sin_a * speed
dy += cos_a * speed
ЧАСТЬ 3
# Проверка столкновений по вертикали
if MAP[int((player_y + dy) // TILE)][int(player_x // TILE)] == 0:
player_y += dy
# Проверка столкновений по горизонтали
if MAP[int(player_y // TILE)][int((player_x + dx) // TILE)] == 0:
player_x += dx
# Поворот игрока
if keys[pygame.K_LEFT]:
player_angle -= 0.04
if keys[pygame.K_RIGHT]:
player_angle += 0.04
256
Движение игрока и столкновение со стенами — как стать настоящим героем
def ray_casting():
cur_angle = player_angle —
FOV / 2
for ray in range(NUM_RAYS):
sin_a = math.sin(cur_angle)
cos_a = math.cos(cur_angle)
for depth in range(MAX_DEPTH):
x = player_x + depth * cos_a
y = player_y + depth * sin_a
i = int(y // TILE)
j = int(x // TILE)
if 0 <= i < len(MAP) and 0 <= j < len(MAP[0]):
if MAP[i][j] == 1:
# исправление искажения перспективы (эффект "рыбьего глаза")
depth *= math.cos(player_angle —
cur_angle)
# вычисляем высоту стены
proj_height = min(int(PROJ_COEFF / (depth + 0.0001)),
HEIGHT)
# цвет стены зависит от расстояния (чем дальше, тем темнее)
color_intensity = 255 / (1 + depth * depth * 0.0001)
color = (color_intensity, color_intensity, color_intensity)
ЧАСТЬ 3
# рисуем вертикальную полоску стены
pygame.draw.rect(screen, color,
(ray * SCALE,
HALF_HEIGHT —
proj_height // 2,
SCALE,
proj_height))
break
cur_angle += DELTA_ANGLE
def draw_minimap():
MINIMAP_SCALE = 8 # масштаб для мини-карты
for y, row in enumerate(MAP):
257
Глава 3.5
for x, tile in enumerate(row):
rect = pygame.Rect(x * TILE // MINIMAP_SCALE,
y * TILE // MINIMAP_SCALE,
TILE // MINIMAP_SCALE,
TILE // MINIMAP_SCALE)
color = (200, 200, 200) if tile else (50, 50, 50)
pygame.draw.rect(screen, color, rect)
# Рисуем игрока на мини-карте
pygame.draw.circle(screen, (255, 0, 0),
(int(player_x / MINIMAP_SCALE),
int(player_y / MINIMAP_SCALE)), 5)
# Рисуем направление взгляда игрока на мини-карте
end_x = int(player_x / MINIMAP_SCALE + math.cos(player_angle) * 20)
end_y = int(player_y / MINIMAP_SCALE + math.sin(player_angle) * 20)
pygame.draw.line(screen, (0, 255, 0),
(int(player_x / MINIMAP_SCALE), int(player_y / MINIMAP_SCALE)),
(end_x, end_y), 2)
# Главный цикл игры
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill((0, 0, 0)) # очистка экрана
ЧАСТЬ 3
move_player() # обработка движения игрока
ray_casting() # отрисовка псевдо‑3D-сцены
draw_minimap() # отрисовка мини-карты
pygame.display.flip() # обновляем экран
clock.tick(60) # 60 кадров в секунду
pygame.quit()
sys.exit()
258
Движение игрока и столкновение со стенами — как стать настоящим героем
Ты познакомился с очень интересным способом создания игры,
когда кажется, что всё вокруг трёхмерное, хотя на самом деле —
просто хитрая картинка! Это называется псевдо‑3D и работает оно
с помощью метода под названием raycasting. Представь, что лучи
света исходят из глаз игрока и «исследуют» комнату, определяя, где
стоят стены. Таким образом игра «видит» пространство и рисует его
трёхмерную модель.
Ты научился:
• отличать псевдо‑3D от настоящего 3D и понял, что это такое;
• создавать простую карту — как план квартиры — где есть стены и пустые места;
• отрисовывать стены на экране так, чтобы казалось, будто ты
смотришь прямо перед собой и видишь эти стены с разной
высотой и тенями;
• создавать движение игрока — вперед, назад, в стороны — и при
этом делать так, чтобы он не сталкивался со стенами;
• видеть мини-карту сверху и ориентироваться в пространстве —
определять своё местонахождение и направление
взгляда.
Ты смог написать код и разобрался в каждом действии — почему
мы расчитываем углы определённым образом, как рисуем стены
и как проверяем, не столкнёмся ли мы с ними. Это похоже на то, как
если бы ты строил собственный маленький мир из кубиков!
В итоге у тебя получилась настоящая игра, где можно бегать
по лабиринту и видеть стены, при этом ощущая себя как в настоящей
3D-комнате.
ЧАСТЬ 3
ГЛАВА 3.6
Физика с помощью
pymunk — создаём
платформер
ВРЕМЯ НА ЧТЕНИЕ: 25 МИНУТ
Привет, юный программист!
В этой главе мы сделаем нечто совершенно новое! Мы отложим
наши предыдущие игры и создадим мини-платформер с реальной
физикой — падающими кубиками, платформами и гравитацией. Для
этого будем использовать библиотеку Pymunk (это как «физический
движок» для Python).
1. Установка Pymunk
Сначала установим библиотеку:
pip install pymunk pygame
2. Основы Pymunk
Pymunk работает с объектами:
• Space — «мир», где всё существует
• Body — физическое тело (может двигаться)
• Shape — форма тела (круг, квадрат и т. д.)
Добавим гравитацию и стены, чтобы объекты не падали вниз
бесконечно.
260
Физика с помощью pymunk — создаём платформер
3. Код: платформер с падающими кубиками
import pygame as pg
import pymunk as pm
import random
# Инициализация Pygame и Pymunk
pg.init()
screen = pg.display.set_mode((800, 600))
clock = pg.time.Clock()
space = pm.Space()
space.gravity = (0, 900) # Гравитация (x, y). 900 —
как на Земле.
# Стены (чтобы объекты не улетали)
def create_walls():
walls = [
pm.Segment(space.static_body, (0, 600), (800, 600), 10), # Пол
pm.Segment(space.static_body, (0, 0), (0, 600), 10), # Левая стена
pm.Segment(space.static_body, (800, 0), (800, 600), 10) # Правая стена
]
for wall in walls:
wall.elasticity = 0.8 # Упругость
space.add(wall)
create_walls()
ЧАСТЬ 3
# Создаём платформу
def create_platform(x, y, width, height):
body = pm.Body(body_type=pm.Body.STATIC) # Неподвижное тело
body.position = (x, y)
shape = pm.Poly.create_box(body, (width, height))
shape.elasticity = 0.5
space.add(body, shape)
return shape
platform = create_platform(400, 500, 200, 20)
261
Глава 3.6
# Создаём случайный кубик
def create_cube(x, y):
body = pm.Body(mass=1, moment=10) # Масса и момент инерции
body.position = (x, y)
shape = pm.Poly.create_box(body, (30, 30))
shape.elasticity = 0.5
shape.friction = 0.7
space.add(body, shape)
return shape
cubes = []
# Основной цикл игры
running = True
while running:
for event in pg.event.get():
if event.type == pg.QUIT:
running = False
elif event.type == pg.MOUSEBUTTONDOWN:
# При клике создаём кубик
cube = create_cube(event.pos[0], event.pos[1])
cubes.append(cube)
# Обновляем физику (60 раз в секунду)
space.step(1/60)
ЧАСТЬ 3
# Отрисовка
screen.fill((240, 240, 240))
# Рисуем платформу
pg.draw.rect(screen, (0, 0, 255),
(platform.body.position.x - 100,
platform.body.position.y - 10,
200, 20))
# Рисуем кубики
for cube in cubes:
262
Физика с помощью pymunk — создаём платформер
vertices = [v.rotated(cube.body.angle) + cube.body.position
for v in cube.get_vertices()]
pg.draw.polygon(screen, (255, 0, 0), vertices)
pg.display.flip()
clock.tick(60)
pg.quit()
4. Как выглядит наша игра?
ЧАСТЬ 3
263
Глава 3.6
5. Что делает этот код?
•
•
•
•
Гравитация — кубики падают вниз
Стены и платформа — объекты отскакивают от них
Клик мыши — создаёт новый кубик
Реалистичная физика — упругость, трение
6. Улучшаем игру
ЧАСТЬ 3
• Добавь прыжки (персонажа, который может прыгать)
• Сделай врагов (двигающиеся объекты)
• Добавь текстуры (замени фигуры картинками)
ГЛАВА 3.7
Продолжаем игру
с физикой — добавляем
сложные взаимодействия!
ВРЕМЯ НА ЧТЕНИЕ: 30 МИНУТ
Привет, юный программист!
Давай продолжим нашу игру с физическим кубиком из первой
бонусной главы и добавим в неё новые интересные механики.
Что мы улучшим
1.
2.
3.
4.
Добавим управление кубиком с клавиатуры
Создадим разрушаемые платформы
Добавим цели для достижения
Введём систему подсчета очков
1. Добавим границы
Для начала нам нужно ограничить наш экран, поэтому давай добавим
функцию с границами и сразу запустим её:
def create_boundaries():
segments = [
((0, 600), (800, 600)), # Пол
((0, 0), (0, 600)), # Левая стена
((800, 0), (800, 600)) # Правая стена
]
265
Глава 3.7
for start, end in segments:
body = pymunk.Body(body_type=pymunk.Body.STATIC)
shape = pymunk.Segment(body, start, end, 5)
shape.elasticity = 0.8
space.add(body, shape)
create_boundaries() # Запустим функцию
2. Класс разрушаемых платформ
Теперь нам нужно описать платформы, которые будут разрушаться
нашим кубиком. Для этого мы заведём новый класс, где опишем, как
устроены наши платформы:
ЧАСТЬ 3
class BreakablePlatform:
def __init__(self, x, y, width, height):
self.body = pymunk.Body(body_type=pymunk.Body.STATIC)
self.body.position = x, y
self.shape = pymunk.Poly.create_box(self.body, (width, height))
self.shape.elasticity = 0.5
self.shape.collision_type = 2 # Уникальный тип для платформ
space.add(self.body, self.shape)
self.health = 3
self.width = width
self.height = height
def draw(self): # Функция отрисовки платформ
color = (0, 255, 0) if self.health > 1 else (255, 165, 0)
# Меняем цвет платформ при уменьшении "здоровья"
pygame.draw.rect(screen, color,
(self.body.position.x —
self.width/2,
self.body.position.y —
self.height/2,
self.width, self.height))
3. Класс игрока
Введём класс игрока. Нашим игроком будет кубик (такой же, как в предыдущей главе), но если ты вернёшься к ранним главам, то вспомнишь,
266
Продолжаем игру с физикой — добавляем сложные взаимодействия!
как можно заменить кубик любой картинкой. Мы дадим возможность
кубику прыгать и разрушать платформы.
class Player:
def __init__(self, x, y):
self.body = pymunk.Body(mass=1, moment=10)
self.body.position = x, y
self.shape = pymunk.Poly.create_box(self.body, (30, 30))
self.shape.elasticity = 0.2
self.shape.friction = 0.8
self.shape.collision_type = 1 # Уникальный тип для игрока
space.add(self.body, self.shape)
self.jumping = False
def draw(self):
pygame.draw.polygon(screen, (255, 0, 0),
[v.rotated(self.body.angle) + self.body.position
for v in self.shape.get_vertices()])
def jump(self):
if not self.jumping:
self.body.apply_impulse_at_local_point((0, —20000))
self.jumping = True
4. Класс цели
Добавим класс для целей
ЧАСТЬ 3
class Target:
def __init__(self, x, y):
self.body = pymunk.Body(body_type=pymunk.Body.STATIC)
self.body.position = x, y
self.shape = pymunk.Circle(self.body, 20)
self.shape.sensor = True # Делаем цель нефизической
self.shape.collision_type = 3 # Уникальный тип для целей
space.add(self.body, self.shape)
267
Глава 3.7
def draw(self):
pygame.draw.circle(screen, (255, 255, 0),
(int(self.body.position.x), int(self.body.position.y)), 20)
5. Обработчик столкновений
Суть этой мини-игры заключается в том, что кубик должен разрушить
платформы и достичь цели. Разрушая платформы и достигая цели,
кубик сталкивается с ними, поэтому давай напишем класс с обработкой столкновений.
def collision_handler(arbiter, space, data):
global score
player_shape = arbiter.shapes[0]
other_shape = arbiter.shapes[1]
ЧАСТЬ 3
# Столкновение с платформой
if other_shape.collision_type == 2:
player = player_shape.body
if player.velocity.y > 100: # Если падаем с большой скоростью
platform = other_shape.body
platform.health -= 1
if platform.health <= 0:
space.remove(platform, platform.shapes[0])
# Столкновение с целью
elif other_shape.collision_type == 3:
score += 100
space.remove(other_shape.body, other_shape)
return True
Теперь если игрок врезается в платформу на большой скорости,
то она разрушается (не сразу, так как у каждой платформы три жизни),
а если игрок достигает цели — счёт увеличивается на 100.
268
Продолжаем игру с физикой — добавляем сложные взаимодействия!
6. Улучшенный код игры
Теперь включим все функции и классы, написанные до этого, и добавим некоторые обновления.
import
import
import
import
pygame
pymunk
random
sys
# Инициализация
pygame.init()
screen = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()
font = pygame.font.SysFont('Arial', 24)
space = pymunk.Space()
space.gravity = (0, 1000) # Усилим гравитацию
# Счетчик очков
score = 0
# Создание границ
def create_boundaries():
segments = [
((0, 600), (800, 600)), # Пол
((0, 0), (0, 600)), # Левая стена
((800, 0), (800, 600)) # Правая стена
]
ЧАСТЬ 3
for start, end in segments:
body = pymunk.Body(body_type=pymunk.Body.STATIC)
shape = pymunk.Segment(body, start, end, 5)
shape.elasticity = 0.8
space.add(body, shape)
create_boundaries()
269
Глава 3.7
# Класс разрушаемой платформы
class BreakablePlatform:
def __init__(self, x, y, width, height):
self.body = pymunk.Body(body_type=pymunk.Body.STATIC)
self.body.position = x, y
self.shape = pymunk.Poly.create_box(self.body, (width, height))
self.shape.elasticity = 0.5
self.shape.collision_type = 2 # Уникальный тип для платформ
space.add(self.body, self.shape)
self.health = 3
self.width = width
self.height = height
ЧАСТЬ 3
def draw(self):
color = (0, 255, 0) if self.health > 1 else (255, 165, 0)
pygame.draw.rect(screen, color,
(self.body.position.x —
self.width/2,
self.body.position.y —
self.height/2,
self.width, self.height))
# Класс игрока
class Player:
def __init__(self, x, y):
self.body = pymunk.Body(mass=1, moment=10)
self.body.position = x, y
self.shape = pymunk.Poly.create_box(self.body, (30, 30))
self.shape.elasticity = 0.2
self.shape.friction = 0.8
self.shape.collision_type = 1 # Уникальный тип для игрока
space.add(self.body, self.shape)
self.jumping = False
def draw(self):
pygame.draw.polygon(screen, (255, 0, 0),
[v.rotated(self.body.angle) + self.body.position
for v in self.shape.get_vertices()])
def jump(self):
270
Продолжаем игру с физикой — добавляем сложные взаимодействия!
if not self.jumping:
self.body.apply_impulse_at_local_point((0, —20000))
self.jumping = True
# Класс цели
class Target:
def __init__(self, x, y):
self.body = pymunk.Body(body_type=pymunk.Body.STATIC)
self.body.position = x, y
self.shape = pymunk.Circle(self.body, 20)
self.shape.sensor = True # Делаем цель нефизической
self.shape.collision_type = 3 # Уникальный тип для целей
space.add(self.body, self.shape)
def draw(self):
pygame.draw.circle(screen, (255, 255, 0),
(int(self.body.position.x), int(self.body.position.y)), 20)
# Обработчик столкновений
def collision_handler(arbiter, space, data):
global score
player_shape = arbiter.shapes[0]
other_shape = arbiter.shapes[1]
ЧАСТЬ 3
# Столкновение с платформой
if other_shape.collision_type == 2:
player = player_shape.body
if player.velocity.y > 100: # Если падаем с большой скоростью
platform = other_shape.body
platform.health -= 1
if platform.health <= 0:
space.remove(platform, platform.shapes[0])
# Столкновение с целью
elif other_shape.collision_type == 3:
score += 100
space.remove(other_shape.body, other_shape)
271
Глава 3.7
return True
# Создаём обработчик столкновений
handler = space.add_collision_handler(1, 2) # Игрок и платформы
handler.begin = collision_handler
handler = space.add_collision_handler(1, 3) # Игрок и цели
handler.begin = collision_handler
# Создаём игровые объекты
player = Player(400, 300)
platforms = [
BreakablePlatform(200, 500, 150, 20),
BreakablePlatform(400, 400, 150, 20),
BreakablePlatform(600, 300, 150, 20)
]
targets = [
Target(100, 100),
Target(700, 200)
]
ЧАСТЬ 3
# Основной игровой цикл
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.jump()
# Управление игроком
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
player.body.apply_force_at_local_point((–5000, 0), (0, 0))
if keys[pygame.K_RIGHT]:
player.body.apply_force_at_local_point((5000, 0), (0, 0))
272
Продолжаем игру с физикой — добавляем сложные взаимодействия!
# Обновление физики
space.step(1/60)
# Проверка прыжка
if player.body.velocity.y == 0:
player.jumping = False
# Отрисовка
screen.fill((240, 240, 240))
# Рисуем все объекты
for platform in platforms:
if hasattr(platform, 'health'): # Проверяем, не удалена ли
платформа
platform.draw()
for target in targets[:]: # Копируем список для безопасного
удаления
if target.shape.body in space.bodies: # Если цель еще
существует
target.draw()
else:
targets.remove(target)
player.draw()
# Отображаем счет
score_text = font.render(f'Очки: {score}', True, (0, 0, 0))
screen.blit(score_text, (20, 20))
ЧАСТЬ 3
pygame.display.flip()
clock.tick(60)
pygame.quit()
sys.exit()
273
Глава 3.7
7. Как выглядит наша игра?
Мы появляемся в середине экрана и сразу слегка разрушаем среднюю платформу.
ЧАСТЬ 3
В процессе игры мы можем разрушать и другие платформы.
274
Продолжаем игру с физикой — добавляем сложные взаимодействия!
8. Что нового мы добавили
1.
•
•
•
2.
•
•
•
3.
•
•
•
4.
•
•
Управление персонажем
Прыжок при помощи клавиши пробела
Движение влево/вправо при помощи клавиш со стрелками
Ограничение на двойной прыжок
Разрушаемые платформы
Платформы меняют цвет при повреждении
Разрушаются при сильном ударе сверху
Имеют три уровня прочности
Система целей
Желтые круги — цели для сбора
При касании начисляются очки (100 за каждую)
Цели исчезают после сбора
Система подсчёта очков
Отображение текущего счёта
Возможность расширения (бонусы за комбо и т. д.)
9. Что можно добавить, чтобы улучшить игру
1. Уровни с разным расположением платформ.
2. Врагов и препятствия.
3. Бонусные предметы (дополнительные прыжки, временная неуязвимость).
4. Анимации разрушения платформ.
5. Звуковые эффекты при взаимодействиях.
6. Картинку вместо обычного кубика.
Попробуйте реализовать хотя бы одно из этих улучшений!
ЧАСТЬ 3
ГЛАВА 3.8
Ren’Py —
игровой движок
ВРЕМЯ НА ЧТЕНИЕ: 15 МИНУТ
Привет! Ты уже освоил основы Pygame и даже сделал несколько
собственных проектов. Теперь давай познакомимся с Ren’Py — движком для создания визуальных новелл. Это отличный способ быстро
собрать свою первую интерактивную историю, даже если ты не художник и не программист-профи.
Зачем нужен Ren’Py?
Ren’Py позволяет легко объединять текст, картинки, музыку и выборы игрока. Ты сможешь создавать истории с разными концовками,
диалогами и даже мини-играми.
Как установить Ren’Py
1. Перейди на официальный сайт: https://www.renpy.org/
2. Скачай версию для своей операционной системы (Windows,
Mac или Linux).
3. Распакуй архив в удобную папку.
4. Запусти файл renpy.exe (или аналог для твоей ОС).
У тебя откроется лаунчер Ren’Py — это главный центр управления
твоими проектами. Здесь ты сможешь создавать новые игры, запускать их и редактировать сценарии.
276
Ren’Py — игровой движок
Отлично, ты установил Ren’Py и готов двигаться дальше! Теперь
давай создадим твой первый проект и разберёмся, из чего состоит
игра на этом движке.
Создаём новый проект
1.
2.
3.
4.
Открой Ren’Py Launcher.
Нажми кнопку Create New Project.
Придумай название для своей игры (например, My first novel).
Выбери язык (оставь English — позже ты сможешь писать сценарий на русском).
5. Выбери шаблон оформления (можно оставить стандартный).
6. Нажми Create Project.
Теперь твой проект появился в списке слева.
ЧАСТЬ 3
Если откроешь папку проекта на компьютере, увидишь несколько
файлов и папок. Самое главное — папка game. В ней хранятся все
сценарии, картинки и музыка.
277
Глава 3.8
Структура проекта
• game/script.rpy — главный файл сценария. Здесь ты будешь
писать свою историю.
• game/images/ — сюда добавляй картинки для фонов и персонажей.
• game/audio/ — здесь будут лежать музыка и звуки.
Запуск шаблонной игры
Попробуй запустить свою новеллу прямо сейчас! Для этого выбери
проект в лаунчере и нажми Launch Project. Откроется окно игры — ты
увидишь пример истории, которую можно адаптировать под себя.
В следующей главе мы начнём писать свой собственный сценарий
и добавим первых персонажей. Всё просто — ты справишься!
КОНТРОЛЬНЫЕ
ВОПРОСЫ
ЧАСТЬ 3
• Что такое визуальная новелла?
• Для чего используется Ren’Py?
• Какие примеры визуальных новелл ты знаешь или хотел бы
создать сам?
• Как создать новый проект в Ren’Py?
• Где находится основной сценарный файл твоей игры?
ГЛАВА 3.9
Сценарий и создание
персонажей
ВРЕМЯ НА ЧТЕНИЕ: 20 МИНУТ
Ты уже создал свой первый проект в Ren’Py и познакомился со структурой папок. Теперь пора добавить в игру персонажей и начать писать
диалоги — ведь это основа любой визуальной новеллы!
Как добавить персонажа
Чтобы не писать имя героя и цвет его реплик каждый раз вручную,
в начале файла script.rpy обычно создают «переменные» для персонажей. Для этого используется команда define.
Например:
define d = Character('Дима', color="#4ca6ff")
Напомню, что script.rpy лежит в папке game.
Здесь:
• d — короткое имя, которое ты будешь использовать в коде для
обращения к персонажу;
• 'Дима' — имя, которое увидит игрок;
• color="#4ca6ff" — цвет, которым будет выделяться имя героя
в диалогах.
279
Глава 3.9
Пример диалога
Теперь добавим простую сцену:
label start:
d "Привет! Я —
твой первый персонаж в Ren’Py".
"А это —
текст от автора, без имени героя".
d "Пора создавать свою историю!"
return
ЧАСТЬ 3
Вот так будет выглядеть игра, если ты сейчас её запустишь:
Когда ты используешь d, Ren’Py сам подставляет имя и цвет. Если
просто написать текст в кавычках без имени, получится реплика
от автора или повествование.
В Ren’Py команда label используется для создания «метки» —
это закладка или название определённого места в сценарии твоей
игры. Метка позволяет обозначить участок кода, к которому можно
обратиться в любой момент — например, чтобы начать игру, сделать
переход между сценами или организовать ветвления сюжета.
label start:
"Это начало игры».
280
Сценарий и создание персонажей
Когда игрок нажимает Start Game, Ren’Py автоматически начинает
выполнение с метки start — это обязательная точка входа в любой
новелле.
Ты можешь создавать свои метки для разных сцен:
label парк:
"Ты пришёл в парк".
return
Позже, используя команду jump парк, игра перейдёт к этому месту
и выполнит все команды внутри метки.
Таким образом, label — это способ организовать и структурировать
твой сценарий, чтобы легко управлять переходами и логикой игры.
Несколько персонажей
Добавить второго героя так же просто:
define s = Character('Саша', color="#c8ffc8")
И теперь в диалоге можно чередовать реплики:
d "Саша, привет!"
s "Привет, Дима!"
Вот такой у нас получился код:
define d = Character('Дима', color="#4ca6ff")
define s = Character('Саша', color="#c8ffc8")
ЧАСТЬ 3
label start:
d "Привет! Я —
твой первый персонаж в Ren’Py".
"А это —
текст от автора, без имени героя".
d "Пора создавать свою историю!"
d "Саша, привет!"
s "Привет, Дима!"
return
281
Глава 3.9
КОНТРОЛЬНЫЕ
ВОПРОСЫ
ЧАСТЬ 3
• Как добавить нового персонажа в Ren’Py? Приведи пример
кода.
• Как в коде обозначается реплика персонажа, а как — повествование?
• Для чего используется команда label?
ГЛАВА 3.10
Изображения в Ren’Py
ВРЕМЯ НА ЧТЕНИЕ: 20 МИНУТ
Ты уже умеешь создавать персонажей и писать диалоги. Теперь пора
добавить в игру изображения — фоны и спрайты героев. Именно
благодаря картинкам визуальная новелла становится по-настоящему
живой!
Как добавить изображения в Ren’Py
1. Помести нужные картинки (например, фоны или изображения персонажей) в папку game/images твоего проекта. Файлы
должны быть в формате .png или .jpg, а их имена лучше писать
маленькими буквами и без пробелов.
2. Чтобы использовать изображение в коде, можно сразу обращаться к его имени без расширения. Например, если у тебя
есть файл game/images/bg_school.png, ты можешь показать
его так:
scene bg_school
Эта команда очистит экран и покажет фон школы.
3. Чтобы показать персонажа, например файл game/images/
dima_happy.png, напиши:
show dima_happy
283
Глава 3.10
Изображение появится поверх фона. Если ты сменишь эмоцию
или позу (например, на dima_sad), новое изображение заменит старое.
4. Чтобы убрать изображение, используй:
hide dima_happy
Как объявлять изображения через оператор image
Если хочешь задать псевдоним или использовать необычный путь,
можно объявить изображение в начале файла:
image bg park = "images/bg_park.jpg"
image dima smile = "images/dima_smile.png"
Теперь для показа этих картинок используй:
scene bg park
show dima smile
Также ты можешь использовать шаблоны для картинок при помощи Placeholder:
image bg park = Placeholder("bg")
image dima smile = Placeholder("boy")
ЧАСТЬ 3
Попробуй запустить этот код и посмотри, как работает твоя игра:
define d = Character('Дима',
, color=
="#4ca6ff")
define s = Character('Саша', color="#c8ffc8")
image bg park = Placeholder("bg")
image dima smile = Placeholder("boy")
label start:
scene bg park
show dima smile
d "Привет! Я —
твой первый персонаж в Ren’Py."
"А это —
текст от автора, без имени героя."
d "Пора создавать свою историю!"
284
Изображения в Ren’Py
d "Саша, привет!"
s "Привет, Дима!"
return
Эффекты перехода
Чтобы смена картинок выглядела плавнее, добавь оператор with:
scene bg_school with fade
show dima_happy with dissolve
fade и dissolve — самые популярные эффекты для плавных переходов между изображениями.
КОНТРОЛЬНЫЕ
ВОПРОСЫ
• Как добавить изображение фона в игру? Приведи пример
команды.
• Как показать и убрать спрайт персонажа на экране?
• Зачем объявлять изображения через оператор image?
ЧАСТЬ 3
ГЛАВА 3.11
Музыка в Ren’Py
ВРЕМЯ НА ЧТЕНИЕ: 15 МИНУТ
Ты уже умеешь добавлять в свою новеллу диалоги, персонажей и картинки. Теперь давай сделаем игру ещё интереснее — добавим музыку
и звуки! Аудио создаёт атмосферу: помогает передать настроение
сцены, выделить важные моменты и просто делает игру живой.
Как добавить музыку и звуки в Ren’Py
1. Помести аудиофайлы (музыка и эффекты) в папку game/audio
или просто в папку проекта. Поддерживаются форматы: mp3,
ogg, wav, opus и другие.
2. Для воспроизведения музыки используй команду:
play music "audio/background_music.ogg"
Музыка начнёт играть и будет звучать до тех пор, пока ты
не остановишь её или не включишь другую.
3. Для добавления звукового эффекта (например, щелчка или
звука шагов), используй:
play sound "audio/click.wav"
Звуки на канале sound не мешают музыке и могут воспроизводиться одновременно.
286
Музыка в Ren’Py
4. Для того чтобы остановить музыку, воспользуйся командой:
stop music
Можно добавить плавное затухание:
stop music fadeout 1.0
(музыка затихнет за 1 секунду).
5. Для того чтобы зациклить музыку, добавь параметр loop:
play music "audio/loop.ogg" loop
6. Если хочешь, чтобы музыка плавно начала играть, используй
fadein:
play music "audio/intro.ogg" fadein 2.0
(музыка появится за 2 секунды].
Пример в сценарии
label start:
В следующей главе ты узнаешь, как добавить в игру выборы и сделать сюжет нелинейным!
287
ЧАСТЬ 3
play music "audio/background.ogg" fadein 1.0
"Ты слышишь приятную музыку на фоне."
play sound "audio/click.wav"
"Звучит короткий звук —
например, щелчок."
stop music fadeout 1.0
"Музыка плавно затихает."
Глава 3.11
КОНТРОЛЬНЫЕ
ВОПРОСЫ
ЧАСТЬ 3
• Как добавить музыку в свою новеллу? Приведи пример
команды.
• Чем отличаются команды play music и play sound?
• Как сделать так, чтобы музыка плавно начала играть или затихла?
ГЛАВА 3.12
Выбор в сценарии
ВРЕМЯ НА ЧТЕНИЕ: 20 МИНУТ
Теперь ты знаешь, как добавить в свою новеллу изображения и музыку.
Самое время сделать сюжет интерактивным — добавить выборы и ветвления. Именно благодаря этому визуальные новеллы становятся понастоящему захватывающими: игрок сам определяет развитие истории!
Как сделать выбор в Ren’Py
В Ren’Py для создания развилок используется команда menu. С её
помощью ты можешь предложить игроку несколько вариантов действий, каждый из которых будет определять продолжение сюжета.
Пример:
label start:
"Ты стоишь на перекрёстке."
menu:
"Пойти налево":
jump left_path
"Пойти направо":
jump right_path
label left_path:
"Ты выбрал левую дорогу."
return
289
Глава 3.12
label right_path:
"Ты выбрал правую дорогу."
return
После команды menu: перечисляются варианты выбора (в кавычках).
После каждого варианта указывается, что делать дальше: обычно
это jump на нужную метку (label).
Зачем нужны ветвления
С помощью меню ты можешь создавать нелинейные истории, где
каждое решение игрока влияет на сюжет, отношения между персонажами или даже концовку игры. Это делает новеллу интереснее
и даёт игроку ощущение настоящего выбора.
Советы
ЧАСТЬ 3
• Не делай слишком много развилок подряд, иначе сценарий
быстро станет запутанным.
• Можно использовать переменные, чтобы запоминать выборы
игрока и менять сюжет в будущем.
ЗАКЛЮЧЕНИЕ
Заключение
Что мы с тобой прошли
Поздравляю! Если ты читаешь эти строки — значит, ты не просто
открыл эту книгу. Ты кодил. Печатал. Ломал. Исправлял. Смеялся.
Радовался. А может, и немного злился. Это всё часть пути. И ты его
прошёл.
За время работы с книгой ты:
• освоил основы языка Python:
» переменные, типы данных, арифметику,
» логику, условия, циклы,
» функции, списки, строки, словари,
» обработку ошибок и исключений;
• научился работать с графикой при помощи Pygame:
» создавать окно игры, рисовать объекты, управлять ими,
» обрабатывать нажатия клавиш и клики мыши,
» добавлять звук, анимацию, счётчики, таймеры.
• написал свои игры: от простых кликеров до движущихся персонажей, змейки и крестиков-ноликов.
А ещё ты:
• сам управлял логикой, цветами, скоростью, интерфейсом;
• научился искать и устранять ошибки (да-да, ты приручил
Багги!);
• научился продумывать свои действия и улучшать игры — создавать собственные фишки, новые уровни, добавлять идеи;
• прокачал логическое мышление, внимание и терпение. Без
этого в кодинге никуда.
291
Глава 3.12
Но самое главное — ты изменился
Может, ты не заметил. Но ты стал другим. Серьёзно.
Когда ты впервые открыл пустой редактор — перед тобой был
экран.
Теперь — перед тобой мир, который ты можешь построить сам.
Ты стал тем, кто не просто потребляет, а создаёт.
Тем, кто не боится ошибок. Тем, кто знает, как включить свет в цифровом пространстве.
Ты стал начинающим программистом, а может — даже больше.
Что дальше?
Книга закончилась, но твой путь только начался.
Вот куда можно идти дальше:
• делать новые игры
» добавь уровни, врагов, бонусы, физику. Или придумай новую механику. Ты это уже умеешь. Просто открой редактор
и начни;
• изучать Python глубже
» посмотри, как работают классы, модули, библиотеки. Начни делать утилиты, автоматизацию, мини-ботов. Да хоть
калькулятор с графиком;
• создать свой проект
» выложи игру на GitHub или itch.io. Покажи друзьям. Сделай
сайт. Кто знает — может, это начало твоей будущей студии;
• научить других
» стань наставником. Объясни другу, брату, сестре, родителям — как работает if. Это закрепит знания и принесёт удовольствие.
Немного человечности
Ты знаешь, программирование — это не о сухом коде. Это об эмоциях. О воле. Об интересе. О радости, когда «заработало!». О ярости,
когда «всё упало». Об азарте, когда «ещё чуть-чуть, и будет круто».
Мы — Коди, Багги и наша книга — прошли этот путь вместе с тобой.
Мы помогали тебе, подталкивали, подсказывали.
292
Заключение
Но главное — всё сделал ты сам.
Ты справился. Ты можешь.
Ты не просто «пробовал» — ты кодил.
А значит — ты прошёл первый уровень. Добро пожаловать в игру
под названием «программирование».
Последнее напутствие от Коди
Ты теперь умеешь управлять
машиной. Не забывай —
куда бы ты ни ехал, главное,
чтобы это был твой путь.
А от Багги — коротко
Ну что, начинающий программист, я ещё вернусь к тебе.
И ошибок подкину. Но ты уже
знаешь, как со мной справляться.
Спасибо, что был с нами.
До встречи в следующем проекте. Или в твоей игре.
АйДаКодить!
ПРИЛОЖЕНИЕ
Приложение
Как делают игры: все этапы создания
Эта глава подробно описывает процесс создания современных компьютерных игр — от формирования идеи до релиза готового продукта.
Здесь рассмотрены все основные этапы разработки: прототипирование, создание игровых персонажей и локаций, написание кода,
тестирование, полишинг и маркетинг.
Разработка видеоигр — это сложный и многоэтапный процесс,
в котором участвует большое количество людей разных специальностей. Давайте подробно разберём, как именно создаются современные игры.
Для начала рассмотрим, кто руководит всем процессом создания игры. В самом верху стоят заказчики и инвесторы. После них
идёт издатель. Он может влиять на разработчика, так как выступает
посредником между теми, кто стоит выше, и самой студией. Далее
располагаются директора студии, среди которых могут быть владельцы большого пакета акций.
Ниже рангом может размещаться стейкхолдер — это лицо или
организация, имеющие права или долю.
Теперь рассмотрим, как устроена работа внутри студии.
Первый вариант управления — это когда всем процессом руководит продюсер. Он же — ведущий гейм-директор или ведущий
гейм-дизайнер. Отделами руководят лиды или скрам-мастеры.
Второй вариант управления — это когда всем руководят проджект-менеджер и продакт-менеджер. Они напрямую подчиняются
директорскому составу компании.
294
Приложение
Три вида компаний-разработчиков
Существует три типа игровых студий:
• независимые (инди) — энтузиасты, независимые разработчики;
• Mobile —
команды, занимающиеся разработкой мобильных
игр;
• AAA (Triple A студии) — буквы A обозначают финансирование.
Чем больше этих букв, тем серьезнее проект.
Концепция и документация
На первом этапе команда разработчиков во главе с гейм-дизайнером проводит мозговой штурм и придумывает основную идею для
игры. Обсуждаются жанр, сеттинг, геймплей, персонажи и другие
ключевые аспекты.
Все финальные решения заносятся в три основных документа:
концепт-документ, vision-документ и Feature-лист.
Концепт-документ — это краткое и емкое описание игры.
Стандартные пункты этого документа таковы:
• название игры;
• основная идея;
• жанр;
• аудитория;
• особенности;
• сюжет;
• механика геймплея;
• описание игрового мира и персонажей;
• платформы, на которые ориентирована игра;
• системные требования;
• сроки и бюджет разработки;
• какие технологии будут использоваться в игре.
Vision-документ посвящен не самому игровому процессу, а тому,
что разработчик хочет получить в итоге.
Этот документ содержит следующие пункты:
• полное описание игры;
• целевая аудитория, исследование рынка;
• конкуренты;
295
Приложение
• стиль и арты;
• бизнес-модель — способы монетизации игры.
Feature-лист посвящен таким вопросам:
• особенности — на какие детали будет сделан больший акцент,
например на графику, уникальные игровые механики;
• уникальность — сюда входят все моменты, которые делают
эту игру уникальной по сравнению с играми конкурентов.
Перечисленные документы станут основой для дальнейшей разработки. Все вместе эти три документа формируют так называемый
общий дизайн-документ: диз-док. На ранней стадии разработчики
выбирают игровой движок из существующих или пишут свой «с нуля».
Но второй вариант на сегодня — это устаревшая практика. Собираются референсы — фотографии из реальной жизни, игр или кино. Эти
концепты предоставляют продюсерам и инвесторам. После этого
концепт-художники приступают к созданию иллюстраций.
Прототипирование
На этом этапе начинается непосредственная реализация задуманного. Художники создают концепт-арты, а 3D-моделлеры — первые
модели персонажей и локаций.
3D моделирование можно разделить на два направления. Первое —это Hard-Surface. Речь идёт о создании рукотворных объектов
для наполнения мира: бутылок, коробок, кирпичей и многого другого.
Сюда же относятся и здания. Их можно собирать из отдельных модулей, как конструктор. Иногда прибегают к процедурному моделированию с использованием программы Houdini. К этому направлению
относят и транспорт.
Второе направление — это Organic Modeling, то есть природа.
К органике относятся деревья и существа, персонажи.
Создание персонажей
Как создаются персонажи? Сперва определяют, каким именно будет
персонаж — животным, монстром или человеком. Далее эти референсы
собирают в композиции — мудборды. Художник рисует концепт-эскиз
и передает 3D-моделлеру.
296
Приложение
Следующий этап — скульптинг, процесс, напоминающий лепку из пластилина. На этом этапе используется программа ZBrush.
Скульптинг начинают с создания болванки персонажа, после чего
прорабатывают анатомию и силуэт.
Второй этап — внутреннее наполнение и большие детали. Третий —
маленькие детали и нюансы анатомии. Иногда бывает и четвёртый
этап — сверхдетализация, например поры или морщины. Далее идёт
ретопология сетки, после этого создается UV-карта для будущих
текстур. Последующие этапы — запекание, текстуринг.
Модель переносится в другой 3D-пакет. Стандартно используют 3DS Max, а для более точной физической анимации — программу Cascader. Создаётся скелет, производится анимация. Сложные
движения человеческого тела фиксируются на модели с помощью
специальных датчиков, а затем переносятся в программу.
После создания персонажа и его мимики он переносится в игровой
движок и настраивается более точно. Можно привязать анимации
к действиям, привязать персонажа к искусственному интеллекту,
либо добавить диалоги.
Создание уровней
Далее рассмотрим, как левел-дизайнеры создают уровни. Всё начинается с референсов. Команда может выехать на определенную
локацию и сделать снимки. Но в большинстве случаев уровни начинают рисовать на бумаге. Отмечаются ивенты — где и сколько врагов,
какие события привязаны к точкам на локации и т. д. В результате
нарисованная на бумаге карта становится больше похожа на схему.
Программисты пишут базовый игровой код. Их работа начинается
с описания. Члены команды обговаривают всё, что нужно сделать.
Затем составляют блок-схему и изображают на ней конкретные части
алгоритма в виде разных геометрических фигур — прямоугольников,
параллелограммов, ромбов. Блоки соединяют между собой линиями,
которые указывают на последовательность выполнения программы.
После компоновки блоков кода программисты приступают к практической работе. Обычно применяют языки программирования C++
и C#. Для графики подключаются библиотеки DirectX и OpenGL,
Vulkan.
297
Приложение
В играх широко используются методы объектно-ориентированного программирования.
Как это работает?
Допустим, тебе нужно создать оружие. Сначала необходимо создать
базовый класс — оружие и приписать ему базовые свойства: урон,
дальность стрельбы, количество патронов. Затем выполняется наследование от базового класса и подстановка определенных параметров.
Для того чтобы упростить разработку игры, в рамках самого движка
используют визуальное программирование. Оно основывается на манипулировании блок-схемами, которые называются узлами (нодами).
Для мобильных игр используют языки программирования Java
или Swift. Последний используется для устройств с операционной
системой iOS (Apple). Для браузерных игр применяют HTML 5, PHP
и Java Script с дополнительными библиотеками.
Геймплей-программисты воплощают в жизнь игровые механики — всё, что оживляет мир и позволяет игроку взаимодействовать
с ним. AI-программист создаёт искусственный интеллект — модель
поведения ботов. Здесь также часто используют ноды, вместо того
чтобы писать код. Это значительно ускоряет процесс разработки.
Система нодов удобна тем, что с ней могут спокойно работать
и дизайнеры, которые по сути не знают программирования. Есть ещё
сетевые программисты, программисты анимации, интерфейсов и т. д.
По итогу работы всех специалистов создается играбельная демоверсия, которая тестируется на предмет геймплея и оптимизации.
Вертикальный срез
Когда основные игровые механики готовы, формируется вертикальный срез игры — небольшой образец конечного продукта. Это может
быть пара уровней, несколько строк кода и реализация основных
персонажей. Вертикальный срез демонстрируют инвесторам.
Производство контента
На этом этапе, который может растянуться на несколько лет, создаётся основная масса игрового контента. Художники разрабатывают
3D-модели, локации, интерфейсы. Программисты пишут код, настра-
298
Приложение
ивают физику и ИИ. Композитор сочиняет музыку. Актёры озвучивают
диалоги. Все компоненты постепенно собираются воедино. На этот
этап зачастую уходят годы. Работа над всеми серьезными проектами
длится, как правило, 3–5 лет.
Тестирование
Готовая игра проходит тщательное тестирование. На этом этапе
выявляют и исправляют ошибки, проводят оптимизацию производительности. Могут даже провести бета-тестирование с участием
игроков. Основная задача тестирования — убедиться в том, что игру
можно пройти до конца.
Релиз и последующая поддержка
Игра поступает в продажу. После релиза разработчики выпускают
обновления и дополнительный контент, исправив оставшиеся ошибки.
Таковы основные этапы создания современной компьютерной
игры. Это кропотливая работа большой команды, и она может длиться
от 2 до 5 лет. Но в итоге мы получаем качественный игровой продукт,
способный увлечь на долгие часы.
Об авторах
Эта книга написана отрядом разнохарактерных кодеров, которых
можно было бы запустить в игру, и они обязательно поспорили бы,
кто из них главный.
Никита Брагин —
«Профессор Переменная»
(Часть 1)
Архетип: Гордон Фримен
(Half-Life)
Роль в команде: спокойный герой, который творит чудеса без лишних слов.
Преподаватель-практик с шестилетним стажем, специалист по математике и информатике, создатель авторского курса «Python Start»
в сети школ #АйДаКодить.
За два года работы в проекте Никита подготовил к экзаменам
десятки учеников — и не просто научил их писать код, а показал, как
из строчек вырастает настоящая игра.
Он убеждён: программирование — это не зубрёжка синтаксиса,
а инструмент, который развивает логику, креатив и умение воплощать
идеи в жизнь. Любит порядок, логические выражения и чай, который
заваривался ровно столько, сколько длится цикл while True. Считает,
что знак == — символ справедливости, а знак = — символ судьбы.
Если бы Никита преподавал в Хогвартсе, его предмет назывался бы «Основы магии условий и переменных».
300
Об авторах
Александр Ташкин —
«Гейм-мастер Pygame»
(Часть 2)
Архетип: Leon Kennedy
(Resident Evil)
Роль в команде: невозмутимый защитник
чистого кода, который даже в хаосе багов
остаётся хладнокровным и точным.
Геймдев-энтузиаст, преподаватель и сценарист по духу. Автор курса
«Python PRO» для школы программирования #АйДаКодить.
Тот самый человек, который однажды сказал:
«А что, если в учебнике по Python будут персонажи —
код и баг?»
Так появились Коди и Багги — вечные напарники, враги, шутники
и философы, благодаря которым эта книга живёт и смеётся.
Александр придумал их не ради прикола (ну, не только ради него).
Он хотел, чтобы каждый ученик увидел в них себя: Коди — когда всё
получается, Багги — когда не получается, но зато весело.
Под его руководством дети создают свои кликеры, змейки, платформеры и начинают видеть за командами — мир, где каждое if может
стать выбором судьбы.
Любимая фраза:
«Ошибки не ломают код. Они делают его приключением».
Если бы Александр снимал фильм, он бы назывался «Buggy &
Cody: Начало».
301
Приложение
Мухамет Идрисов —
«Маг из Raycasting’а»
(Часть 3)
Архетип: Геральт из Ривии
(The Witcher)
Роль в команде: мудрый одиночка, видящий мир в трёх измерениях и одном
парадоксе.
Разработчик, преподаватель и философ цифрового пространства.
Пишет код так, будто строит храм логики в четвёртом измерении.
Автор продвинутых курсов #АйДаКодить по игровым движкам,
3D-логике и визуальным новеллам на Ren’Py.
Для него Python — это кисть, а экран — холст, где можно рисовать
миры, тени и перспективу.
Когда ученики делают первые шаги в 3D, он улыбается и говорит:
«Всё просто: немного тригонометрии, немного веры и один
правильный цикл».
Верит, что каждый ребёнок должен хотя бы раз написать свой
«Doom для души» — просто чтобы понять, что чудеса тоже компилируются.
Если бы Мухамет был персонажем RPG, его класс назывался бы
«Архитектор пространства и света», а заклинание — import math, hope.
302
Об авторах
Владимир Афанасьев —
«Главный баголов»
(редактор-куратор)
Архетип: Marcus Fenix
(Gears of War)
Роль в команде: архитектор вселенной,
продюсер, шеф-ментор и главный балансировщик хаоса.
Именно он заставлял авторов объяснять код так, чтобы его поняла
даже кошка. А ещё он придумал, что каждая ошибка должна вызывать улыбку, а не страх. Где-то добавил шутку, где-то убрал скуку,
а где-то просто сказал:
«Ребята, дети — это не аудитория, это игроки. Пусть им
будет весело».
Предприниматель, ментор и создатель проектов под брендом «АйДа» — сети детских школ программирования АйДаКодить
и летнего IT-лагеря АйДаКемп.
Автор книги «Факап № 18: плохая книга о том, как делать бизнес»,
в которой он с самоиронией описывает то, как ошибки превращаются
в опыт, а опыт — в систему.
В «АйДаКодить» именно Владимир собрал команду и придумал,
что учебник по Python должен быть живым, смешным и человечным.
Если бы Владимир был классом в Python, то выглядел бы примерно так:
class Bugolov:
def __init__(self):
self.projects = ["АйДаКодить", "АйДаКемп", "Факап № 18"]
def run(self):
print("Ошибки - часть сюжета. Главное - не забыть Ctrl+S.")
Все права защищены. Книга или любая ее часть не может быть
скопирована, воспроизведена в электронной или механической форме,
в виде фотокопии, записи в память ЭВМ, репродукции или каким-либо
иным способом, а также использована в любой информационной системе
без получения разрешения от издателя. Копирование, воспроизведение
и иное использование книги или ее части без согласия издателя
является незаконным и влечет уголовную, административную
и гражданскую ответственность.
Производственно-практическое издание
Для среднего и старшего школьного возраста
ПРОГРАММИРОВАНИЕ ДЛЯ ДЕТЕЙ
Афанасьев Владимир Владимирович, Брагин Никита Сергеевич,
Ташкин Александр Игоревич, Идрисов Мухамет Ильшатович
PYTHON ДЛЯ ДЕТЕЙ
ИГРАЕМ, ЧТОБЫ ПРОГРАММИРОВАТЬ
Главный редактор Р. Фасхутдинов
Руководитель направления В. Обручев. Ответственный редактор Л. Салихова
Научный редактор Е. Суворова. Литературный редактор О. Рухлова
Младший редактор М. Назаренко. Художественный редактор С. Власов
Компьютерная верстка Дж. Льюис. Корректоры Е. Ерошкина, Р. Болдинова
В оформлении обложки использованы иллюстрации:
Colorfuel Studio, yusuf_demirci / Shutterstock / FOTODOM
Используется по лицензии от Shutterstock / FOTODOM
Страна происхождения: Российская Федерация
Шы6арушы ел: Ресей Федерациясы
ООО «Издательство «Эксмо»
123308, Россия, г. Москва, ул. Зорге, д. 1, стр. 1, эт. 20, каб. 2013. Тел.: 8 (495) 411-68-86.
Home page: www.eksmo.ru E-mail: info@eksmo.ru
Rндіруші: «Издательство «Эксмо» ЖШX
123308, Ресей, МYскеу Zаласы, Зорге к[шесі, 1-\й, 1-Z]рылыс, 20 Zабат, 2013-каб.
Тел.: 8 (495) 411-68-86. Home page: www.eksmo.ru E-mail: info@eksmo.ru.
Тауар белгісі: «Эксмо»
Интернет-магазин : www.book24.ru
Интернет-магазин : www.book24.kz
Интернет-д/кен : www.book24.kz
12+
Импортёр в Республику Казахстан ТОО «РДЦ-Алматы».
XазаZстан Республикасына импорттаушы «РДЦ-Алматы» ЖШС.
Дистрибьютор и представитель по приему претензий на продукцию
в Республике Казахстан: ТОО «РДЦ-Алматы»
ТОО РДЦ Алматы, Алматы, ул. Домбровского, 3«а», литер Б, офис 1.
Дистрибьютор жYне XазаZстан Республикасында [німге ша6ымдар
Zабылдау ж[ніндегі [кіл: «РДЦ-Алматы» ЖШС.
Алматы Z., Домбровский к[ш., 3 «а», литер Б, офис 1.
Тел.: 8 (727) 251-59-90/91/92. E-mail: RDC-Almaty@eksmo.kz
Сведения о подтверждении соответствия издания согласно законодательству РФ
о техническом регулировании можно получить на сайте Издательства «Эксмо»:
www.eksmo.ru/certification
ТехникалыZ реттеу туралы РФ за{намасына сай басылымны{ сYйкестігін растау
туралы мYліметтерді мына адрес бойынша алу6а болады: http://eksmo.ru/certification/
Произведено в Российской Федерации
Ресей Федерациясында [ндірілген
Сертификаттау6а жатпайды
Дата изготовления / Подписано в печать 11.12.2025. Формат 70x1001/16.
Гарнитура «Myriad Pro». Печать офсетная. Усл. печ. л. 24,63.
Тираж
экз. Заказ