Idag kommer vi att studera insidan av Tetris-spelet skrivet under plattformen arduino och LED-matris.
Författaren till den här hemlagade produkten är AlexGyver, författaren till YouTube-kanalen med samma namn. Välkommen till den underbara världen med fyrkantiga pixlar.
Låt oss börja med berättelsen. Tetris är ett spel där siffror som består av fyra rutor faller från topp till botten. I olika kombinationer kan dessa former roteras och flyttas åt vänster och höger. Målet med spelet är att samla horisontella nivåer som rensas och poäng tilldelas dig. Att förlora anses vara det ögonblick då den nya figuren inte har någonstans att falla. Tetris uppfanns av den sovjetiska programmeraren Alexei Leonidovich Pazhitnov.
Den ursprungliga Pascal-versionen dök upp 6 juni 1984. Sedan dess har Tetris kommit långt och har portats till alla plattformar där det i allmänhet är möjligt att spela spel, såväl som till enheter som inte är avsedda för spel alls, till exempel en ingenjörskalkylator, oscilloskop och, du kommer inte tro, ett lödkolv.
Med antalet sålda kommersiella versioner är Tetris överlägset alla andra spel i mänsklighetens historia. För bara en Game Boy såldes 35 miljoner exemplar, för att inte tala om det bärbara Brick Game, som nästan alla hade på en gång.
Vi kommer att börja implementeringen av tetris på arduino och en färgmatris med analysen av "kryckor". Matrisen består av adressfärger med tre färger. Problemet med denna typ av matris är att den är för cool. Färgen på varje pixel är kodad med 24 bitar, det vill säga 8 bitar för varje komponent: röd, grön och blå. Det finns ingen sådan typ av data om arduino, det finns följande - 32 bitar.
Färgerna på alla lysdioder bör lagras i RAM, eftersom vi kommer att ändra dem. Och dessutom har vi för en matris på 16 med 16 exakt 1 kB med ockuperat dynamiskt minne, och arduino nano har bara 2 av dem.
Lägg till några bibliotek till och börja skriva kod, minnet slutar. Författaren använder till exempel inte arduino mega, där det finns mer minne. Målet är att göra spelet på arduino nano med enkla, standardiserade och välkända verktyg, men samtidigt icke-standardiserade tillvägagångssätt och "kryckor" och med deras hjälp uppnå den mest optimala koden.
Den första "kryckan" kommer att vara vägran att separat lagra i minnet figurernas positioner, och i allmänhet allt som händer på skärmen.Vi måste lagra koordinaterna för punkterna i matningsfiguren och koordinaterna för punkterna på de redan tappade siffrorna, det vill säga, maximalt behöver vi ytterligare en grupp, tvådimensionell 16 med 16, och det är så mycket som 256 byte.
Du och jag har redan en mängd färger för alla pixlar, låt oss använda den. Förutom det faktum att vi kan sätta en färgad prick på matrisen, kan vi mäta ljuset på en befintlig punkt så att vi arbetar med färger.
Tetris börjar med ett fallande block, som styrs av knappar och har 2 koordinater i matriskoordinatsystemet. Det är väldigt enkelt, vi bygger en timer, enligt vilken blocket kommer att falla. Detta är författarens bibliotek, du kan läsa på webbplatsen.
För att bearbeta knappar använder författaren också sitt bibliotek. Anslutningsschemat för knapparna är löjligt enkelt: 4 knappar, 8 ledningar.
Varje steg i timern ritar vi en punkt en pixel under den gamla och drar den gamla punkten i svart, det vill säga stänga av lysdioden. Genom att klicka på knappen gör vi samma sak, men med en horisontell koordinat. Tja, för anständighet kommer vi att begränsa storleken på matrisen så att punkten inte går längre än fältet.
Inget komplicerat. Men detta är inte så länge eftersom det är dags att rita siffror. Vi kommer att arbeta på följande sätt: vi kommer att behålla referensen till leveranspunkten, som vi redan har skrivit, vi kommer att kalla det huvudpunkten eller huvudblocket. Huvudblocket rör sig i matriskoordinatsystemet, vi har redan gjort det. Alla figurer av Tetris består av 4 block, varför det förresten kallas Tetris.
Följaktligen återstår det att avsluta lägga till ytterligare 3 block till huvudblocket. Låt oss skriva deras koordinater i koordinatsystemet i huvudblocket, så att huvudblocket alltid är under. Det är väldigt enkelt, ta figuren av det inverterade bokstaven T. Huvudblocket från botten till centrum har koordinater 0,0 i sitt koordinatsystem.
Det övre blocket är 0,1, det högra är 1,1 och det vänstra -1,1.
Ta bokstaven G. Det nedre blocket är 0,0, nästa 0,1, nästa 0,2 och kanten på bokstaven 1,2.
Vi skriver dessa koordinater i matrisen i följande form: {0,1, 0,2, 1,2} och släpper matrisen i flashminnet för att inte slösa bort dynamiskt minne. När det gäller figurernas rotation. Det är omöjligt att rotera siffrorna. Det är känsligt, det är mycket svårt att förklara för mikrokontrollern hur man gör detta. För att göra detta måste du ställa in rotationscentret, på något sätt sönderdela figuren i delar och leta efter nya koordinater för varje del, med hänsyn till stark pixelering, vilket uppenbarligen kommer att leda till fel och det kommer att bli nonsens. Problemet löses väldigt enkelt, vi kommer att hålla i minnet alla fyra positionerna för alla figurer och alla.
Det återstår faktiskt att slumpmässigt välja siffranummer och rita det runt det fallande blocket. För alla tre kvarvarande blocken tar vi koordinaterna från flashminnet, översätter dem till matrisens globala koordinater och tänder lysdioderna. Förresten, färgen väljs också slumpmässigt från de 6 mest enkla och ljusa färgerna i rgb-rymden. Figurs rotationsvinkel i början av omgången ställs också slumpmässigt in, och när du trycker på knappen upp tar du bara nästa uppsättning koordinater för att rita och rotera medurs. Att flytta en form fungerar likadant. Först raderar vi figuren vid föregående position, det vill säga, rita den i svart, sedan i den nya positionen rita figurens nuvarande färg. När vi vänder igen raderar vi den gamla positionen och ritar bara en ny.
Firmware kan laddas ner på. Vi kommer bara att analysera essensen. Låt oss börja med att kontrollera vänster och höger vägg och botten. Allt är väldigt enkelt med botten, vi tittar på varje steg på hösten, har basenheten nådd en höjd av 0, detta är inte svårt, men varje gång vi trycker på kontrollknappen måste vi se om figurens extrema punkt rörde matrisens sidoväggar.
Om du rör vid den, flytta inte figuren. Detsamma gäller för figurernas rotation. Till exempel, om figurens nya position sträcker sig bortom väggarna, är rotationen förbjuden, och eftersom alla former vi har är av olika former, så är de extrema blocken för dem alla olika. Det skulle vara möjligt att måla enskilda extrema block för varje figur för att förenkla mikrokontrollerns arbete, men låt det övervägas att de uppfann det för detta.
Allt är väldigt enkelt. Men nästa uppgift är mycket mer intressant. Vi måste kontrollera för kollisioner med block som redan ligger under.Om vi hade en matris som innehöll tillståndet för alla celler i fältet, skulle det vara lättare, men vi kommer att använda en matris med färger för pixlarna på bandet, så vi kommer att ha den coolaste "kryckan". Vad är det faktiska problemet. Allt verkar vara enkelt, en grön figur kommer att falla, och varje steg på hösten, varje skift åt sidan och varje försök att vända bör kontrollera om figuren i den nya positionen vilar på de redan liggande figurerna. Om den omgivande färgen för alla block är lika med svart eller lika med figurens färg, tillåter vi rörelse i önskad riktning. Detta kommer att fungera tills formen under oss har samma färg som den fallande formen. Det är faktiskt "kryckan": vi kommer att måla om den fallna formen i en annan färg. Måla omöjligt omöjligt för ögonen, men märks för programmet. Allt du behöver göra är att öka ljusstyrkan i formens nuvarande färg och det är allt.
Figuren föll på botten eller en annan figur, dess ljusstyrka ökade inte märkbart, och i den nya omgången kommer de fallande figurerna inte längre att förvirra dess färg med sin egen, de kommer att falla på den och lika fixerade, något lägga till ljusstyrka.
Förresten, när du trycker ner knappen, rusar figuren ner i hög hastighet och tar sin plats.
Vår Tetris sitter kvar med den sista handen, nämligen att kontrollera och rensa de fyllda nivåerna horisontellt. Allt är enkelt här. Efter att ha fixat figuren i den aktuella omgången, flyttar vi oss längs linjerna och jämför bilderna på pixlarna med svart. Om det inte finns en enda svart pixel i hela linjen kommer vi att rensa hela linjen.
De detekterade linjerna är fyllda med vitt, sedan sjunker ljusstyrkan gradvis till noll och animeringen erhålls. Vidare förskjuts alla pixlar, från den första fyllda linjen till toppen, nedåt och antalet rader som har raderats. Denna process upprepas tills det inte finns några slutförda nivåer. Vi kontrollerar också om vi har nått toppen, vilket innebär att förlora. I detta fall visas ett konto lika med antalet rensade nivåer.
Kontot visas i siffror som lagras i minnet som en uppsättning av nollor och nollor, med vilka lysdioderna sedan slås på eller av. Så ser Tetris skriven i adressmatrisen ut. Tack för din uppmärksamhet. Vi ses snart!
videor: