Завершаем проект: текстовый квест

Введение

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

Как добавить в квест графику?

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

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

                   _ |\_
                   \` ..\
              __,.-" =__Y=
            ."        )
      _    /   ,    \/\_
     ((____|    )_-\ \_-`
jgs  `-----'`-----` `--`

Откуда взять такие картинки?

  • Можно взять из архива (https://www.asciiart.eu/) или просто поискать в интернете.
  • Можно воспользоваться одним из генераторов, которые умеют произвольную картинку превратить в ASCII Art, например, вот этот. Но скорее всего получится менее отчетливо, как минимум придется поискать картинку с белым или прозрачный фоном.

Вот это, например, Вупсень из генератора.


                      ` `                          
                    `: /                          
                ./++oo/+                          
               .s+ososyss:                        
              `-:/:.//+oss`                       
             .-:/:/::::/+s+                       
           `+/:::::::/+++oy-                      
           //:::::::/o+/-/o`                      
           +::::::::/o+:.:o.                      
           ::::::::::o++/+o`                      
           ./::::::::/oooo-                       
           `-:::::://////+.                       
          `.`..-------.:sys.                      
          .....```````.+soo+                      
         ..-+//-`````.:oo++s.                     
       `./-.ss:-````.--:++++/                     
 `.``.-://:.-..`...----::/+++                     
 `:::::::::-------/::::::::+s.`                   
 .::::::.:--------:/::::::/ydho+:.                
 `.:::- `:-------://:::::::yhho+os/.``            
  ``..  .:::-----:://///://+osy+++osoo/.          
        .::::::::::::/++++++++yo+++oy+os+`        
        --------------/+++++++os++++yo++os`       
        --------------:+++++++os++++ss+++s+       
        ---------------:::::::/+++++ys+++oy+`     
        .:---------------------://+oyo+++oyso`    
         ::--------------::---:---:/o/+++ss+s/    
         `::::-------::+osso/::/++//::::/+++s+    
        `+o++/:::::::osossssyyssssyysyys/:::/.    
        so+/osoo+///s+//+sssydo+ssshsssho::.`     
        `.------` ``/////oo++/:://::.-.`          

Вставляем ASCII в код: многострочный текст

Как вставить ASCII Art в код? Не разбивать же картинку на отдельные строки и выводить по одной?

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

image = """
                }--O--{
                  [^]
                 /ooo\\
 ______________:/o   o\:______________
|=|=|=|=|=|=|:A|":|||:"|A:|=|=|=|=|=|=|
^""""""""""""""!::{o}::!""""""""""""""^
                \     /
                 \.../
      ____       "---"       ____
     |\/\/|=======|*|=======|\/\/|
     :----"       /-\       "----:
                 /ooo\
                #|ooo|#
                 \___/
"""

print(image)

Если в картинке встречается символ \, картинка может слегка "поехать", дело в том, что обратный слэш используется для обозначения специальных непечатных символов (например, \n - это перенос строки), а обычный "бэкслэш" обозначается как \\. Можно либо заменить все бэкслеши в коде на двойные, либо... поставить перед кавычками букву r. Тогда питон сделает это автоматически.

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

image = r'''
                }--O--{
                  [^]
                 /ooo\\
 ______________:/o   o\:______________
|=|=|=|=|=|=|:A|":|||:"|A:|=|=|=|=|=|=|
^""""""""""""""!::{o}::!""""""""""""""^
                \     /
                 \.../
      ____       "---"       ____
     |\/\/|=======|*|=======|\/\/|
     :----"       /-\       "----:
                 /ooo\
                #|ooo|#
                 \___/
'''

print(image)

Кстати, совершенно неясно, почему Microsoft решила выбрать именно его в качестве разделителя у путей в файлах - постоянно приходится писать \\, это называется экранированием. В других операционных системах используется обычный /, экранировать его не нужно.

Используем модули для упрощения кода

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

Все просто! Для этого в папке нашего проекта рядом с основным файлой квеста (пусть это будет quest.py) нужно создать новый файл images.py.

В файл images.py поместим несколько переменных с картинками.

space_station = r'''
                }--O--{
                  [^]
                 /ooo\\
 ______________:/o   o\:______________
|=|=|=|=|=|=|:A|":|||:"|A:|=|=|=|=|=|=|
^""""""""""""""!::{o}::!""""""""""""""^
                \     /
                 \.../
      ____       "---"       ____
     |\/\/|=======|*|=======|\/\/|
     :----"       /-\       "----:
                 /ooo\
                #|ooo|#
                 \___/
'''

bear = r"""
  _      _                        
 : `.--.' ;              _....,_  
 .'      `.      _..--'"'       `-._
:          :_.-'"                  .`.
:  6    6  :                     :  '.;
:          :                      `..';
`: .----. :'                          ;
  `._Y _.'               '           ;
    'U'      .'          `.         ; 
       `:   ;`-..___       `.     .'`.
jgs    _:   :  :    ```"''"'``.    `.  `.
     .'     ;..'            .'       `.'`
    `.......'              `........-'`
"""

А в главном с квестом quest.py будем их импортировать. С точки зрения питона модуль images - это просто файл images.py, а через точку можно обращаться в функциям и переменным из этого файла.

# images.py - наш файл с картинками
import images

# печатаем переменную bear из модуля images
print(images.bear)

# печатаем переменную space_station из модуля images
print(images.space_station)

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

Добавляем звук

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

А что делать, если хочется добавить саундтрек? Ничего, просто добавить его! 😉

Windows:

Если ты работаешь в Windows, то музыку в квест добавить достаточно просто. Для этого в питоне есть встроенный модуль, который называет winsound.

Но есть два нюанс: воспроизводить можно только файлы в формате wav (можно воспользоваться онлайн-конвертером).

import winsound

winsound.PlaySound("ИМЯФАЙЛА.wav", winsound.SND_ASYNC)

# начало квеста...

Mac:

Аналогично windows, но winsound работать не будет, придется поставить сторонний модуль, например, simpleaudio. Для этого нужно запустить терминал (программа в MacOS) и ввести команду pip install --user simpleaudio.

После этого можно использовать его.

import simpleaudio

sound = simpleaudio.WaveObject.from_wave_file("ИМЯФАЙЛА.wav")
sound.play()

# начало квеста...

В примерах выше аудиофайл лежит в одной папке с вашей программой. Например, если файл с вашей программой сохранен на Рабочем столе, то и аудиофайл должен лежать на Рабочем столе.

Добавляем задержки

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

Сделать это можно, используя встроенный модуль time. Пример его использования ниже.

import time

print("Сейчас будет перерыв 10 секунд.")
time.sleep(10)

print("10 секунд прошло, работаем дальше...")

Завершаем квест

Итак, теперь ты уж точно готов взорвать индустрию своей игрой! 💥

Обновленные критерии для самооценивания.

  • +5 баллов - программа запускается без ошибок.
  • +5 баллов - программа всегда работает корректно, если вводить допустимые данные.
  • +5 баллов - программа корректно работает даже если пользователь вводит недопустимые данные, в этом случае она просит повторить ввод.
  • +5 баллов - удобство интерфейса и понятность инструкций.
  • +5 баллов - проработанность сюжета.
  • +5 баллов - квест разбит на функции.
  • +5 баллов - наличие обратных переходов.
  • +5 баллов - наличие инвентаря и/или изменяемость карты в процессе игры.
  • +5 баллов - ASCII графика.
  • +5 баллов - квест разбит на несколько модулей.
  • +5 баллов - звуковое сопровождение.
  • +5 баллов - иногда используются задержки на несколько секунд.
  • +5 баллов - красивый, читаемый код.

Что дальше? Тестирование и обратная связь от пользователей.

Очень важно, чтобы результатами твоей работы пользовались реальные люди. Ведь в конечном итоге, программирование всегда позволяет нам решать проблемы и улучшать жизнь конкретных людей. А еще положительные отзывы дадут тебе толчок к дальнейшему саморазвитию!

А значит, чтобы стать хорошим программистом, тебе нужно общаться с твоими пользователями и собирать обратную связь..

Как только будешь +- уверен в работоспособности своего квеста, покажите его нескольким друзьям или одноклассникам, соберите и проанализируйте конструктивную обратную связь о них (что понравилось? что стоит изменить? что можно добавить в следующей версии?). Я уверен, что они будут в восторге!

Единственная проблема - для запуска твоего проекта нужен питон, но у нее есть простое решение. Просто зарегистрируйся и выложи весь код на сайт Repl.it, там можно загружать файлы по отдельности и скинь друзьям ссылку!

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

from replit import audio

audio.play_file('audio.wav')

# квест...

Поздравляю, как только все получится, ты завершишь свой первый большой проект! 🥳