Предыдущая часть: Пишем Питона на Питоне!
Может показаться странным, но мы начнём делать игру с загрузки ini-файла. Есть сильное подозрение, что это здорово понадобится в будущем :)
- Формат ini-файла очень прост и подходит для ручного редактирования. Вы наверняка с ним встречались, а если нет, то можете ознакомиться здесь.
- Я рассматривал вариант с форматом JSON, но он менее читабелен и его труднее редактировать, поэтому был выбран более простой формат.
В Питоне есть готовый парсер (то есть обработчик) ini-файлов. Это класс ConfigParser в модуле configparser. Но он мне не нравится тем, что для доступа к параметру, допустим, game.speed, надо писать так:
config['game']['speed']
Было бы гораздо лучше писать так:
config.game.speed
Поэтому мы возьмём класс ConfigParser и завернём его в свой класс, который обеспечит нам нужный вид доступа. Заодно мы создадим структуру каталогов проекта и будем размещать разные классы в разных файлах, чтобы у нас всё было как у больших.
Итак, в рабочем каталоге, где вы делаете проект, создайте папку app, а в ней папку utils. В этой папке мы создадим файл config.py cо следующим кодом (ссылка):
Суть нашего класса Config в том, чтобы создать объект класса ConfigParser, загрузить в него файл (filename), и получить готовый к употреблению конфиг (config). Он cостоит из списка секций, а каждая секция содержит список переменных. Всё это, то есть и секции, и переменные в них, нужно взять и сделать свойствами нашего класса.
Для этого мы проходим по списку секций (for section_name in config) и для каждой непустой секции создаём безымянный объект:
section_object = type('', (), {})
Читайте также: ООП в Python: Особенности реализации.
Далее мы проходим уже по секции (for key in section) и найденные пары ключ-значение делаем свойствами (атрибутами) нашего объекта:
setattr(section_object, key, section[key])
Функция setattr(obj, name, value) изменяет в объекте obj свойство с именем name, присваивая ему value. Если такого свойства нет, то оно создаётся. Именно это нам и нужно. В результате, обработав одну секцию, мы получили безымянный объект со свойствами, которые создались из содержимого секции. Теперь весь этот объект мы в свою очередь делаем свойством объекта нашего класса Config:
setattr(self, section_name, section_object)
Всё это происходит при создании объекта. И теперь мы можем писать
config = Config('game.ini')
и далее обращаться к параметрам вроде config.game.speed, и всё будет работать, так как game является атрибутом объекта config, а speed является атрибутом объекта game. Мы их просто создали вручную.
Да, а вот так пока выглядит (исключительно тестовый) файл game.ini (ссылка):
Создайте его в основном каталоге.
Там же создайте файл main.py, где мы проверим работу конфига. В нём пока всего три строчки:
from app.utils.config import Config
config = Config('game.ini')
print(config.game.test)
Сначала мы импортируем собственный класс Config из собственного модуля app.utils.config (помните, что структура каталогов это app/utils).
Затем мы создаём объект класса Config, передав ему в конструктор имя ini-файла (game.ini).
И наконец, мы распечатываем значение config.game.test. Это значит, что в ini-файле должна быть секция с именем game, а в ней должен быть параметр с именем test. И вот значение этого параметра мы и должны получить. Если всё сработало правильно, то после запуска программы будет распечатана строка 'test'. Вы можете изменить ini-файл, задать другие значения параметров или вообще новые параметры, и также попробовать их распечатать.
Следующая часть: Загрузка уровня из файла