Átfogó útmutatás a lángokról (vagy hogyan lehet játékot játszani a csapkodással)

Bevezetés

Üdv mindenkinek! Luan vagyok, és üdvözlöm ezt az első átfogó oktatóvideót.

A Flame egy minimalista Flutter játékmotor, amely néhány modult kínál a vászon alapú játék készítéséhez.

Ebben az oktatóanyagban egy nagyon egyszerű játékot fogunk létrehozni, ahol a dobozok esnek, és a cél az, hogy elpusztítsák őket, mielőtt elérnék a képernyő alját.

Így fog kinézni a játék

Ön is ellenőrizheti a játékot, hogy megnézze, mi az APK telepítésének, vagy a Play Áruházból történő telepítésének a feladata.

Ez lehetővé teszi számunkra, hogy lefedjük a keret által biztosított összes funkciót, és megmutatjuk, hogy miként hajthatjuk végre a legalapvetőbb műveleteket: megjelenítést, ízeket, hangot, szöveget, animációkat és így tovább.

De miért választottuk ezt a játékot? Eltekintve attól, hogy nagyon egyszerű, mégis komplett a keret feltárására, az egyik jó tényező az, hogy megvannak erőforrásai ennek elvégzéséhez!

E játékhoz a következő erőforrásokat fogjuk felhasználni: egy láda sprite, egy robbanás sprite (animációval), egy robbanás hang, egy "miss" hang (mert ha a doboz nem érkezik meg), háttérzene és egy szép betűtípus a pontszám megjelenítéséhez.

Nehéz megtalálni az interneten kereskedelemben elérhető jó forrásokat, de mindent (a betűtípus kivételével) megtaláltunk ezen a fantasztikus oldalon. Nagyon nagyszerűek, feltétlenül ajánlottak.

Ami a mai napig, a sprite lapok nem támogatottak, tehát először az összes erőforrást át kell alakítanunk megfelelő formátumra. Emellett konvertálnunk kell az összes audio fájlt MP3-hoz (az OGG is támogatott; a WAV nem). Mivel ez kész, letölthet egy csomagot mindazzal, amire itt erőforrás-ból szükség lesz.

Érdemes megemlíteni, hogy az itt leírtak teljes mértékben működőképes teljes verziójaként a GitHub-on elkötelezettek. Bármikor megnézheti, ha kétségei vannak. Ugyancsak a példát e pontos lépések alapján hozták létre, és pillanatfelvételekkel gyakran elvégezték a kötelezettségvállalásokat. Az oktatóanyag egészében összekapcsolom azokat a konkrét kötelezettségvállalásokat, amelyek előremozgatják a lerakatot a kérdéses színpadra. Ez lehetővé teszi ellenőrző pontok készítését és a régi kód böngészését, hogy bármi olyat lássa, amely nem volt tiszta.

Egy utolsó dolog; itt megtekintheti a Láng teljes dokumentációját. Ha bármilyen kérdése, javaslata, hibája van, nyugodtan nyisson meg egy problémát, vagy vegye fel a kapcsolatot velem.

Ezen kívül a Flutter és a Dart telepítésére is szükség lesz. Ha megfelel neked, akkor rendelkezhet IntelliJ IDEA-val is, amely nagyon jó hely a kód írásához. A cucc telepítéséhez megnézheti a rengeteg oktatóprogramot, mint például ez.

alapjai

Tehát egyelőre azt feltételezem, hogy minden készen áll. Tehát csak futtassa a következőket, és nyissa ki!

Az első dolog, amit meg kell tennie, a lángfüggőség hozzáadása. Nyissa meg a pubspec.yaml fájlt, és ellenőrizze, hogy a függőségi kulcs felsorolja-e a lángot:

Itt a legfrissebb, 0.5.0 verziót használjuk, de választhat egy újat is, ha rendelkezésre áll.

Most a main.dart fájljában már sok minden található: egy „fő” módszer, amelyet meg kell tartani; és egy későbbi runApp módszer hívás. Ez a módszer az alkalmazások képernyőinek elkészítéséhez használt widgeteket és más Flutter összetevőket veszi át. Mivel játékot készítünk, mindent rajzolunk a vászonra, és ezeket az összetevőket nem használjuk; szóval szedd ki mindezt.

Fő módszerünk most üres, és két dolgot fogunk hozzáadni; először néhány konfiguráció:

A flame.dart import hozzáférést biztosít a Flame statikus osztályhoz, amely csak számos más hasznos osztály tulajdonosa. Ezt később többet fogjuk használni. Jelenleg két módszert hívunk meg ebben a Láng osztályban.

Az utolsó magától értetődő, letiltja a naplózást az audiolejátszók beépülő moduljából. Most hamarosan hangot adunk a játékhoz, és ha nem működik, akkor itt kell megjegyzést fűznie a hibaelhárításhoz. De végül odaérünk.

Az első sor összetettebb. Alapvetően a Flutter néhány alapvető funkciója hiányzik, mivel nem a runApp módszert használjuk. Ez az enableEvents hívás egy kis megoldást jelent annak érdekében, hogy minden elemhez nélkülözhetetlen elemeket szerezzen a widgetek használata nélkül.

Végül el kell kezdenünk a játékunkat. Ennek érdekében még egy osztályt hozzáadunk az import listához, a Game osztályt. Ez az osztály minden játék létrehozásához szükséges absztrakciót nyújt: játék hurok. Alosztályba kell sorolni úgy, hogy minden játék alapját végre kell hajtania: egy frissítési módszert, amelyet minden alkalommal meghívnak, és amely az utolsó frissítés óta eltelt időt igénybe veszi, valamint egy megjelenítési módszert, amelynek tudnia kell, hogyan kell felhívni a a játék jelenlegi állapota. A hurok belső működését a játék osztály hagyja megoldani (természetesen átnézheti, ez nagyon egyszerű), és csak ki kell hívnia az indulást, nos, induljon.

Ellenőrzőpont: 599f809

Jelenleg a vakolat nem tesz semmit, tehát ha elindítja, akkor futnia kell, de fekete képernyőt kell adnia. Édes! Tehát kapott egy funkcionális alkalmazást widget és szöcske nélkül, valamint egy üres vászont, hogy elkezdhessük rajzolni az alkalmazást.

Megjelenítési formák

És hogyan történik a rajz? Rajzoljunk egy egyszerű téglalapot a működéshez. Adja hozzá a következőt a megjelenítési módszerhez:

Itt, amint láthatja, egy téglalapot definiálunk a képernyő pozíciói alapján. A következő kép bemutatja, hogyan irányulnak a szabályok. Alapvetően az eredet a bal felső sarokban van, és a tengely jobbra és lefelé növekszik.

Azt is vegye figyelembe, hogy a legtöbb rajzolási módszer festéket vesz igénybe. A Festék nem csak egyszínű, de lehet Degradè vagy más textúra is. Általában egyszínűre vágyik, vagy egyenesen a Sprite-ra. Tehát beállítottuk a színt a festék belsejében egy színpéldányra.

A szín egyetlen ARGB színt jelent; olyan egész számmal hozza létre, amelyet hexán írhat le az egyszerűbb olvasás érdekében; A formátumban van (alfa, átlátszó, általában 0xFF), majd két számjegy R, G és B számára ebben a sorrendben.

Van is nevezett színek gyűjteménye; az anyagcsomagban van. Vigyázzon, ha csak a Színek modult importálja, hogy ne véletlenül használjon valami mást az anyagcsomagból.

Szóval, remek, most van egy négyzetünk!

Ellenőrzőpont: 4eff3bf

Azt is tudjuk, hogyan működnek az uralkodók, de nem tudjuk a képernyő méretét! Hogyan rajzolhatunk valamit a másik három sarokban ezen információ nélkül? Ne félj, mivel a Lángnak van módja a képernyő tényleges méretének beolvasására (azért van, mert ennek körül van egy dokumentált probléma).

Alapvetően az async módszer

Vegye figyelembe, hogy a várakozási kulcsszó, akárcsak a JavaScriptben, csak async függvényben használható, tehát feltétlenül készítse el a fő async-et (a flamter nem érdekel).

A következő ellenőrzőpont egyszer meghozza a méreteket a fő módszerhez, és tárolja azokat a Game osztályban, mert többször szükségünk lesz rájuk.

Ellenőrzőpont: a1f9df3

Sprites megjelenítés

Végül tudjuk, hogyan lehet bármilyen alakzatot rajzolni, bárhol a képernyőn. De akarunk spriteket! A következő ellenőrzőpont hozzáad egy-egy eszközt, amelyeket használni fogunk a megfelelő eszközök mappába:

Ellenőrzőpont: 92ebfd9

A következő pedig egy kulcsfontosságú dolgot tesz, amelyet nem szabad elfelejteni: mindent adjon hozzá a pubsepc.yaml fájlhoz. A kód építésekor a Dart csak az ott megadott erőforrásokat köti össze.

Checkpoint cf5975f

Végül készen állunk arra, hogy felhívjuk a figyelmünket. Az alapvető módszer, amelyet a Láng lehetővé tesz, hogy felfedje a Flame.images.load ('útvonal a képek mappájában') metódust, amely visszatér a betöltött kép ígéretéhez, amelyet később a canvas.drawImage módszerrel lehet felhívni.

Láda rajzolása esetén azonban ezt nagyon egyszerűbb megtenni, mert a SpriteComponent osztályt használhatjuk, például:

Az absztrakt Komponens osztály egy felület két módszerrel, megjelenítés és frissítés, akárcsak játékunk. Az ötlet az, hogy a játék olyan komponensekből állhat, amelyek render és frissítési módszereit a játék módszereiben hívják. A SpriteComponent egy olyan megvalósítás, amely egy sprite-et ad meg, neve és mérete (négyzet vagy téglalap alakú), az (x, y) helyzet és a forgási szög alapján. Megfelelően zsugorodik vagy kibővíti a képet, hogy illeszkedjen a kívánt mérethez.

Ebben az esetben a 'crate.png' fájlt töltjük be, amelynek az eszközök / képek mappában kell lennie, és van egy Crate osztály, amely 128x128 pixel méretű dobozokat húz, 0 forgásszöggel.

Ezután hozzáadunk egy láda tulajdonságot a játékhoz, a képernyő tetejére inicializáljuk, vízszintes középre, és megjelenítjük a játék hurkában:

Ez teszi a rekeszünket! Fantasztikus! A kód elég tömör és könnyen olvasható.

Ellenőrzőpont 7603ca4

Az állapot frissítése a játék hurkában

A rekeszünk minden, de megállt a levegőben. Meg akarjuk mozgatni! Minden láda állandó sebességgel esik lefelé. Ezt meg kell tennünk a frissítési módszerünkben; csak változtassa meg az egyetlen láda Y helyzetét:

Ez a módszer időt vesz igénybe (másodpercben), ami az utolsó frissítéstől számított. Általában ez nagyon kicsi lesz (10 ms sorrendben). Tehát a SPEED állandó ezekben az egységekben; a mi esetünkben SPEED = 100 pixel / másodperc.

Ellenőrzési pont: 452dc40

Bemenet kezelése

Hurrá! A ládák leesnek és eltűnnek, de velük nem léphet kapcsolatba. Adjunk hozzá egy módszert a rekeszek megsemmisítésére, amelyekre megérintünk. Ehhez egy ablak eseményt fogunk használni. Az ablakobjektum globálisan rendelkezésre áll minden Flutter projektben, és van néhány hasznos tulajdonsága. A fő módszernél regisztrálunk egy onPointerDataPacket eseményt, azaz amikor a felhasználó megérinti a képernyőt:

Kibontjuk a kattintás (x, y) koordinátáját, és egyenesen átadjuk a játékunkhoz; így a játék képes kezelni a kattintást anélkül, hogy aggódna az események részletei miatt.

Annak érdekében, hogy a dolgok még érdekesebbé váljanak, utánozzuk újra a Game osztályt, hogy legyen egyetlen rekeszlista helyett. Hátul, ezt akarjuk. A render és a frissítési módszereket kicseréljük a rekeszek feletti forEach-ra, és az új beviteli módszer lesz:

Ellenőrzési pont: 364a6c2

Többféle sprite megjelenítés

Van egy kritikus szempont, amelyet megemlíthetünk, és ez a render módszerrel kapcsolatos. Láda készítésekor a vászon állapotát lefordítják és önkényesen forgatják a rajz lehetővé tétele érdekében. Mivel több ládát rajzolunk, vissza kell állítanunk a vászonot minden húzott között. Ez történik a mentési módszerekkel, amelyek mentik az aktuális állapotot, és a visszaállítás, amely visszaállítja az előzőleg mentett állapotot, törölve azt.

Ez egy fontos megjegyzés, mivel számos furcsa hiba forrása. Talán ezt automatikusan meg kell tennünk minden egyes megjelenítésnél? Nem tudom, mit gondolsz?

Most több ládát akarunk! Hogyan kell csinálni? Nos, a frissítési módszer lehet az időzítőnk. Tehát azt akarjuk, hogy másodpercenként új láda kerüljön a listára (született). Tehát létrehoztunk egy másik változót a Game osztályban, hogy felhalmozzuk az egyes frissítési hívások delta-idejét (t). Ha 1-nél többet kap, akkor visszaáll és új láda keletkezik:

Ne felejtsd el megőrizni az előző frissítést, így a rekeszek nem állnak le. Ezenkívül a sebességet 250 pixel / másodpercre változtatjuk, hogy egy kicsit érdekesebbé váljunk.

Ellenőrzőpont: 3932372

Animációk renderelése

Ennek GIF-nek kell lennie, nem? Dolgozunk az ezen oktatóprogram jobb képernyőképeinek és GIF-jeinek beállításán!

Most ismerjük a Sprite kezelésének és megjelenítésének alapjait. Menjünk a következő lépésre: Robbanások! Milyen játék jó ezek nélkül? A robbanás másféle vadállat, mert animációval rendelkezik. A Láng animációi egyszerűen úgy készülnek, hogy különböző dolgokat renderelnek a jelenlegi kullancs szerint. Ugyanúgy, mint egy kézzel készített időzítőt adtunk hozzá az ívási dobozokhoz, minden robbanáshoz hozzáadunk egy LifeTime tulajdonságot. Az Explosion nem örököl a SpriteComponent-től, mivel az utóbbi csak egy Sprite-t tartalmazhat. A szuperosztályt, a PositionComponent-t kibővítjük, és a megjelenítést a Flame.image.load fájl segítségével valósítjuk meg.

Mivel minden robbanásnak sok képkockája van, és azokat érzékenyen kell rajzolni, minden keretet előzetesen betöltünk, és egy statikus változóba mentjük a robbanásosztályon belül; tetszik:

Vegye figyelembe, hogy a 7 animációs keret mindegyikét sorrendben töltjük be. Ezután a render módszerrel egyszerű logikát alkalmazunk annak eldöntésére, hogy melyik keretet rajzoljuk:

Vegye figyelembe, hogy a „kézzel” rajzolunk, a drawImageRect használatával, a korábban kifejtettek szerint. Ez a kód hasonló ahhoz, amit a SpriteComponent csinál a motorháztető alatt. Vegye figyelembe azt is, hogy ha a kép nincs a tömbben, semmit sem rajzol - TIME másodperc múlva (0,75 vagy 750 ms-ra állítottuk) semmi nem jelenik meg.

Ez jó és jó, de nem akarjuk, hogy a robbanások tömbjét robbanó robbanásokkal szennyezzük, tehát hozzá kell adnunk egy pusztítás () módszert is, amely az életidő alapján visszatér, hogy el kell pusztítanunk a robbanás tárgyát.

Végül frissítjük játékunkat, hozzáadva a Robbanások listáját, megjelenítve őket a render módszerrel, majd frissítve a frissítési módszerrel. Frissíteni kell az élettartamuk növelése érdekében. Ezúttal arra is törekszünk, hogy reagáljanak arra, ami korábban a Game.update módszernél történt, azaz a dobozokat leesik, hogy a Crate.update módszer belsejébe kerüljenek, mivel ez a lád felelõssége. A játékfrissítés most már csak másokra delegál. Végül, a frissítés során törölnünk kell a listából azt, ami elpusztult. Ehhez a Lista egy nagyon hasznos módszert kínál, az removeWhere:

Ezt már a beviteli módszernél használtuk, hogy eltávolítsuk a tömbből megérintett dobozokat. Itt is ott lesz egy robbanás.

Vessen egy pillantást az ellenőrző pontra további részletekért.

Ellenőrzőpont: d8c30ad

Audio lejátszása

A következő elkötelezettségben végre lejátsszunk némi hangot! Ehhez hozzá kell adnia a fájlt az eszközök mappához, az eszközök / audio / mappába. MP3 vagy OGG fájlnak kell lennie. Ezután a kód bármely pontján futtassa:

Ahol a filename.mp3 a benne található fájl neve. A mi esetünkben akkor a robbanás.mp3 hangot fogjuk lejátszani, amikor egy dobozba kattintunk.

Ezenkívül kezdjük el elválasztani az írásjeleket. Pontváltozót adunk hozzá, hogy megőrizzük az aktuális pontszámot. Nullával kezdődik; dobozonként 10 pontot kattintunk, és 20-at veszítünk, amikor a doboz megérkezett a földre.

Most kötelességünk a kiszabadult dobozokkal foglalkozni. Annak alapján, amit tettünk az Explosion osztályban, hozzáadunk egy romboló módszert a láda számára, amely visszatér, függetlenül attól, hogy kívül vannak-e a képernyőn. Ez kezd mintává válni! Ha megsemmisül, akkor eltávolítjuk a tömbből és beállítjuk a pontokat.

Egyelőre a pontozás működik, de sehol nem jelenik meg; ez hamarosan jön.

A hang nem fog működni a következő ellenőrző pontban, mert elfelejtettem hozzáadni a fájlokat, és a pubspec.yaml fájlba helyeztem őket; ez történik a következő kötelezettségvállalásban.

Ellenőrzőpont: 43a7570

Most több hangot akarunk! Az audiolejátszók (figyelembe véve a lib), amelyet a Láng használ, lehetővé teszik több hang egyszerre lejátszását, amint azt már észrevetted, ha őrületre kattintasz, de most ezt használjuk előnyünkre, ha hiányzik a hang, amikor a doboz megüti a talajt (elpusztítja a láda módszerét) és háttérzene.

A háttérzene hurkon történő lejátszásához használja a hurok módszert, amely ugyanúgy működik, mint korábban:

Ebben a kötelezettségvállalásban rögzítjük a ládák pusztulási feltételét is, amelyet elmulasztottunk az előző kötelezettségvállaláskor (mivel nem volt tudásunk, most van hang).

Ellenőrzési pont: f575150

Megjeleníti a szöveget

Most, hogy megvan az összes kívánt hang (háttér, zene, hanghatások, MP3, OGG, hurok, egyidejűleg), kezdjük a szövegmegjelenítést. Végül is látnunk kell ezt a pontszámot. Ennek „kézzel” történő végrehajtása az, hogy létrehozunk egy bekezdésobjektumot, és használjuk a vászon drawParagraph-ját. Nagyon sok konfigurációra van szükség, és ez egy meglehetősen zavaró API, de a következő módon hajtható végre:

Ellenőrzőpont: e09221e

Ezt az alapértelmezett betűkészlet rajzolja, és a fontFamily tulajdonsággal megadhat egy másik általános rendszer betűtípust; bár valószínűleg a játékodban hozzáadni szeretne egyéni egyet.

Tehát elindultam a 1001fonts.com oldalra, és megkaptam ezt a szép, ingyenes Halo betűtípust TTF-ként. Ismét dobja el a fájlt az eszközökben / betűkészletekben, de most különféleképpen kell importálnia a pubspec.yaml fájlba. Még egy eszköz hozzáadása helyett van egy dedikált betűkészlet-címke, amelyet alapértelmezetten a betűkészletek hozzáadásával kapcsolatos teljes utasítások kommentálnak. Tehát rendeljen neki egy nevet, és tegyen valamit, például:

Ez az extra absztrakciós réteg magától a Flutter-től származik, és lehetővé teszi több fájl hozzáadását ugyanahhoz a betűtípushoz (félkövér, nagyobb méretek stb. Meghatározásához). Most, a bekezdésünkhöz, csak hozzáadjuk a fontFamily: 'Halo' tulajdonságot a TextStyle konstruktorhoz.

Fuss, és látni fogja a szép Halo betűtípust!

Ellenőrzőpont: 3155bda

Ez a leírt módszer nagyobb irányítást biztosít, ha például több stílust szeretne ugyanabban a bekezdésben. De ha szeretne, mint például ebben az esetben, egyetlen stílusú egyszerű bekezdést, akkor csak a Flame.util.text segédprogram segítségével hozhatja létre:

Ez az egyetlen sor felváltja a korábbi 4-et, és felfedi a legfontosabb funkciókat. Szöveg (első argumentum) szükséges, és a többi nem kötelező, ésszerű alapértelmezésekkel.

A színhez ismét a Colors.white segítőt használjuk, de akkor is használhatunk új színt (0xFFFFFFFF), ha egy adott színt szeretne.

Ellenőrzőpont: 952a9df

És megvan! Komplett játék sprite rendereléssel, szöveges megjelenítéssel, audio, játék hurokkal, eseményekkel és állami menedzsmenttel.

Kiadás

Készen állsz játékod kiadására?

Csak kövesse ezeket a néhány egyszerű lépést a Flutter bemutatóból.

Mindegyik nagyon egyszerű, amint azt az utolsó ellenőrző pontból láthatja, kivéve az Ikonok részt, amely kissé fejfájást okozhat. Javaslom, hogy készítsen nagy méretű (512 vagy 1024 képpontos) ikont, és a Make App Icon weboldal használatával hozzon létre egy ZIP-fájlt, amire szüksége van (iOS és Android).

Ellenőrzési pont: 2974f29

Mi más?

Élvezte a lángot? Ha bármilyen javaslata, hibája, kérdése, szolgáltatás igénye vagy bármilyen kérdése van, kérjük, bátran forduljon hozzám!

Javítani szeretné játékát, és többet tudna? Mi lenne egy szerver hozzáadása a Firebase és a Google Bejelentkezés szolgáltatáshoz? Mi lenne a hirdetések elhelyezése? Mi lenne a főmenü és a több képernyő beállítása?

Természetesen még sokat kell javítani - ez csak egy példajáték. De meg kellett volna adnia egy alapelvet a játék fejlesztésének a Flutterrel (lánggal vagy anélkül) kifejlesztett alapelveiről.

Remélem mindenki élvezte!

Eredetileg a GitHub-ban publikálták.