- PVSM.RU - https://www.pvsm.ru -
VM, написанная неуверенной рукой гуманитария в среде программирования Arduino с использованием быдлокода и велосипедов. А еще есть компилятор для нее из си-подобного языка, написанный на JavaScript теми же методами. Да. Уже можно спешить в комментарии, бросать камни. Ну а тех, кому все же интересно, приглашаю продолжить чтение.
В общем-то мою поделку уже немного осветил уважаемый tormozedison [1] вот тут [2]. Но на тот момент был скорее сферический в вакууме прототип. А сейчас у меня появилось устройство работы RomanS, которое он любезно предоставил мне для опытов совершенно безвозмездно. Зовется сие устройство ESPboy. От остальных поделок оно отличается компактностью и слотом расширения, использующим микросхему MCP23017. Тут [3] о нем можно узнать больше.
Если кому интересно, как мне вообще пришла в голову такая странная мысль, как виртуальная машина на микроконтроллере, то можно прочитать под спойлером.
Начал я с написания игры под ардуино уно, куда же без нее. Тогда она у меня была единственная, и я очень волновался за ее работоспособность. Старался прошивать как можно реже. Но путь граблей идется маленькими шажками. Каждая небольшая правка кода заставляла прошивать снова и снова. И я решил написать стековую виртуальную машину. Как-никак на борту огромные два килобайта оперативной памяти для байт кода и данных. Но какой же она была медленной, а памяти почему то постоянно не хватало. Наверное, все дело в том, что все мои велосипеды были с квадратными колесами и медленно ехали. Тогда я решил написать эмулятор chip-8 на только что пришедшую из Китая ардуино мега. Конечно же, потом я хотел написать для нее же еще и эмулятор геймбоя, первой плейстейшн и какого-нибудь суперкомпьютера попроще. В результате я понял главное. Виртуальная машина chip-8 была очень простой, чрезмерно простой. Настолько, что при написании своих игр для умножения или деления приходилось писать отдельную медленную подпрограмму. А значит нужно написать свою VM, избавившись от фатального недостатка. В это время еще и несколько esp8266 приехало, со своими космическими 160MHz.
Если вам кажется, что виртуальная машина это пустая трата ресурсов, то я еще и переписал под нее свой эмулятор chip-8. Получилась виртуальная машина в виртуальной машине на микроконтроллере. Наверное, можно пойти дальше, и написать машину тьюринга на chip-8.
Виртуальная машина содержит 16 регистров по 16 бит, нулевой регистр является указателем стека. Каждая инструкция двухбайтовая, некоторые инструкции содержат после себя два байта данных. Адресуемая память 64KB. В случае ESP8266 доступно 20KB. Возможна загрузка программы из SPIFFS и UART. При желании можно добавить загрузка с карты памяти или через WiFi. Кроме обычных арифметических инструкций и инструкций перемещения данных, есть отдельные инструкции для работы со спрайтами, экраном и звуком. Размер экрана 128 на 128 пикселей. При 16 цветах на точку экран занимает 8KB памяти, еще столько же занимает буфер для рисования спрайтов и частиц. Хоть используемая мной библиотека TFT_eSPI способна обновлять экран более 60 раз в секунду, пришлось ограничиться 20 кадрами в секунду. Иначе не хватало процессорного времени для виртуальной машины. Можно рисовать тайлы и 32 спрайта размером до 128х128 пикселей с возможностью вращения и зеркалирования. Для экономии памяти можно использовать однобитные изображения или RLE сжатие. Присутствует упрощенная физика: обнаружение столкновений спрайтов со спрайтами и тайлами, разрешение столкновений, гравитация. Экран обновляется построчно, только если в строке произошло изменение пикселей. Скорость VM в зависимости от того, сколько строк отрисовывается в кадре, варьируется от 100 тысяч до 900 тысяч операций в секунду. Можно использовать разные цветные экраны, есть софтовое растягивание изображения до нужных пропорций.
Некоторые игры, из написанных мной, можно посмотреть тут [4].
Одновременно с VM для ESP8266 я писал эмулятор на JavaScript для браузера. Что бы не редактировать байт-код вручную, был добавлен простенький ассемблер, основанный на моем опыте с ассемблером для MOS6502. Затем я решил добавить язык более высокого уровня. Все же моей основной задачей было быстрое написание простых игр, а не долгая отладка ассемблерного кода. Мне показалось, что написать свой компилятор будет проще, чем добавить LLVM. И я написал его на JavaScript, так как знаю его не так плохо, как другие языки. На данный момент ему далеко до поддержки стандартов C и при компиляции можно легко столкнуться с непонятной ошибкой в непонятном месте. Зато он быстр, ведь он занимает меньше 2000 строк.
А теперь к вопросу, зачем я вообще все это здесь написал. Уже сейчас можно писать и запускать игры. Однако до совершенства еще далеко. Если кто захотел мне помочь в доработке ESP LGE, или написать свою собственную игру, то я буду очень рад. Если Вам моя идея показалась интересной, и Вы хотите узнать больше, то я с радостью отвечу на интересующие вопросы. Предупреждаю, код для Arduino довольно сложно читать. Отчасти из-за того, что я самоучка. Отчасти из-за того, что я попытался уменьшить количество вызовов функций, для увеличения скорости работы. В результате многие функции содержат огромные портянки кода. Так что не подпускайте к экрану беременных и детей. Постепенно я постараюсь это исправить и улучшить читаемость.
А для тех, кто дочитал, пример игры. Занимает меньше ста строк и меньше 1KB в скомпилированном виде.
int stickCount;
char key,previouseKey,takenSticks;
void redraw(){
int i;
//выбираем красный цвет
setcolor(2);
//рисуем видимые палочки
for(i = 0; i < stickCount; i++)
line(22 + i * 6, 74, 22 + i * 6, 84);
//выбираем серый цвет
setcolor(11);
//рисуем выброшенные
for(i = stickCount; i < 15; i++)
line(22 + i * 6, 74, 22 + i * 6, 84);
//возвращаем белый цвет как основной
setcolor(1);
//ждем перерисовки экрана
delayredraw();
}
void playersMove(){
//если код кнопки равен предыдущему, значит она еще не отпущена. Ждем
while(key == previouseKey){
key = getkey();
}
while(key != KEY_LEFT && key != KEY_DOWN && key != KEY_RIGHT){
key = getkey();
}
if(key & KEY_LEFT){
takenSticks = 1;
}else if(key & KEY_DOWN){
takenSticks = 2;
}else{
takenSticks = 3;
}
printf("%d, ", takenSticks);
stickCount -= takenSticks;
previouseKey = key;
}
void computersMove(){
if(stickCount % 4){
//компьютер реализует выигрышную стратегию, если выпала возможность
takenSticks = stickCount % 4;
}else{
//компьютер ждет возможности реализовать выигрышную стратегию
takenSticks = 1 + random(1);
}
stickCount -= takenSticks;
printf("%d, ", takenSticks);
}
void game(){
//инициализация
stickCount = 15;
clearscreen();
//переводим каретку на восьмой символ нулевой строки
gotoxy(8,0);
puts("Баше");
gotoxy(2,1);
puts("Возьмите 1,2 или 3 палочки. Проигрывает тот, кому нечего брать. Управление:n");
//коды 27,25 и 26 соответствуют стрелкам
printf(" %c 1 %c 2 %c 3", 27, 25, 26);
gotoxy(0,12);
redraw();
while(1){
playersMove();
if(stickCount <= 0){
gotoxy(3,8);
puts("Вы выиграли");
return;
}
redraw();
computersMove();
redraw();
if(stickCount <= 0){
gotoxy(3,8);
puts("Компьютер выиграл");
return;
}
}
}
void main(){
while(1){
game();
//ждем секунду
settimer(1,1000);
while(gettimer(1)){}
while(getkey() == 0){}
previouseKey = key;
}
}
Можно сразу и протестировать [5]. Перейдите по ссылке, затем нажмите compile, затем run. Если хотите узнать больше о возможностях IDE можно почитать туториал [6]. Спасибо за внимание.
Автор: corax89
Источник [7]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/diy-ili-sdelaj-sam/323634
Ссылки в тексте:
[1] tormozedison: https://habr.com/ru/users/tormozedison/
[2] тут: https://habr.com/ru/post/443918/
[3] Тут: https://hackaday.io/project/164830-espboy-beyond-the-games-platform-with-wifi
[4] тут: https://corax89.github.io/esp8266Game/gamelist/index.html
[5] протестировать: https://corax89.github.io/esp8266Game/index.html?src=6ca18ff8b2718c059d07c93374145d36
[6] туториал: https://corax89.github.io/esp8266Game/user_guide/index.html
[7] Источник: https://habr.com/ru/post/459714/?utm_campaign=459714&utm_source=habrahabr&utm_medium=rss
Нажмите здесь для печати.