марио на питоне код

gym-super-mario-bros 7.3.2

pip install gym-super-mario-bros Copy PIP instructions

Released: Jun 12, 2020

Super Mario Bros. for OpenAI Gym

Navigation

Project links

Statistics

View statistics for this project via Libraries.io, or by using our public dataset on Google BigQuery

License: Free For Educational Use (Proprietary)

Tags OpenAI-Gym, NES, Super-Mario-Bros, Lost-Levels, Reinforcement-Learning-Environment

Maintainers

Classifiers

Project description

gym-super-mario-bros

An OpenAI Gym environment for Super Mario Bros. & Super Mario Bros. 2 (Lost Levels) on The Nintendo Entertainment System (NES) using the nes-py emulator.

Installation

The preferred installation of gym-super-mario-bros is from pip :

Usage

Python

NOTE: gym_super_mario_bros.make is just an alias to gym.make for convenience.

NOTE: remove calls to render in training code for a nontrivial speedup.

Command Line

gym_super_mario_bros features a command line interface for playing environments using either the keyboard, or uniform random movement.

Environments

These environments allow 3 attempts (lives) to make it through the 32 stages in the game. The environments only send reward-able game-play frames to agents; No cut-scenes, loading screens, etc. are sent from the NES emulator to an agent nor can an agent perform actions during these instances. If a cut-scene is not able to be skipped by hacking the NES’s RAM, the environment will lock the Python process until the emulator is ready for the next action.

EnvironmentGameROMScreenshot
SuperMarioBros-v0SMBstandard
SuperMarioBros-v1SMBdownsample
SuperMarioBros-v2SMBpixel
SuperMarioBros-v3SMBrectangle
SuperMarioBros2-v0SMB2standard
SuperMarioBros2-v1SMB2downsample

Individual Stages

These environments allow a single attempt (life) to make it through a single stage of the game.

Random Stage Selection

Info about the rewards and info returned by the step method.

Reward Function

The reward function assumes the objective of the game is to move as far right as possible (increase the agent’s x value), as fast as possible, without dying. To model this game, three separate variables compose the reward:

The info dictionary returned by the step method contains the following keys:

KeyTypeDescription
coinsintThe number of collected coins
flag_getboolTrue if Mario reached a flag or ax
lifeintThe number of lives left, i.e.,
scoreintThe cumulative in-game score
stageintThe current stage, i.e.,
statusstrMario’s status, i.e.,
timeintThe time left on the clock
worldintThe current world, i.e.,
x_posintMario’s x position in the stage (from the left)
y_posintMario’s y position in the stage (from the bottom)

Citation

Please cite gym-super-mario-bros if you use it in your research.

Источник

Mario Game In Python With Source Code

Mario Game In Python With Source Code

The Mario Game In Python is written in Python, This Mario Game Code In Python is design in Graphical User Interface (GUI) that uses PyGame library. Talking about the gameplay, it’s a single player game, where the player (Mario) has to dodge fireballs coming out from the dragon. Each level comes with more difficulties, the area gets smaller and smaller as soon as there’s an increment in level. In this Super Mario Python Tutorial you can learn on How To Make Super Mario Game In Python.

A Mario Game Program In Python simple and clean GUI is provided for easy gameplay. The gameplay design is so simple that the user won’t find it difficult to use and understand. Different images are used in the development of this game project, the gaming environment is just like the Mario game.

Watch the video here to see the full running super mario game in python.

Anyway if you want level up your knowledge in programming especially games in python, try this new article I’ve made for you Code For Game in Python: Python Game Projects With Source Code

This Super Mario In Python also includes a downloadable Mario Game In Python source code for free, just find the downloadable source code below and click to start downloading.

To start creating a Mario Game In Python, make sure that you have PyCharm IDE installed in your computer.

By the way if you are new to python programming and you don’t know what would be the the Python IDE to use, I have here a list of Best Python IDE for Windows, Linux, Mac OS that will suit for you. I also have here How to Download and Install Latest Version of Python on Windows.

Steps on how to create a Mario Game In Python

You are free to copy the code given below and download the full source code below.

Источник

Пишем платформер на Python. Часть 2. Подчасть 1, подготовка к созданию редактора уровней

марио на питоне код. image loader. марио на питоне код фото. марио на питоне код-image loader. картинка марио на питоне код. картинка image loader. pip install gym-super-mario-bros Copy PIP instructions
Привет, друзья!

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

Upgrade героя

Добавим нашему герою возможность ускоряться. Для этого немного изменим код метода update.

Для начала, добавим констант

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

Теперь займемся самим методом update

Добавим входной параметр running

Изменим обработку движений персонажа, добавив поведение при ускорении.

И в основном файле добавим обработку события нажатия левого шифта.

И не забываем добавить аргументы при вызове метода hero.update()

Смотрим результаты ( я изменил цвет фона на черный, брутальный цвет для брутального МариоБоя)
Без ускорения
марио на питоне код. image loader. марио на питоне код фото. марио на питоне код-image loader. картинка марио на питоне код. картинка image loader. pip install gym-super-mario-bros Copy PIP instructions
Прыжок с ускорением
марио на питоне код. image loader. марио на питоне код фото. марио на питоне код-image loader. картинка марио на питоне код. картинка image loader. pip install gym-super-mario-bros Copy PIP instructions

Смертельные шипы

Создаем класс, наследующийся от Platform.

Далее, добавим поведение героя при соприкосновении с ним. Для этого, добавим 2 метода в класс персонажа. Первый метод — поведение при смерти, второй — перемещение по указанным координатам(который пригодится нам еще раз чуть ниже)

Т.е. когда мы умираем, игра замирает на некоторое время, затем мы перемещаемся в начало уровня и играем дальше.

Ну и описываем само поведение при пересечении с блоком смерти в методе collide()

Теперь, в основном классе изменим уровень

И добавим создание блока смерти, если в уровне есть символ «*»

Результат:
марио на питоне код. image loader. марио на питоне код фото. марио на питоне код-image loader. картинка марио на питоне код. картинка image loader. pip install gym-super-mario-bros Copy PIP instructions

Порталы

Какой современный сантехник обходится без телепорта? Так давайте и нашего героя не будем делать белой вороной.

Создаём новый тип блока. Работаем в файле blocks.py

Cперва добавляем константы

Затем создаем новый класс.

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

Далее, добавим нашему герою поведение при соприкосновении с порталом

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

И создаем телепортер.

В конце, добавим вызов метода update() у всех анимированных спрайтов

Как-то так
марио на питоне код. image loader. марио на питоне код фото. марио на питоне код-image loader. картинка марио на питоне код. картинка image loader. pip install gym-super-mario-bros Copy PIP instructions

Монстры

Страшные, передвигающиеся, смертельно опасные огоньки.

Отличие монстров от смертельных блоков в том, что монстры могут двигаться.

Будем работать в новом файле, дабы не запутаться. Назовем его очень оригинально — monsters.py

Создадим новый класс Monster. В нём нет ничего такого, чего мы не применяли ранее.
Содержимое всего файла

При создании монстра необходимо указать 6 аргументов: х, y — координаты, left — скорость перемещения по горизонтали, up — скорость перемещения по вертикали, maxLengthLeft — максимальное расстояние в одну сторону, которое может пройти монстр, maxLengthUp — аналогично предыдущему, но по вертикали.

И не забываем добавить импорт с файла monsters.py

И, конечно же, добавим создание монстра в основной файл.

Создадим еще одну группу спрайтов, в которую будем помещать наших монстриков.

Вопрос: Для чего нам еще одна группа? Почему не хватило предыдущей? Ведь в группе спрайтов animatedEntities мы вызываем метод update()
Ответ: В предыдущей группе мы вызываем метод update()без аргументов, а в группе monsters этот метод будет вызывать с аргументом.

Создаем самого монстра.

Смотрим на результат.
марио на питоне код. image loader. марио на питоне код фото. марио на питоне код-image loader. картинка марио на питоне код. картинка image loader. pip install gym-super-mario-bros Copy PIP instructions

Принцесса

Дело чести любого сантехника — спасти принцессу.

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

Нашему персонажу добавим свойство winner, по которому будем судить, что пора завершать уровень.

И внесем изменения в метод collide()

И далее, напишем код создания принцессы

Не забыв вставить символ «P» в уровень.

Смотрим
марио на питоне код. image loader. марио на питоне код фото. марио на питоне код-image loader. картинка марио на питоне код. картинка image loader. pip install gym-super-mario-bros Copy PIP instructions

Уровень

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

Что мы тут видим? Ни чего такого, чего бы не рассматривали в этом посте (включая первую часть). Сперва генерирум статические платформы, посредствам символов «[«,»-«, «*»,»]»,»|»
Где «[« — показывает парсеру начало уровня
«]» — соответсвенно, конец уровня
«|» — конец строки
«-« — обычная платформа
«*» — шипованная платформа

Затем, в строчке «player 55 44» мы указываем начальные координаты нашего героя
«portal 128 512 900 35» — первые два числа — координаты портала, вторые — координаты перемещения
«monster 150 200 1 2 150 100» — первые два числа, аналогично, координаты монстра, затем, вторые два — скорость горизонтальная и вертикальная, и последние — максимальное расстояние в одну сторону по горизонтали и вертикали.
Как вы уже заметили, как порталов, так и монстров может быть столько, сколько вам захочется.
Символ «/» означает конец файла. Все данные, после него, считаны не будут.

Теперь, давайте, напишем сам парсер.
Работаем в основном файле.

Для начала, перенесем все массивы и группы из функции main() в тело основной программы

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

И добавляем новую функцию

Не забываем вызвать эту функцию и указать переменные startX и startY как стартовые координаты нашему герою.

Источник

Пишем платформер на Python, используя pygame

марио на питоне код. image loader. марио на питоне код фото. марио на питоне код-image loader. картинка марио на питоне код. картинка image loader. pip install gym-super-mario-bros Copy PIP instructions
Сразу оговорюсь, что здесь написано для самых маленькихначинающих.

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

Что такое платформер?

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

Одними из моих любимых игр данного жанра являются «Super Mario Brothers» и «Super Meat Boy». Давайте попробуем создать нечто среднее между ними.

Самое — самое начало.

Внимание! Используем python ветки 2.х, с 3.х обнаружены проблемы запуска нижеописанных скриптов!

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

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

Запустив этот код, мы увидим окно, залитое зелененьким цветом.

марио на питоне код. image loader. марио на питоне код фото. марио на питоне код-image loader. картинка марио на питоне код. картинка image loader. pip install gym-super-mario-bros Copy PIP instructions
(Картинка кликабельна)

Ну что же, начало положено, идём дальше.

Уровень.

А как без него? Под словом «уровень» будем подразумевать ограниченную область виртуального двумерного пространства, заполненную всякой — всячиной, и по которой будет передвигаться наш персонаж.

Для построения уровня создадим двумерный массив m на n. Каждая ячейка (m,n) будет представлять из себя прямоугольник. Прямоугольник может в себе что-то содержать, а может и быть пустым. Мы в прямоугольниках будем рисовать платформы.

Добавим еще константы

Затем добавим объявление уровня в функцию main

И в основной цикл добавим следующее:

Т.е. Мы перебираем двумерный массив level, и, если находим символ «-», то по координатам (x * PLATFORM_WIDTH, y * PLATFORM_HEIGHT), где x,y — индекс в массиве level

Запустив, мы увидим следующее:

марио на питоне код. image loader. марио на питоне код фото. марио на питоне код-image loader. картинка марио на питоне код. картинка image loader. pip install gym-super-mario-bros Copy PIP instructions

Персонаж

Просто кубики на фоне — это очень скучно. Нам нужен наш персонаж, который будет бегать и прыгать по платформам.

Создаём класс нашего героя.

Для удобства, будем держать нашего персонажа в отдельном файле player.py

Что тут интересного?
Начнём с того, что мы создаём новый класс, наследуясь от класса pygame.sprite.Sprite, тем самым наследую все характеристики спрайта.
Cпрайт — это движущееся растровое изображение. Имеет ряд полезных методов и свойств.

self.rect = Rect(x, y, WIDTH, HEIGHT), в этой строчке мы создаем фактические границы нашего персонажа, прямоугольник, по которому мы будем не только перемещать героя, но и проверять его на столкновения. Но об этом чуть ниже.

Метод update(self, left, right)) используется для описания поведения объекта. Переопределяет родительский update(*args) → None. Может вызываться в группах спрайтов.

Метод draw(self, screen) используется для вывода персонажа на экран. Далее мы уберем этот метод и будем использовать более интересный способ отображения героя.

Добавим нашего героя в основную часть программы.

Перед определением уровня добавим определение героя и переменные его перемещения.

В проверку событий добавим следующее:

Т.е. Если нажали на клавишу «лево», то идём влево. Если отпустили — останавливаемся. Так же с кнопкой «право»

Само передвижение вызывается так: (добавляем после перерисовки фона и платформ)

марио на питоне код. image loader. марио на питоне код фото. марио на питоне код-image loader. картинка марио на питоне код. картинка image loader. pip install gym-super-mario-bros Copy PIP instructions

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

И в начало основного цикла добавим следующее:

Завис в воздухе

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

И так, работаем в файле player.py

Добавим еще констант

В метод _init_ добавляем строки:

Добавляем входной аргумент в метод update
def update(self, left, right, up):
И в начало метода добавляем:

И перед строчкой self.rect.x += self.xvel
Добавляем

И добавим в основную часть программы:
После строчки left = right = False
Добавим переменную up

В проверку событий добавим

И изменим вызов метода update, добавив новый аргумент up:
hero.update(left, right)
на

Здесь мы создали силу гравитации, которая будет тянуть нас вниз, постоянно наращивая скорость, если мы не стоим на земле, и прыгать в полете мы не умеем. А мы пока не можем твердо встать на что-то, поэтому на следующей анимации наш герой падает далеко за границы видимости.
марио на питоне код. image loader. марио на питоне код фото. марио на питоне код-image loader. картинка марио на питоне код. картинка image loader. pip install gym-super-mario-bros Copy PIP instructions

Встань обеими ногами на землю свою.

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

Создадим еще один файл blocks.py, и перенесем в него описание платформы.

Дальше создадим класс, наследуясь от pygame.sprite.Sprite

Тут нет ни чего нам уже не знакомого, идём дальше.

В основной файле произведем изменения, перед описанием массива level добавим

Группа спрайтов entities будем использовать для отображения всех элементов этой группы.
Массив platforms будем использовать для проверки на пересечение с платформой.

Т.е. создаём экземплр класса Platform, добавляем его в группу спрайтов entities и массив platforms. В entities, чтобы для каждого блока не писать логику отображения. В platforms добавили, чтобы потом проверить массив блоков на пересечение с игроком.

Дальше, весь код генерации уровня выносим из цикла.

И так же строчку
hero.draw(screen) # отображение
Заменим на

Запустив, мы увидим, что ни чего не изменилось. Верно. Ведь мы не проверяем нашего героя на столкновения. Начнём это исправлять.

Работаем в файле player.py

Удаляем метод draw, он нам больше не нужен. И добавляем новый метод collide

В этом методе происходит проверка на пересечение координат героя и платформ, если таковое имеется, то выше описанной логике происходит действие.

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

И не забудьте изменить его вызов в основном файле.

Т.е. передвинули героя вертикально, проверили на пересечение по вертикали, передвинули горизонтально, снова проверили на пересечение по горизонтали.

Вот, что получится, когда запустим.

марио на питоне код. image loader. марио на питоне код фото. марио на питоне код-image loader. картинка марио на питоне код. картинка image loader. pip install gym-super-mario-bros Copy PIP instructions

Фу[у]! Движущийся прямоугольник — не красиво!

Давайте немного приукрасим нашего МариоБоя.

Начнем с платформ. Для этого в файле blocks.py сделаем небольшие изменения.

Заменим заливку цветом на картинку, для этого строчку
self.image.fill(Color(PLATFORM_COLOR))
Заменим на

Мы загружаем картинку вместо сплошного цвета. Разумеется, файл «platform.png» должен находиться в папке «blocks», которая должна располагаться в каталоге с исходными кодами.

Вот, что получилось

марио на питоне код. image loader. марио на питоне код фото. марио на питоне код-image loader. картинка марио на питоне код. картинка image loader. pip install gym-super-mario-bros Copy PIP instructions

Сперва добавим в блок констант.

Тут, думаю, понятно, анимация разных действий героя.

Теперь добавим следующее в метод __init__

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

Осталось в нужный момент показать нужную анимацию.

Добавим смену анимаций в метод update.

Вуаля!
марио на питоне код. image loader. марио на питоне код фото. марио на питоне код-image loader. картинка марио на питоне код. картинка image loader. pip install gym-super-mario-bros Copy PIP instructions

Больше, нужно больше места

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

Для этого создадим класс Camera

Далее, добавим начальное конфигурирование камеры

Создадим экземпляр камеры, добавим перед основным циклом:

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

меньший прямоугольник, размером, идентичным размеру окна.

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

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

Заменим строчку
entities.draw(screen) # отображение
На

И перед ней добавим

Теперь можем изменить уровень.

Вот, собственно, и результат
марио на питоне код. image loader. марио на питоне код фото. марио на питоне код-image loader. картинка марио на питоне код. картинка image loader. pip install gym-super-mario-bros Copy PIP instructions

Результат можно скачать, ссылка на GitHub

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

upd pygame можно скачать отсюда, спасибо, Chris_Griffin за замечание
upd1 Вторая часть

Источник

Извлекаем уровни из Super Mario Bros с помощью Python

марио на питоне код. image loader. марио на питоне код фото. марио на питоне код-image loader. картинка марио на питоне код. картинка image loader. pip install gym-super-mario-bros Copy PIP instructions

Введение

Для нового проекта мне понадобилось извлечь данные уровней из классической видеоигры 1985 года Super Mario Bros (SMB). Если конкретнее, то я хотел извлечь фоновую графику каждого уровня игры без интерфейса, подвижных спрайтов и т.п.

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

На первом этапе проекта мы изучим язык ассемблера 6502 и написанный на Python эмулятор. Полный исходный код выложен здесь.

Анализ исходного кода

Реверс-инжиниринг любой программы намного проще, если есть её исходный код, а у нас имеются исходники SMB в виде 17 тысяч строк ассемблерного кода 6502 (процессора NES), опубликованных doppelganger. Поскольку Nintendo так и не выпустила официального релиза исходников, код был создан дизассемблированием машинного кода SMB, с мучительной расшифровкой значения каждой части, добавлением комментариев и осмысленных символьных названий.

Выполнив быстрый поиск по файлу, я нашёл нечто, похожее на нужные нам данные уровней:

Если вы незнакомы с ассемблером, то я объясню: всё это просто означает «вставить такой набор байтов в скомпилированную программу, а потом позволить другим частям программы ссылаться на него с помощью символа L_GroundArea6 ». Можно воспринимать этот фрагмент как массив, в котором каждый элемент является байтом.

марио на питоне код. image loader. марио на питоне код фото. марио на питоне код-image loader. картинка марио на питоне код. картинка image loader. pip install gym-super-mario-bros Copy PIP instructions

Сокращённый граф вызовов для AreaParserCore

Процедура выполняет запись в MetatileBuffer : раздел памяти длиной 13 байтов, представляющий собой один столбец блоков в уровне, каждый байт которого обозначает отдельный блок. Метатайл (metatile) — это блок 16×16, из которого составляются фоны игры SMB:

марио на питоне код. image loader. марио на питоне код фото. марио на питоне код-image loader. картинка марио на питоне код. картинка image loader. pip install gym-super-mario-bros Copy PIP instructions

Уровень с прямоугольниками, описанными вокруг метатайлов

Они называются метатайлами, потому что каждый состоит из четырёх тайлов размером 8×8 пикселей, но подробнее об этом ниже.

То, что декодер работает с заранее заданными объектами, объясняет маленький размер уровня: данные уровня должны ссылаться только на типы объектов и их расположение, например «расположить трубу в точке (20, 16), ряд блоков в точке (10, 5), …». Однако это означает, что для превращения сырых данных уровня в метатайлы требуется много кода.

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

py65emu

Если бы у нас был интерфейс между Python и языком ассемблера 6502, мы могли бы вызывать подпроцедуру AreaParserCore для каждого столбца уровня, а затем использовать более понятный Python для преобразования информации блоков в нужное изображение.

Тут на сцене появляется py65emu — лаконичный эмулятор 6502 с интерфейсом Python. Вот как в py65emu настраивается та же конфигурация памяти, что и в NES:

Стоит заметить, что это всего лишь эмулятор процессора NES: он не эмулирует другие аппаратные части, такие как PPU (Picture Processing Unit), поэтому его нельзя использовать для эмуляции всей игры. Однако его должно быть достаточно для вызова подпроцедуры парсинга, потому что она не использует никаких других аппаратных устройств, кроме ЦП и памяти.

Но перед этим нам нужно скомпилировать листинг на ассемблере в машинный код.

Как указано в исходном коде, ассемблер компилируется с помощью x816. x816 — это ассемблер 6502 под MS-DOS, используемый сообществом разработчиков самодельных игр (homebrew) для NES и ROM-хакеров. Он замечательно работает в DOSBox.

Наряду с ROM программы, который необходим для py65emu, ассемблер x816 создаёт символьный файл, привязывающий символы к расположению их в памяти в адресном пространстве ЦП. Вот фрагмент файла:

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

Подпроцедуры

Как сказано в представленном выше плане, мы хотим научиться вызывать подпроцедуру AreaParserCore из Python.

Чтобы понять механику подпроцедуры, давайте изучим короткую подпроцедуру и соответствующий ей вызов:

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

Вот код для выполнения подпроцедуры из Python:

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

Valgrind для NES?

На самом деле написать простую версию memcheck для py65emu очень легко:

Вот какие результаты даёт MMU в обёртке при вызове execute_subroutine(sym_file[‘AREAPARSERCORE’]) :

Uninitialized read! 0x0728 (BACKLOADINGFLAG):
Uninitialized read! 0x0742 (BACKGROUNDSCENERY):
Uninitialized read! 0x0741 (FOREGROUNDSCENERY):
Uninitialized read! 0x074e (AREATYPE):
Uninitialized read! 0x075f (WORLDNUMBER):
Uninitialized read! 0x0743 (CLOUDTYPEOVERRIDE):
Uninitialized read! 0x0727 (TERRAINCONTROL):
Uninitialized read! 0x0743 (CLOUDTYPEOVERRIDE):
Uninitialized read! 0x074e (AREATYPE):
.

марио на питоне код. image loader. марио на питоне код фото. марио на питоне код-image loader. картинка марио на питоне код. картинка image loader. pip install gym-super-mario-bros Copy PIP instructions

Очевидно, что metatile_data явно соответствует информации фона.

Графика метатайлов

(Чтобы посмотреть конечный результат, можно сразу перейти к разделу «Соединяем всё вместе».)

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

Чтобы понять, как рендерить каждый метатайл, нам сначала нужно поговорить о цветовых палитрах NES. PPU консоли NES способен в общем рендерить 64 разных цвета, однако чёрный цвет несколько раз дублируется (подробности см. в Nesdev):

марио на питоне код. image loader. марио на питоне код фото. марио на питоне код-image loader. картинка марио на питоне код. картинка image loader. pip install gym-super-mario-bros Copy PIP instructions

Каждый уровень Mario может использовать для фона только 10 из этих 64 цветов, разделённых на на 4 четырёхцветных палитры; первый цвет всегда одинаков. Вот четыре палитры для World 1-1:

марио на питоне код. image loader. марио на питоне код фото. марио на питоне код-image loader. картинка марио на питоне код. картинка image loader. pip install gym-super-mario-bros Copy PIP instructions

Давайте теперь рассмотрим пример номера метатайла, представленный в двоичном виде. Вот номер метатайла тайла камней с трещинами, который является землёй уровня World 1-1:

марио на питоне код. image loader. марио на питоне код фото. марио на питоне код-image loader. картинка марио на питоне код. картинка image loader. pip install gym-super-mario-bros Copy PIP instructions

Индекс палитры говорит нам, какой палитрой пользоваться при рендеринге метатайла (в нашем случае палитрой 1). Индекс палитры также является индексом двух следующих массивов:

.db >Palette0_MTiles, >Palette1_MTiles, >Palette2_MTiles, >Palette3_MTiles

Сочетание этих двух массивов даёт нам 16-битный адрес, который в нашем примере указывает на Palette1_Mtiles :

Четыре записи этой строки на самом деле являются идентификаторами тайлов: каждый метатайл состоит из четырёх тайлов размером 8×8 пикселей, выстроенных в следующем порядке — верхний левый, нижний левый, верхний правый и нижний правый. Эти идентификаторы передаются непосредственно в PPU консоли NES. Идентификатор ссылается на 16 байтов данных в CHR-ROM консоли, а каждая запись начинается с адреса 0x1000 + 16 * :

