Днес ще изучим вътрешностите на играта Tetris, написана под платформата Ардуино и LED матрица.
Автор на този домашен продукт е AlexGyver, автор на едноименния канал в YouTube. Добре дошли в прекрасния свят на квадратни пиксели.
Да започнем с историята. Tetris е игра, в която фигури, състоящи се от 4 квадрата, падат отгоре надолу. В различни комбинации тези форми могат да се завъртат и да се преместват наляво и надясно. Целта на играта е да събере хоризонтални нива, които са изчистени и точките се присъждат на вас. Загубата се счита за момента, в който новата фигура няма къде да падне. Тетрис е измислен от съветския програмист Алексей Леонидович Пажитнов.
Оригиналната версия на Pascal се появи на 6 юни 1984 г. Оттогава Tetris измина дълъг път и беше пренесен на всички платформи, на които по принцип е възможно да се играят игри, както и на устройства, които изобщо не са предназначени за игри, като инженерен калкулатор, осцилоскоп и, няма да повярвате, поялник.
По брой продадени комерсиални версии Tetris превъзхожда всяка друга игра в историята на човечеството. Само за един Game Boy бяха продадени 35 милиона копия, да не говорим за преносимата Brick Game, която почти всички имаха наведнъж.
Ще започнем прилагането на тетрис върху ардуино и цветна матрица с анализ на „патерици“. Матрицата се състои от трицветни светодиоди за адреси. Проблемът с този тип матрица е, че е твърде готин. Цветът на всеки пиксел е кодиран с 24 бита, тоест 8 бита за всеки компонент: червен, зелен и син. Няма такъв тип данни за arduino, има следното - 32 бита.
Цветовете на всички светодиоди трябва да се съхраняват в RAM, тъй като ние ще ги променим. И че за 16 на 16 матрица имаме точно 1 KB заета динамична памет, а arduino nano има само 2 от тях.
Добавете още няколко библиотеки и започнете да пишете код, паметта ще свърши. Авторът по принцип не използва например arduino mega, където има повече памет. Целта е да направим играта специално на arduino nano, използвайки прости, стандартни и добре познати инструменти, но в същото време нестандартни подходи и „патерици“ и с тяхна помощ да постигнем най-оптималния код.
Първата „патерица“ ще бъде отказът да съхраняваме отделно в паметта позициите на фигурите и като цяло всичко, което се случва на екрана.Необходимо е да съхраним координатите на точките на фигурата за хранене и координатите на точките на вече изпуснатите фигури, тоест като максимум се нуждаем от още 1 масив, двуизмерен 16 на 16, и това е колкото 256 байта.
Вие и аз вече имаме масив от цветове за всички пиксели, нека го използваме. Всъщност, в допълнение към факта, че можем да поставим цветна точка върху матрицата, можем да измерим светлината на съществуваща точка, така че да работим с цветове.
Tetris започва с падащ блок, който се контролира от бутони и има 2 координати в матричната координатна система. Много е просто, изграждаме таймер, според който блокът ще падне. Това е авторската библиотека, която можете да четете в сайта.
За да обработва бутони, авторът също използва своята библиотека. Схемата за свързване на бутоните е нелепо проста: 4 бутона, 8 проводника.
Всяка стъпка от таймера, ние изчертаваме точка, пиксел под старата и изчертаваме старата точка в черно, тоест изключваме светодиода. С натискане на бутона правим същото, но с хоризонтална координата. Е, за приличие ще ограничим размера на матрицата, така че точката да не излиза извън полето.
Вижте, нищо сложно. Но това не е за дълго, защото е дошъл моментът да нарисуваме цифри. Ще работим по следния начин: ще запазим препратката към точката на доставка, за която вече сме писали, ще я наречем основната точка или основния блок. Основният блок се движи в матричната координатна система, вече сме направили това. Всички фигури на тетрис се състоят от 4 блока, поради което, между другото, той се нарича тетрис.
Съответно остава да приключим с добавянето на още 3 блока към основния блок. Нека запишем техните координати в координатната система на основния блок, така че основният блок да е винаги отдолу. Много е просто, вземете фигурата на обърната буква Т. Основният блок от дъното до центъра има координати 0,0 в координатната си система.
Горният блок е 0,1, десният е 1,1, а левият е -1,1.
Вземете буквата G. Долният блок е 0,0, следващият 0,1, следващият 0,2 и ръбът на буквата 1,2.
Ние записваме тези координации в масива в следната форма: {0.1, 0.2, 1.2} и пускаме масива във флаш памет, за да не губим динамична памет. Що се отнася до въртенето на фигурите. Невъзможно е да завъртите фигурите. Банално е много трудно да се обясни на микроконтролера как се прави това. За да направите това, трябва да зададете центъра на въртене, по някакъв начин да разложите фигурата на части и да потърсите нови координати за всяка част, като вземете предвид силна пикселация, което очевидно ще доведе до грешки и ще се окаже глупост. Проблемът се решава много просто, ще запазим в паметта всички 4 позиции за всички фигури и всички.
Всъщност сега остава да избираме произволно числото на цифрата и да я нарисуваме около падащия блок. Тук за всички 3 останали блока вземаме координатите от флаш паметта, превеждаме ги в глобалните координати на матрицата и включваме светодиодите. Между другото, цветът също е избран на случаен принцип от 6-те най-прости и светли цвята на rgb пространството. Ъгълът на завъртане на фигурата в началото на кръга също е зададен на случаен принцип и когато натиснете бутона нагоре, просто вземете следващия набор от координати, за да го нарисувате и завъртите по посока на часовниковата стрелка. Преместването на форма работи едно и също. Първо изтриваме фигурата в предишната позиция, тоест я нарисуваме в черно, след това в новата позиция нарисуваме текущия цвят на фигурата. При завъртане отново изтриваме старата позиция и просто рисуваме нова.
Фърмуерът може да бъде изтеглен на. Ще анализираме само същността. Нека започнем с проверка на лявата и дясната стена и долната част. Всичко е много просто с дъното, разглеждаме всяка стъпка на падането, достигнал ли е основната единица височина 0, това не е трудно, но всеки път, когато натискаме контролния бутон, трябва да видим дали крайната точка на фигурата докосва страничните стени на матрицата.
Ако докоснете, тогава не местете фигурата. Същото важи и за въртенето на фигурите. Например, ако новата позиция на фигурата се простира отвъд стените, тогава завъртането е забранено и тъй като всички фигури, които имаме, са с различни форми, тогава крайните блокове за тях са различни. Би било възможно да рисувате отделни крайни блокове за всяка фигура, за да опростите работата на микроконтролера, но нека се счита, че са го измислили за това.
Всичко е много просто. Но следващата задача е много по-интересна. Трябва да проверим за сблъсъци с блокове, които вече лежат отдолу.Ако имахме масив, съдържащ състоянието на всички клетки в полето, би било по-лесно, но ще използваме масив от цветове за пикселите на лентата, така че ще имаме най-готината „патерица“. Какъв е действителният проблем. Всичко изглежда просто, зелена фигура ще падне и всяка стъпка на падането, всяко изместване встрани и всеки опит за завъртане трябва да проверяват дали фигурата в новата позиция опира до вече лежащите фигури. Ако за всички блокове околният цвят е равен на черен или равен на цвета на фигурата, тогава допускаме движение в желаната посока. Това ще работи, докато формата под нас не е същия цвят като падащата форма. Това всъщност е „патерицата“: ще пребоядисаме падналата форма в различен цвят. Пребоядисайте незабележимо за очите, но забележимо за програмата. Всичко, което трябва да направите, е леко да увеличите яркостта на текущия цвят на формата и това е всичко.
Фигурата падна на дъното или друга фигура, яркостта й не се увеличи значително и в новия кръг падащите фигури вече няма да объркат цвета си със собствения си, те ще паднат върху него и точно както са фиксирани, леко добавяйки яркост.
Между другото, когато натиснете бутона надолу, фигурата се втурва надолу с висока скорост и заема своето място.
Нашият тетрис е оставен с последното докосване, а именно проверка и изчистване на запълнените нива хоризонтално. Тук всичко е просто. След като фиксираме фигурата в текущия кръг, се движим по линиите и сравняваме цветовете на пикселите с черно. Ако в целия ред няма нито един черен пиксел, тогава ще изчистим цялата линия.
Откритите линии се запълват с бяло, след това яркостта постепенно пада до нула и се получава анимацията. Освен това всички пиксели, като се започне от първия запълнен ред до върха, се изместват надолу и се изчиства броят на реда. Този процес се повтаря, докато нивата се запълнят. Проверяваме също дали сме стигнали до върха, което означава загуба. В този случай се показва акаунт, равен на броя на изчистените нива.
Сметката се показва на числа, които се съхраняват в паметта като набор от единици и нули, според които след това светодиодите се включват или изключват. Ето как изглежда Tetris, написан в адресната матрица. Благодаря за вниманието. Ще се видим скоро!
видео: