Játék a mikrokontrollereden
Szeretnél játékot fejleszteni, de úgy, hogy az azt futtató hadvert is te magad állítod össze mellé? Mutatjuk, miként vághatsz bele.
Amikor a játékfejlesztés szóba kerül a legtöbb felhasználó hajlamos a szemkápráztató grafikájú, több száz ember megfeszített munkájával megvalósuló AAA-s projektekre gondolni, azonban egy ilyen ambiciózus terv megvalósításába nem érdemes egyedül belevágnod, hisz elég hamar eljutnál arra a pontra, ahol további emberek segítségére lenne már szükséged. Azonban elég, ha első alkotásként egy megvalósítható célt tűzöl ki magad elé, mondjuk egy egyszerű kis 2D-s platformert, vagy egy könnyedén összeállítható ügyességi játékot, ha pedig kellően elszánt vagy, még a futtatható hardvert is saját kezűleg állíthatod össze.
Az Arduino mikrokontroller felülete pedig tökéletesen alkalmas terepet kínál arra, hogy egy saját retrókonzolt építs, melynek felületén egyedi játékod fut majd. Cikkünkben összegyűjtöttük, mi mindenre lesz szükséged ahhoz, hogy az első alkotásod a mikrovezérlőd segítségével életre keljen.
Hardveres alapok
A játékod megvalósításához mindössze két kiemelten fontos komponensre lesz szükséged, egy LCD kijelzőre, valamint egy potenciométerre - összekapcsolásukhoz pedig természetesen némi kábel sem jelent hátrányt. Mi a kiegészítők terén a Grove Starter Kit-ben található eszközöket vetettük be, a programozáshoz pedig egy Genuino 101-es mikrovezérlőt alkalmaztunk. Az Arduinora csatlakoztatott shield, valamint a beviteli eszköz azonnal a rendelkezésedre áll, azonban a kijelző használatához még telepítened kell a megfelelő csomagokat. Az eszközöd számítógépes csatlakoztatását követően navigálj a menüsáv Vázlat felirata alatt található Könyvtár tartalmazása opcióra, majd klikkelj a Könyvtárak kezelése lehetőségre. A megnyíló felület kereső sávjába gépeld be a Grove LCD kulcsszavakat, majd a megjelenő könyvtár Telepítés gombjára kattintva már indul is a szükséges komponensek társítása. Ha végzett az installer, nincs más teendőd, mint belevágnod a kódolásba.
Egyedi karakterek
Ahhoz, hogy az egész játék-koncepciód megvalósítása működőképes legyen ezen az LCD kijelzőn szükséged lesz arra, hogy egyedi karaktereket is kirajzoljon a képernyőd. Erre szerencsére a Grove LCD kijelző már az előre elkészített kódok között is mutat példát, mely tökéletes alapot kínál majd projekted elindításához. A szükséges .ino fájl felkutatásához az Arduino fejlesztői környezetében válaszd a Fájl menü Példák lehetőségét a megjelenő listában pedig keresd ki a Grove - LCD könyvtárhoz tartozó almappát és kattints a CustomCharacter.ino állományra. A megnyíló felületen láthatsz több példát is arra, miként készítheted el az egyedi karaktereket.
A cikkünkben bemutatott játékban autód segítségével kerülgetheted a megjelenő akadályokat, ehhez azonban szükséged lesz egy autót ábrázoló karakterre is. Rögtön az rgb_lcd lcd; sor után helyezz el egy byte car[8] ={}; kódrészletet, melynek belsejében a 0b00000, sor nyolcszori megadásával készítheted el a kijelző 8x5-ös felbontású egységeit, rajzod elkészítéséhez pedig mindössze annyi a teendőd, hogy a megfelelő sorokban a 0b után található 0 értékeket 1-re cseréld. Ezzel a módszerrel könnyedén készíthetsz egy pixeles autót, ha a négyes és ötös sorban mindent egyesre változtatsz, a hármas és hatos sorokban pedig az első és a negyedik nullát módosítod. Karaktered készen áll, már csak azt kell megvalósítanod, hogy ezt a byte-sorozatot az Arduino is képes legyen értelmezni. Ehhez a setup függvényen belül az lcd.createChar(2, car); kifejezést helyezd el a speciális karaktereket létrehozó utasítások között (semmi esetre se a 0 vagy 1 értékhez kapcsold az új karaktert, mert a fordító könnyedén problémázni kezd a felüldefiniálások miatt). A mintaprogram #endif sora alatt a setup()-ban található részt törölheted, ezekre a kiíratásokra nem lesz szükséged a továbbiakban. Hasonlóan járj el a loop()-ban is, hisz itt is teljesen új funkciókat valósítunk meg . Amint ezzel végeztél, készíts - még a függvényen kívül - egy int sensorReading=0; változót, melyen keresztül az A0 portra kötött beviteli eszközöd adatait ültetheted át a szoftveredbe, ezzel tudod majd fel-le mozgatni a kis kocsit. Ezen kívül hozz még létre egy int updown=0; nevű változót is, melynek segítségével az autó aktuális állását adhatod meg az előzőleg beolvasott adatok alapján. A loop()-on belül aztán használd a sensorReading = analogRead(A0); kódot, mely minden körben ellenőrzi az aktuális értéket, amit aztán az updown = map(sensorReading, 0, 1023, 0, 1); parancs segítségével 0-ra vagy 1-re konvertál attól függően, hogy a potenciométer melyik végéhez áll közelebb az épp olvasott érték. Ha ezzel megvagy térj vissza a globális változókhoz, hisz azt is meg kell adnod a programnak, hogy a megjelenítő hányadik pozíciójában áll éppen a kurzorunk, vagyis hova rajzolja ki a frissen kreált karaktereket.
Ehhez készíts egy int positionCounter = 0; változót, majd a loop()-ba visszatérve a lcd.setCursor(positionCounter, updown); segítségével állítsd be a kurzort az első képkockára és az lcd.write(2); utasítással rajzold ki a kisautót. Ha sikerült, adj némi késleltetést a felületnek amennyi ideig szeretnénk, ha egy képkocka tartana - a delay(1000); függvénnyel egy másodperces késleltetést kapsz -, majd az lcd.clear(); parancs segítségével töröld a kijelző tartalmát, a positionCounter++; utasítással pedig növelj kocsid aktuális pozícióján. Ezzel már autód képes arra, hogy a potenciométert tekerve fel-le mozogjon a képernyőn és eljut a kijelző széléig, ám ott szemrebbenés nélkül tovább halad a semmibe. Ha szeretnéd elérni, hogy a megjelenítő szélére érve ismét a képernyő bal oldalán tűnjön fel járműved, helyezz el a loopon belül egy if ágat melynek feltételében a positionCounter<15 kifejezéssel ellenőrizd, hogy pozíciód a kijelző széléhez képest hol helyezkedik el. Amennyiben még nem érte el az utolsó képkockát, úgy a positionCounter++; segítségével növeld az értékét, ha viszont már odaért (tehát az else ágon) a positionCounter=0; szöveget helyezd az else-ágba.
Akadály előttünk
Autód tehát már képes végighaladni a képernyőn, így jöhet egy kis akadály, hogy azért mégis valami játékmechanikai elemmel is feldobd a környezetet. Hogy új figurát ne kelljen rajzolnod használd a mintaprogram armsUp karakterét, melyet az alapértelmezett program a 4-es számhoz társított. A loop elején tehát az lcd.setCursor(6, 1); lcd.write(4); parancs segítségével készíts egy akadályt a 7-es alsó, az lcd.setCursor(10, 0); parancs segítségével pedig a 11-es felső képkockára, melyek a kód feltöltését követően már meg is jelennek képernyőn. Ezek után a statikus akadályokra készíts egy ellenőrző függvényt egy if ((positionCounter==6 and updown==1) or (positionCounter==10 and updown==0)) formájában, mely lefutása esetén egy kis késleltetést követően hívja meg a gameOver(); nevű függvényt.
Már csak annyi teendőd maradt, hogy elkészítsd ezt a függvényt, ehhez pedig a loop()-ot lezáró kapcsos zárójel után üss egy entert és gépeld be a void gameOver(){} utasítást, majd a függvényen belül töröld le a képernyőt (lcd.clear();), irass ki egy Game Over feliratot (lcd.write("Game Over");), várj néhány másodpercet (delay(6000);) és végezetül állítsd az alapértelmezett, 0 kezdőpozícióba a positionCounter-t (positionCounter=0;). Ezzel pedig kész is a hordozható játékgéped prototípusa.