0x1000 + 16 * 0xb4: 0b01111111 0x1000 + 16 * 0xb5: 0b11011110
0x1001 + 16 * 0xb4: 0b10000000 0x1001 + 16 * 0xb5: 0b01100001
0x1002 + 16 * 0xb4: 0b10000000 0x1002 + 16 * 0xb5: 0b01100001
0x1003 + 16 * 0xb4: 0b10000000 0x1003 + 16 * 0xb5: 0b01100001
0x1004 + 16 * 0xb4: 0b10000000 0x1004 + 16 * 0xb5: 0b01110001
0x1005 + 16 * 0xb4: 0b10000000 0x1005 + 16 * 0xb5: 0b01011110
0x1006 + 16 * 0xb4: 0b10000000 0x1006 + 16 * 0xb5: 0b01111111
0x1007 + 16 * 0xb4: 0b10000000 0x1007 + 16 * 0xb5: 0b01100001
0x1008 + 16 * 0xb4: 0b10000000 0x1008 + 16 * 0xb5: 0b01100001
0x1009 + 16 * 0xb4: 0b01111111 0x1009 + 16 * 0xb5: 0b11011111
0x100a + 16 * 0xb4: 0b01111111 0x100a + 16 * 0xb5: 0b11011111
0x100b + 16 * 0xb4: 0b01111111 0x100b + 16 * 0xb5: 0b11011111
0x100c + 16 * 0xb4: 0b01111111 0x100c + 16 * 0xb5: 0b11011111
0x100d + 16 * 0xb4: 0b01111111 0x100d + 16 * 0xb5: 0b11111111
0x100e + 16 * 0xb4: 0b01111111 0x100e + 16 * 0xb5: 0b11000001
0x100f + 16 * 0xb4: 0b01111111 0x100f + 16 * 0xb5: 0b11011111

0x1000 + 16 * 0xb6: 0b10000000 0x1000 + 16 * 0xb7: 0b01100001
0x1001 + 16 * 0xb6: 0b10000000 0x1001 + 16 * 0xb7: 0b01100001
0x1002 + 16 * 0xb6: 0b11000000 0x1002 + 16 * 0xb7: 0b11000001
0x1003 + 16 * 0xb6: 0b11110000 0x1003 + 16 * 0xb7: 0b11000001
0x1004 + 16 * 0xb6: 0b10111111 0x1004 + 16 * 0xb7: 0b10000001
0x1005 + 16 * 0xb6: 0b10001111 0x1005 + 16 * 0xb7: 0b10000001
0x1006 + 16 * 0xb6: 0b10000001 0x1006 + 16 * 0xb7: 0b10000011
0x1007 + 16 * 0xb6: 0b01111110 0x1007 + 16 * 0xb7: 0b11111110
0x1008 + 16 * 0xb6: 0b01111111 0x1008 + 16 * 0xb7: 0b11011111
0x1009 + 16 * 0xb6: 0b01111111 0x1009 + 16 * 0xb7: 0b11011111
0x100a + 16 * 0xb6: 0b11111111 0x100a + 16 * 0xb7: 0b10111111
0x100b + 16 * 0xb6: 0b00111111 0x100b + 16 * 0xb7: 0b10111111
0x100c + 16 * 0xb6: 0b01001111 0x100c + 16 * 0xb7: 0b01111111
0x100d + 16 * 0xb6: 0b01110001 0x100d + 16 * 0xb7: 0b01111111
0x100e + 16 * 0xb6: 0b01111111 0x100e + 16 * 0xb7: 0b01111111
0x100f + 16 * 0xb6: 0b11111111 0x100f + 16 * 0xb7: 0b01111111

CHR-ROM — это фрагмент памяти read-only, к которому может получать доступ только PPU. Он отделён от PRG-ROM, в котором хранится код программы. Поэтому приведённые выше данные отсутствуют в исходном коде и их нужно получать из дампа ROM игры.

16 байта для каждого тайла составляют 2-битный тайл размером 8×8: первый бит — это первые 8 байтов, а второй — вторые 8 байтов:

21111111 13211112
12222222 23122223
12222222 23122223
12222222 23122223
12222222 23132223
12222222 23233332
12222222 23111113
12222222 23122223

12222222 23122223
12222222 23122223
33222222 31222223
11332222 31222223
12113333 12222223
12221113 12222223
12222223 12222233
23333332 13333332

Выполняем привязку этих данных к палитре 1:

марио на питоне код. image loader. марио на питоне код фото. марио на питоне код-image loader. картинка марио на питоне код. картинка image loader. pip install gym-super-mario-bros Copy PIP instructions

…и объединяем куски:

марио на питоне код. image loader. марио на питоне код фото. марио на питоне код-image loader. картинка марио на питоне код. картинка image loader. pip install gym-super-mario-bros Copy PIP instructions

Наконец мы получили отрендеренный тайл.

Соединяем всё вместе

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

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *