Põhjalik leegiõpetus (või kuidas teha mänge räpasega)

Sissejuhatus

Tere kõigile! Olen Luan ja tere tulemast selle esimese põhjaliku leegiõpetuse juurde.

Flame on minimalistlik Flutteri mängumootor, mis pakub lõuendil põhineva mängu valmistamiseks mõned moodulid.

Selles õpetuses loome väga lihtsa mängu, kus kastid kukuvad alla ja eesmärk on need hävitada enne, kui nad ekraani põhja satuvad.

Mäng näeb välja selline

Saate mängu ise kontrollida, et näha, mida me selle APK installimisega või Play poest installimisega ette võtame.

See võimaldab meil hõlmata kõiki raamistiku pakutavaid funktsioone ja demonstreerida kõige elementaarsemate toimingute teostamist: renderdamist, spreid, heli, teksti, animatsioone ja palju muud.

Miks me selle mängu valisime? Lisaks sellele, et raamistiku uurimine on väga lihtne, kuid samas täielik, on heaks teguriks ka see, et meil on selleks ressursse!

Selle mängu jaoks kavatseme kasutada järgmisi ressursse: üks aedikute sprite, üks plahvatus sprite (koos animatsiooniga), plahvatuse heli, 'miss' heli (kui kasti pole löödud), taustmuusika ja ka ilus font partituuri tegemiseks.

Internetis müügil olevaid häid ressursse on raske leida, kuid leidsime sellest vinge saidilt kõik (välja arvatud font). Need on tõesti suurepärased, tingimata soovitatav.

Kuna praegu sprite-lehti ei toetata, siis esiteks peame kõik ressursid teisendama sobivatesse formaatidesse. Samuti peame kogu heli MP3-vormingusse teisendama (ka OGG on toetatud; WAV pole). Kui see kõik on valmis, saate siin alla laadida kimbu kõigega, mida vajate ressursside tarvis.

Samuti väärib märkimist, et kõik siin kirjeldatu on täielikult funktsionaalse tervikversioonina pühendatud GitHubile. Kahtluse korral võite alati pilgu heita. Ka näide loodi täpselt neid samme järgides ja sageli pilte tehes. Tervises õpetuses seostan konkreetsed kohustused, mis viivad hoidla asjaomase etapini. See võimaldab teil teha kontrollpunkte ja sirvida vana koodi, et näha kõike, mis polnud selge.

Viimane asi; leegi täielikku dokumentatsiooni saate vaadata siit. Kui teil on küsimusi, ettepanekuid, vigu, avage mõni probleem või võtke minuga ühendust.

Peale selle on teil vaja installida ka Flutter ja Dart. Kui see teile sobib, võib teil olla ka IntelliJ IDEA, mis on väga hea koht oma koodi kirjutamiseks. Selle kraami installimiseks saate vaadata seal hulgaliselt õpetusi, nagu see.

Põhitõed

Seega eeldan, et nüüd on teil kõik valmis. Nii, lihtsalt käivitage järgmine ja avage see!

Esimene asi, mida peate tegema, on lisada leegist sõltuvus. Minge oma pubspec.yaml faili ja veenduge, et sõltuvusvõti sisaldab leeki:

Kasutame siin uusimat versiooni 0.5.0, kuid võimaluse korral saate valida ka uue.

Nüüd on teie failis main.dart juba palju kraami: „peamine” meetod, mida tuleb säilitada; ja sellele järgnev üleskutse runApp-meetodile. Selle meetodi jaoks võetakse vidinad ja muud räpsukomponendid, mida kasutatakse rakendusekraanide tegemiseks. Kuna me teeme mängu, joonistame kõik lõuendile ja me ei kasuta neid komponente; nii et eemaldage see kõik.

Meie peamine meetod on nüüd tühi ja lisame kaks asja; esiteks mõned konfiguratsioonid:

Import leegi.dart võimaldab juurdepääsu staatilise leegi leegile, mis on lihtsalt mitme muu kasuliku klassi omanik. Me kasutame seda hiljem rohkem. Praegu kutsume selles Flame klassis kahte meetodit.

Viimane on iseenesestmõistetav, see keelab osa logimisest audio-mängijate pistikprogrammi. Nüüd lisame varsti mängu mängu heli ja kui see ei tööta, peate selle tõrkeotsinguks kommenteerima. Kuid lõpuks jõuame sinna.

Esimene rida on keerulisem. Põhimõtteliselt puudub mõni Flutteri oluline funktsioon, kuna me ei kasuta runApp-meetodit. See enableEventsi kõne aitab pisut lahendada, et saada iga rakenduse jaoks vajalikke asju ilma vidinaid kasutamata.

Lõpuks peame oma mängu alustama. Selleks lisame impordiloendisse veel ühe klassi, mänguklassi. See klass pakub abstraktsiooni, mis on vajalik mis tahes mängu loomiseks: mängusilm. See peab olema alamklassi, nii et peate rakendama mis tahes mängu aluseid: värskendusmeetod, mida kutsutakse igal ajal mugavaks ja võtab viimasest värskendusest möödunud aja, ning renderdusmeetod, mis peab teadma, kuidas joonistada mängu hetkeseis. Silmuse sisemised toimingud jäetakse mänguklasside lahendada (võite muidugi vaadata, see on väga lihtne) ja peate lihtsalt helistama starti, noh, starti.

Kontrollpunkt: 599f809

Praegu ei tee renderdus midagi, seega peaks selle käivitamisel töötama, kuid andma teile musta ekraani. Magus! Nii et saime funktsionaalse rakenduse ilma vidinate ja nootideta ning tühja lõuendi, et meie rakendust joonistada.

Kujude renderdamine

Ja kuidas joonistamine toimub? Joonistame selle toimimiseks nägemiseks lihtsa ristküliku. Lisage oma renderdusmeetodile järgmine:

Nagu näete, määratleme siin ekraani positsioonide põhjal ristküliku. Järgmine pilt näitab, kuidas reeglid on orienteeritud. Põhimõtteliselt on päritolu vasakus ülanurgas ja telg suureneb paremale ja allapoole.

Samuti pange tähele, et enamik joonistusmeetodeid võtab värvi. Värv ei ole lihtsalt ühevärviline, vaid see võib olla Degradè või mõni muu tekstuur. Tavaliselt tahaksite kas kindlat värvi või minge otse Sprite'i juurde. Nii et me määrasime värvi värvi sees ainult värvi eksemplarile.

Värv tähistab ühte ARGB-värvi; loote selle täisarvuga, mille saate hõlpsamaks lugemiseks kuushaaval kirjutada; see on vormingus A (alfa, läbipaistvus, tavaliselt 0xFF) ja seejärel kaks numbrit R, G ja B jaoks selles järjekorras.

Seal on ka nimekate värvide kollektsioon; see on siiski materjali pakendis. Lihtsalt olge ettevaatlik, et impordiksite lihtsalt värvide moodulit, et mitte kasutada materjalipakist juhuslikult midagi muud.

Nii, tore, nüüd on meil ruut!

Kontrollpunkt: 4eff3bf

Me teame ka, kuidas joonlauad töötavad, kuid me ei tea ekraani mõõtmeid! Kuidas me ilma selle teabeta kolmest teisest nurgast midagi joonistame? Ärge kartke, kuna leegil on meetod ekraani tegeliku mõõtme toomiseks (seda seetõttu, et selle ümber on dokumenteeritud probleem).

Põhimõtteliselt asünkri meetod

Pange tähele, et ootamissõna, nagu ka JavaScriptis, saab kasutada ainult asünkroonifunktsioonis, seega veenduge, et teeksite oma peamise asünkrooni (laperdus ei hooli sellest).

Järgmine kontrollpunkt tõmbab mõõtmed üks kord põhimeetodi järgi ja salvestab need meie mänguklassi, kuna vajame neid korduvalt.

Kontrollpunkt: a1f9df3

Spriteede renderdamine

Lõpuks teame, kuidas joonistada ükskõik millist kuju ekraanile. Aga me tahame spreid! Järgmine kontrollpunkt lisab mõned varad, mida me kasutame, vastavasse varade kausta:

Kontrollpunkt: 92ebfd9

Ja järgmine teeb ühe olulise asja, mida te ei saa unustada: lisage kõik oma pubsepc.yaml-faili. Teie koodi ehitamisel koondab Dart ainult teie määratud ressursse.

Kontrollpunkt cf5975f

Lõpuks oleme valmis oma sprite joonistama. Peamine viis, kuidas Flame seda võimaldab, on paljastada Flame.images.load ('tee piltide kaustast') meetod, mis tagastab laaditud pildi lubaduse, mille saab seejärel joonistada meetodiga canvas.drawImage.

Kasti joonistamise puhul on seda aga väga lihtne teha, kuna saame kasutada klassi SpriteComponent, näiteks nii:

Abstraktsete komponentide klass on liides kahe meetodiga renderdamiseks ja värskendamiseks, nagu ka meie mäng. Idee on see, et mäng võib koosneda komponentidest, mille renderdamis- ja värskendamismeetodeid nimetatakse mängu meetodite piires. SpriteComponent on rakendus, mis muudab sprite, arvestades selle nime ja suurust (ruut või ristkülik), (x, y) asendit ja pöördenurka. See kahandab või laiendab pilti vastavalt soovitud suurusele.

Sel juhul laadime faili 'crate.png', mis peab olema varade / piltide kaustas, ja sellel on aediklass, mis tõmbab kastid suurusega 128x128 pikslit pöördenurgaga 0.

Seejärel lisame mängule atribuudi Crate, kiirendame selle ekraani ülaservas, horisontaalselt keskele ja renderdame selle meie mängu ahelasse:

See muudab meie aediku! Vinge! Kood on üsna lühike ja hõlpsasti loetav.

Kontrollpunkt 7603ca4

Oleku värskendamine mänguahelas

Meie aedik on vaid õhus peatunud. Me tahame seda liigutada! Iga aedik langeb ühtlase kiirusega allapoole. Peame seda oma värskendusmeetodis tegema; lihtsalt muutke meil oleva üksiku aediku Y-positsiooni:

See meetod võtab aega (sekundites), mis kulus viimasest värskendusest. Tavaliselt on see väga väike (suurusjärk 10 ms). Seega on KIIRUS nendes ühikutes konstant; meie puhul SPEED = 100 pikslit sekundis.

Kontrollpunkt: 452dc40

Sisendi haldamine

Hurraa! Kastid kukuvad alla ja kaovad, kuid te ei saa nendega suhelda. Lisagem meetod, mille abil hävitada korvid, mida me puutume. Selleks hakkame kasutama aknasündmust. Aknaobjekt on saadaval kõigis Flutteri projektides globaalselt ja sellel on mõned kasulikud omadused. Registreerime põhimeetodil onPointerDataPacketi sündmuse, see tähendab siis, kui kasutaja puudutab ekraani:

Me eraldame lihtsalt klõpsu (x, y) koordinaadi ja edastame selle otse meie mängu; nii saab mäng hakkama klõpsuga, muretsemata sündmuste üksikasjade pärast.

Asjade huvitavamaks muutmiseks mõelgem ka mängude klassile, et meil oleks ainsana üks aedikute loend. Pärast seda on see, mida me tahame. Asendame renderdamis- ja värskendamismeetodid aedikutega forEachiga ja uueks sisestusmeetodiks saab:

Kontrollpunkt: 364a6c2

Mitme spriidi renderdamine

Siinkohal tuleb mainida ühte olulist punkti ja see puudutab renderdusmeetodit. Kui muudame aediku, tõlgitakse lõuendi olek joonistamise võimaldamiseks suvaliselt ja pöörleb. Kuna me joonistame mitu kasti, peame lähtestama lõuendi iga joonistatud vahel. See tehakse salvestamise meetoditega, mis salvestab praeguse oleku ja taastamise abil, mis taastab varem salvestatud oleku, kustutades selle.

See on oluline märkus, kuna see on paljude imelike vigade allikas. Võib-olla peaksime seda automaatselt tegema igas renderduses? Ma ei tea, mis sa arvad?

Nüüd tahame rohkem kaste! Kuidas seda teha? Noh, värskendusmeetod võib olla meie taimer. Seega soovime, et iga sekund lisanduks loendisse uus kuur. Nii lõime mänguklassis veel ühe muutuja, et iga värskenduskõne delta-ajad (t) koguneksid. Kui see saab üle 1, lähtestatakse see ja uus karp sündis:

Ärge unustage säilitada eelmist värskendust, nii et kastid ei lakka kukkumast. Samuti muudame kiiruse 250 pikslile sekundis, et asi pisut huvitavamaks muuta.

Kontrollpunkt: 3932372

Animatsioonide renderdamine

See peaks olema GIF, eks? Töötame selle õpetuse jaoks paremate ekraanipiltide ja GIF-i häälestamisel!

Nüüd teame Sprite käitlemise ja renderdamise põhitõdesid. Liigume järgmise sammu juurde: Plahvatused! Mis mäng on hea ilma nendeta? Plahvatus on teistsugune metsaline, kuna sellel on animatsioon. Animatsioone leegis tehakse lihtsalt renderdades erinevaid asju vastavalt praegusele linnukesele. Samamoodi, kui lisasime kudekarbidele käsitsi valmistatud taimeri, lisame iga plahvatuse jaoks LifeTime'i omaduse. Samuti ei päri Explosion SpriteComponentilt, kuna viimasel võib olla ainult üks Sprite. Me laiendame superklassi PositionComponent ja rakendame renderdamist Flame.image.load abil.

Kuna igal plahvatusel on palju kaadreid ja neid tuleb joonistada reageerivalt, laadime iga kaadri üks kord ette ja salvestame plahvatusklassi staatilise muutujana. meeldib nii:

Pange tähele, et laadime järjekorras kõik meie 7 animatsiooniraami. Seejärel loome renderdusmeetodi abil lihtsa loogika, et otsustada, millist kaadrit joonistada:

Pange tähele, et joonistame käsitsi, kasutades drawImageRect, nagu varem selgitatud. See kood sarnaneb sellega, mida SpriteComponent kapoti all teeb. Pange tähele ka seda, et kui pilti pole massiivis, ei joonistata midagi - nii, et TIME sekundi pärast (valisime selle väärtuseks 0,75 või 750 ms), ei kuvata midagi.

See on hästi ja hea, kuid me ei taha plahvatusohtlikke plahvatusi pidevalt reostada, seega lisame ka hävitamise () meetodi, mis annab eluaja põhjal teada, kas peaksime plahvatusobjekti hävitama.

Lõpuks värskendame oma mängu, lisades plahvatuste loendi, renderdades need renderdusmeetodil ja värskendades seejärel värskendusmeetodil. Neid tuleb aja jooksul uuendada. Võtame selle aja ka reaktoriks, mis oli varem meetodil Game.update, st paneb kastid langema, et olla Crate.update meetodi sees, kuna see on aediku vastutus. Nüüd delegeerib mänguvärskendus ainult teistele. Lõpuks peame värskenduses loendist kustutama selle, mis on hävinud. Selleks pakub loend väga kasulikku meetodit eemalda kus:

Me kasutasime seda juba sisestusmeetodi korral massiivist puudutatud kastide eemaldamiseks. Seal on ka koht, kus me plahvatuse tekitame.

Lisateavet leiate kontrollpunktist.

Kontrollpunkt: d8c30ad

Heli mängimine

Järgmisel pühendumisel kavatseme lõpuks heli esitada! Selleks peate faili lisama varade kausta, vara / heli / sisse. See peab olema MP3- või OGG-fail. Seejärel käivitage oma koodi kõikjal:

Kus failinimi.mp3 on sees oleva faili nimi. Meie puhul mängime kasti klõpsamisel heli "shootion.mp3".

Lisaks alustame kirjavahemärkide andmist. Lisame punktide muutuja praeguse punktide arvu hoidmiseks. See algab nulliga; saame ühe klõpsitud kasti kohta 10 punkti ja kaotame 20, kui kast maapinnale langeb.

Nüüd on meil kohustus tegeleda põgenenud kastidega. Selle põhjal, mida me Explosion-klassiga tegime, lisame kasti hävitamismeetodi, mis naaseb siis, kui nad on ekraanist väljas. See on muutumas mustriks! Kui see hävitatakse, eemaldame massiivist ja kohandame punkte.

Praegu punktiskoor töötab, kuid seda ei näidata kuskil; see tuleb varsti.

Heli selles järgmises kontrollpunktis ei tööta, kuna unustasin failid lisada ja pubspec.yaml; see on tehtud järgmises kohustuses.

Kontrollpunkt: 43a7570

Nüüd tahame rohkem helisid! Helimängijad (pidage meeles), mida Flame kasutab, võimaldavad teil mängida mitu heli korraga, nagu juba võisite tähele panna, kui klõpsatasite meeletu, kuid kasutagem nüüd seda oma eeliseks, mängides miss heli, kui kast tabab maad (hävitada aediku meetod) ja taustamuusika.

Taustmuusika esitamiseks silmusel kasutage silmusmeetodit, mis töötab täpselt nagu enne:

Selles kohustuses fikseerime ka aedikute hävitamise tingimuse, millest jätsime eelmises kohustuses ilma (kuna polnud teada saada, nüüd on kindel).

Kontrollpunkt: f575150

Teksti renderdamine

Nüüd, kui meil on olemas kõik soovitud heli (taust, muusika, heliefektid, MP3, OGG, silmus, üheaegselt), laskem siis teksti renderdamisse. Lõppude lõpuks peame seda tulemust nägema. See, kuidas seda käsitsi tehakse, on lõiguobjekti loomine ja lõuendi joonistamisfunktsiooni DrawParagraph kasutamine. See võtab palju konfigureerimist ja on üsna segane API, kuid seda saab teostada nii:

Kontrollpunkt: e09221e

See on joonistatud vaikefondiga ja atribuudi fontFamily abil saate määratleda erineva tavalise süsteemi fondi; kuigi tõenäoliselt soovite oma mängus lisada kohandatud.

Niisiis suundusin saidile 1001fonts.com ja sain selle päris kommertsliku tasuta Halo fondi TTF-na. Jällegi lihtsalt pudistage fail varadesse / fondidesse, kuid nüüd tuleb see faili pubspec.yaml teisiti importida. Veel ühe vara lisamise asemel on selleks spetsiaalne kirjasilt, mida vaikimisi kommenteeritakse koos täielike juhistega, kuidas fonte lisada. Nii et määrake sellele nimi ja tehke midagi sellist:

See täiendav abstraktsioonikiht pärineb Flutterilt endalt ja võimaldab teil lisada sama fondi jaoks mitu faili (paksude, suuremate suuruste jne määratlemiseks). Nüüd lõigu juurde, lisame lihtsalt TextStyle konstruktorile vara fontFamily: 'Halo'.

Jookse ja sa näed päris Halo fonti!

Kontrollpunkt: 3155bda

Kirjeldatud meetod annab teile suurema kontrolli, kui soovite näiteks samas lõigus kasutada mitut stiili. Kuid kui soovite, nagu antud juhul, ühte stiilset lihtsat lõiku, kasutage selle loomiseks lihtsalt abistajat Flame.util.text:

See üks rida asendab eelnevaid 4 ja paljastab kõige olulisemad omadused. Tekst (esimene argument) on nõutav ja kõik ülejäänud on valikulised, mõistlike vaikimiste korral.

Värvi jaoks kasutame jällegi Colors.white abilist, kuid kui soovite konkreetset värvi, võime kasutada ka uut värvi (0xFFFFFFFF).

Kontrollpunkt: 952a9df

Ja seal see teil on! Terviklik mäng sprite renderdamise, teksti renderdamise, heli, mängusilmuse, sündmuste ja olekuhaldusega.

Vabastage

Kas teie mäng on valmis vabastamiseks?

Lihtsalt järgige neid paar lihtsat sammu Flutteri õpetusest.

Need on kõik üsna sirged, nagu näete selles viimases kontrollpunktis, välja arvatud ikoonide osa, mis võib põhjustada pisut peavalu. Minu soovitus on teha oma ikoonist suur (512 või 1024 pikslit) ja kasutada veebisaidi Make App Icon veebisaidi loomiseks vajaliku tõmblukuga (iOS ja Android).

Kontrollpunkt: 2974f29

Mida veel?

Kas teile meeldis Flame? Kui teil on ettepanekuid, vigu, küsimusi, funktsioonitaotlusi või midagi muud, võtke minuga julgelt ühendust!

Kas soovite oma mängu paremaks muuta ja rohkem teada saada? Kuidas oleks serveri lisamisega Firebase'i ja Google'i sisselogimisega? Kuidas oleks reklaamide ülespanemisega? Kuidas oleks põhimenüü ja mitme ekraaniga seadistamine?

Muidugi on palju veel parandamist - see on lihtsalt näitemäng. Kuid see oleks pidanud andma põhiidee mängude arendamise põhimõistetest koos Flutteriga (leegiga või ilma).

Loodetavasti kõigile meeldis!

Algselt avaldati GitHubis.