Kuidas kirjutada oma esimene Android-mäng Java-s

Autor: John Stephens
Loomise Kuupäev: 1 Jaanuar 2021
Värskenduse Kuupäev: 19 Mai 2024
Anonim
Kuidas kirjutada oma esimene Android-mäng Java-s - Rakendused
Kuidas kirjutada oma esimene Android-mäng Java-s - Rakendused

Sisu


Androidi mängu loomiseks on palju võimalusi ja üks oluline viis on seda teha nullist Android Studio koos Javaga. See annab teile maksimaalse kontrolli selle üle, kuidas soovite oma mängu välja näha ja käituda ning protsess õpetab teile oskusi, mida saate kasutada ka paljudes teistes stsenaariumides - olgu siis loomisel rakenduse pritsikuva või soovite lihtsalt lisage mõned animatsioonid. Seda silmas pidades näitab see õpetus teile, kuidas luua Android Studio ja Java abil lihtsat 2D-mängu. Kogu koodi ja ressursid leiate Githubist, kui soovite neid jälgida.

Seadistan

Oma mängu loomiseks peame tegelema mõne konkreetse kontseptsiooniga: mänguaasad, niidid ja lõuendid. Alustuseks käivitage Android Studio. Kui teil pole seda installitud, siis vaadake meie täielikku sissejuhatust Android Studio, mis läbib installiprotsessi. Nüüd alustage uut projekti ja veenduge, et olete valinud malli „Tühi tegevus”. See on mäng, nii et loomulikult ei vaja te selliseid asju nagu FAB-nupp, mis asju keeruliseks muudab.


Esimene asi, mida soovite teha, on muuta AppCompatActivity kuni Tegevus. See tähendab, et me ei kasuta toiminguriba funktsioone.

Samamoodi tahame muuta oma mängu täisekraaniks. Lisage järgmine kood saidile onCreate () enne kõne seadistamiseks setContentView ():

getWindow (). setFlags (WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); this.requestWindowFeature (Window.FEATURE_NO_TITLE);

Pange tähele, et kui kirjutate mõne koodi välja ja see on punasega alla joonitud, tähendab see tõenäoliselt, et peate klassi importima. Teisisõnu peate andma Android Studio-le teada, et soovite kasutada teatud avaldusi ja need kättesaadavaks teha. Kui klõpsate lihtsalt allakriipsutatud sõna kuskil ja vajutate klahve Alt + Enter, siis tehakse seda teie jaoks automaatselt!


Mänguvaate loomine

Võib-olla olete harjunud rakendustega, mis kasutavad XML-skripti, et määratleda vaadete paigutust nagu nupud, pildid ja sildid. See on see joon setContentView teeb meie heaks.

Kuid jällegi on see mäng, mis tähendab, et sellel pole vaja brauseriaknaid ega ringlussevõtja vaateid kerima. Selle asemel tahame näidata lõuendit. Android Stuudios on lõuend täpselt sama, mis kunstis: see on meedium, millele saame joonistada.

Nii et muutke seda rida nii, et see oleks järgmine:

setContentView (uus GameView (see))

Leiate, et see on jälle punasega alla joonitud. Aga nüüd kui vajutate Alt + Enter, pole teil võimalust klassi importida. Selle asemel on teil võimalus luua klass. Teisisõnu, me hakkame looma oma klassi, mis määratleb lõuendil toimuva. See võimaldab meil joonistada ekraanile, selle asemel et näidata lihtsalt vaateid.

Nii paremklõpsake vasakul asuvas hierarhias paketi nime ja valige Uus> klass. Teile pakutakse nüüd klassi loomiseks akent ja kavatsete sellele helistada GameView. SuperKlassi all kirjutage: android.view.SurfaceView mis tähendab, et klass pärib meetodeid - oma võimalusi - SurfaceView-st.

Kirjutate väljale Liides (ed) android.view.SurfaceHolder.Callback. Nagu iga klassi puhul, peame ka nüüd oma konstruktori looma. Kasutage seda koodi:

privaatne MainThread niit; avalik GameView (konteksti kontekst) {super (kontekst); getHolder (). addCallback (see); }

Iga kord, kui meie klass kutsutakse üles tegema uut objekti (antud juhul meie pinda), juhib ta konstruktorit ja see loob uue pinna. Rida "super" kutsub superklassi ja meie puhul on see SurfaceView.

Tagasihelistamise lisamisega suudame sündmusi pealtkuulata.

Nüüd tühistage mõned meetodid:

@Üleserva avaliku tühja pinna muutmine (SurfaceHolderi hoidja, int-vormingus, int-laius, -kõrgus) {} @Alustamine avaliku tühja pinnaCreated (SurfaceHolder-hoidja) {} @Origeerige avaliku tühja pinnagavaataja (SurfaceHolderi hoidja) {}

Põhimõtteliselt võimaldavad need üleklassi (SurfaceView) meetodeid (seega ka nime) alistada. Teil ei tohiks koodis enam punaseid allakriipsutusi olla. Tore.

Lõite just uue klassi ja iga kord, kui sellele viitame, ehitab see teie mängu jaoks lõuendi, et see saaks maalitud. Klassid luua objekte ja meil on vaja veel ühte.

Niitide loomine

Meie uus klass kutsutakse MainThread. Ja selle ülesandeks on niidi loomine. Keerm on põhimõtteliselt nagu paralleelne koodikahvl, mis võib samaaegselt kulgeda ka peamine osa oma koodist. Teil võib korraga olla palju niite, mis võimaldavad asjadel toimuda samaaegselt, mitte järgida ranget jada. See on oluline mängu jaoks, kuna peame tagama, et see töötab tõrgeteta ka siis, kui palju toimub.

Looge oma uus klass täpselt nii, nagu tegite varem ja seekord kavatsetakse seda pikendada Niit. Ehitajas me lihtsalt helistame Super(). Pidage meeles, et see on superklass, mis on niit ja mis suudab meie jaoks kogu raske tõste teha. See on nagu lihtsalt helistatavate nõude pesemise programmi loomine pesumasin().

Kui seda klassi kutsutakse, luuakse see eraldi lõim, mis töötab peamise osana. Ja see on pärit siin et tahame luua oma GameView. See tähendab, et peame viitama ka GameView klassile ja kasutame ka SurfaceHolderit, mis sisaldab lõuendit. Nii et kui lõuend on pind, on SurfaceHolder molbert. Ja GameView on see, mis selle kõik kokku paneb.

Kogu asi peaks välja nägema nii:

avaliku klassi MainThread laiendab lõime {private SurfaceHolder surfaceHolder; privaatne GameView gameView; avalik MainThread (SurfaceHolder surfaceHolder, GameView gameView) {super (); this.surfaceHolder = surfaceHolder; this.gameView = gameView; }}

Schweet. Nüüd on meil GameView ja niit!

Mängusilmuse loomine

Nüüd on meil oma mängu tegemiseks vajalikud toorained, kuid midagi ei juhtu. Siin tuleb mängu mäng silmus sisse. Põhimõtteliselt on see koodisilm, mis läheb ringi ja kontrollib sisestusi ja muutujaid enne ekraani joonistamist. Meie eesmärk on muuta see võimalikult ühtlaseks, nii et kaadrisageduses ei esineks kokutamist ega luksumist, mida uurin veidi hiljem.

Praegu oleme alles MainThread klassi ja me eira mingit meetodit ülemklassist. See on see jooksma.

Ja see läheb natuke midagi sellist:

@Kuva üldsuse tühine jooks () {samal ajal (töötab) {lõuend = null; proovige {lõuend = see.surfaceHolder.lockCanvas (); sünkroonitud (surfaceHolder) {this.gameView.update (); this.gameView.draw (lõuend); }} püüdmine (erand e) {} lõpuks {if (lõuend! = null) {proovige {surfaceHolder.unlockCanvasAndPost (lõuend); } saak (erand e) {e.printStackTrace (); }}}}}

Näete palju allajoonimist, seetõttu peame lisama veel mõned muutujad ja viited. Pea tagasi üles ja lisage:

privaatne SurfaceHolder pinnahoidja; privaatne GameView gameView; eraviisiline loogiline jooks; avalik staatiline lõuend lõuend;

Ärge unustage lõuendit importida. Lõuend on asi, millele me tegelikult joonistame. Mis puutub „lockCanvas”, siis see on oluline, kuna see võimaldab lõuendi sisuliselt külmutada, et saaksime sellele joonistada. See on oluline, sest muidu võib teil olla mitu lõime, mis proovivad sellele korraga joonistada. Lihtsalt teadke, et lõuendi redigeerimiseks peate esmalt tegema lukk lõuend.

Värskendus on meetod, mida kavatseme luua, ja siin juhtub hiljem see lõbus värk.

proovida ja saagi vahepeal on lihtsalt Java nõuded, mis näitavad, et me oleme valmis proovima hakkama saada eranditega (vigadega), mis võivad tekkida juhul, kui lõuend pole veel valmis jne.

Lõpuks tahame, et saaksime oma niidi alustada, kui seda vajame. Selleks vajame siin teist meetodit, mis võimaldab meil asjad käima panna. Just seda jooksmine muutuja on (arvestage, et tõeväärtus on muutuja tüüp, mis on alati tõene või vale). Lisage see meetod jaotisesse MainThread klass:

public void setRunning (loogiline isRunning) {töötab = isRunning; }

Kuid praegusel hetkel tuleks üks asi siiski välja tuua ja see on värskendus. Selle põhjuseks on asjaolu, et me pole veel värskendusmeetodit loonud. Nii et pop tagasi GameView ja lisage nüüd meetod.

avalik tühine värskendus () {}

Samuti peame algus niit! Me teeme seda oma pinnaga loodud meetod:

@Kuiuta avaliku tühja pinnaga loodud (SurfaceHolderi hoidja) {thread.setRunning (true); niit.start (); }

Samuti peame lõime peatama, kui pind hävitatakse. Nagu arvata võis, käsitleme seda jaotises pinnapealne meetod. Kuid nähes, et niidi peatamiseks võib kuluda mitu katset, paneme selle aasa ja kasutame proovida ja saagi jälle. Meeldib nii:

@Külastage avalik tühine pindDestroyed (SurfaceHolderi omanik) {boolean retry = true; while (uuesti proovida) {proovida {thread.setRunning (false); niit.join (); } saak (InterruptedException e) {e.printStackTrace (); } uuesti proovida = vale; }}

Ja lõpuks pöörduge konstruktori poole ja looge kindlasti oma lõime uus eksemplar, vastasel juhul saate kardetud null-osuti erandiks! Ja siis muudame GameView fokuseeritavaks, see tähendab, et see saab sündmustega hakkama.

niit = uus MainThread (getHolder (), see); setFocusable (tõene);

Nüüd sa saad lõpuks testige seda asja tegelikult! See on õige, klõpsake käsku Käivita ja see peaks tegelikult kulgema ilma vigadeta. Valmistuge puhumiseks!

See on… see on… tühi ekraan! Kogu see kood. Tühja ekraani jaoks. Kuid see on tühi ekraan võimalus. Sündmuste käsitlemiseks peate oma pinna püsti ajama ja mängunurgaga mängima. Nüüd jääb üle vaid asi teha. Pole vahet, kas te ei järginud kuni selleni kõik õpetuses sisalduvat. Mõte on selles, et võite kuulsusrikaste mängude tegemiseks selle koodi lihtsalt taaskasutada.

Graafika tegemine

Õige, nüüd on meil joonistamiseks tühi ekraan, peame vaid sellele joonistama. Õnneks on see lihtne osa. Kõik, mida peate tegema, on meie loosimismeetodi alistamine GameView klass ja seejärel lisage ilusad pildid:

@Kuva üldsuse tühine joonistamine (lõuend lõuend) {super.draw (lõuend); if (lõuend! = null) {canvas.drawColor (Color.WHITE); Paint paint = new Paint (); paint.setColor (Color.rgb (250, 0, 0)); canvas.drawRect (100, 100, 200, 200, värv); }}

Käivitage see ja nüüd peaks teil muidu valge valge ekraani vasakus ülanurgas olema päris punane ruut. See on kindlasti edasiminek.

Teoreetiliselt võiksite kogu mängu luua üsna palju, kleepides selle selle meetodi sisse (ja alistades saidil onTouchEvent sisendi haldamiseks), kuid see ei oleks eriti hea viis asjade käiguks. Uue värvi asetamine silmusesse aeglustab asja märkimisväärselt ja isegi siis, kui paneme selle mujale, lisab joonistama meetod muutuks koledaks ja seda oleks keeruline järgida.

Selle asemel on palju mõistlikum käsitleda mänguobjekte oma klassidega. Alustame ühega, mis näitab tähemärki ja see klass kutsutakse CharacterSprite. Minge edasi ja tehke see.

See klass joonistab lõuendile sprite ja see näeb välja selline

avaliku klassi CharacterSprite {privaatne bittkaardi pilt; avalik CharacterSprite (bitmap bmp) {image = bmp; } avalik tühine joonistamine (lõuend lõuend) {canvas.drawBitmap (pilt, 100, 100, null); }}

Nüüd selle kasutamiseks peate esmalt laadima bitikaardi ja seejärel helistama klassist GameView. Lisage viide privaatne tegelaneSprite tegelaneSprite ja siis pinnaga loodud meetod, lisage rida:

characterSprite = uus CharacterSprite (BitmapFactory.decodeResource (getResources (), R.dravable.avdgreen));

Nagu näete, salvestatakse meie laaditav bittkaart ressurssidesse ja seda nimetatakse avdgreeniks (see oli eelmisest mängust). Nüüd peate vaid edastama selle bitmap uue klassis joonistama meetod koos:

iseloomuSprite.draw (lõuend);

Nüüd klõpsake käsul Käivita ja te peaksite nägema, et teie graafiline ekraan ilmub! See on BeeBoo. Joonistasin teda kooliõpikutes.

Mis oleks, kui me tahaksime selle väikese mehe liikuma panna? Lihtne: loome lihtsalt x ja y muutujad tema positsioonide jaoks ja muudame need väärtused an-des värskendus meetod.

Nii et lisage viited oma CharacterSprite ja siis joonistage oma bittkaart aadressil x, y. Looge siin värskendusmeetod ja nüüd proovime lihtsalt:

y ++;

Iga kord, kui mäng silmus töötab, liigutame märgi ekraanil alla. Pidage meeles, y koordinaate mõõdetakse ülalt, nii et 0 on ekraani ülaosa. Muidugi peame helistama värskendus meetod sisse CharacterSprite alates värskendus meetod sisse GameView.

Vajutage uuesti nuppu Esitus ja nüüd näete, et teie pilt jätab ekraanile aeglaselt jälje. Me ei võida veel ühtegi mänguauhinda, kuid see on algus!

Olgu, et asjad korda teha pisut Huvitavam on see, et ma viskan siia lihtsalt mõne pommitava palli koodi. See muudab meie graafilise pildi põrkuma ekraani servadest eemale, nagu need vanad Windowsi ekraanisäästjad. Teate, kummaliselt hüpnootilised.

avalik tühine värskendus () {x + = xVelocity; y + = yVelocity; if ((x> screenWidth - image.getWidth ()) || (x <0)) {xVelocity = xVelocity * -1; } if ((y> screenHeight - image.getHeight ()) || (y <0)) {yVelocity = yVelocity * -1; }}

Peate määratlema ka järgmised muutujad:

privaatne xVelocity = 10; privaatne keskmine väärtus = 5; privaatne int ekraanilaius = Resources.getSystem (). getDisplayMetrics (). widthPixels; private int screenHeight = Resources.getSystem (). getDisplayMetrics (). pikkusPixels;

Optimeerimine

Seal on palju siin on rohkem, alates mängijate sisendi töötlemisest kuni piltide suurendamiseni ja kuni kõigi ekraanil korraga liikuvate tähemärkide haldamiseni. Praegu tegelane põrkab, aga kui väga tähelepanelikult vaadata, on seal kerge mütsakas. See pole kohutav, kuid see, et näete seda palja silmaga, on hoiatus. Kiirus varieerub emulaatoris ka füüsilise seadmega võrreldes palju. Kujutage nüüd ette, mis juhtub, kui teil on tonni toimub ekraanil korraga!

Sellele probleemile on mõned lahendused. Alustuseks tahan luua privaatse täisarvu MainThread ja helistage sellele targetFPS. Selle väärtus on 60.Proovin saada oma mängu sellise kiirusega joosta ja vahepeal kontrollin, kas see on olemas. Selle jaoks tahan ka privaatset topeltkutset keskmineFPS.

Uuendan ka jooksma meetodil, et mõõta, kui kaua iga mängusilm võtab ja seejärel paus seda mängusilmu ajutiselt, kui see on targetFPS-ist eespool. Seejärel arvutame, kui pikk see on nüüd võttis ja siis printida, et saaksime seda logis näha.

@Kulutage avaliku void run () {long startTime; pikk aegMillis; pikk ooteaeg; pikk totalTime = 0; int frameCount = 0; pikk targetTime = 1000 / targetFPS; while (töötab) {startTime = System.nanoTime (); lõuend = null; proovige {lõuend = see.surfaceHolder.lockCanvas (); sünkroonitud (surfaceHolder) {this.gameView.update (); this.gameView.draw (lõuend); }} püüdmine (erand e) {} lõpuks {if (lõuend! = null) {proovige {surfaceHolder.unlockCanvasAndPost (lõuend); } saak (erand e) {e.printStackTrace (); }}} timeMillis = (System.nanoTime () - startTime) / 1000000; waitTime = targetTime - timeMillis; proovige {this.sleep (waitTime); } catch (erand e) {} totalTime + = System.nanoTime () - startTime; frameCount ++; if (frameCount == targetFPS) {keskmineFPS = 1000 / ((totalTime / frameCount) / 1000000); frameCount = 0; totalTime = 0; System.out.println (keskmineFPS); }}}

Nüüd üritab meie mäng lukustada selle FPS-i 60-ni ja peaksite leidma, et see mõõdab tänapäevases seadmes üldiselt üsna ühtlast 58-62 FPS-i. Emulaatoril võite saada teistsuguse tulemuse.

Proovige muuta see 60 väärtuseks 30 ja vaadake, mis juhtub. Mäng aeglustub ja see peaks loe nüüd oma logcatist 30

Mõtte sulgemine

Toimivuse optimeerimiseks saame teha ka muid asju. Selle teema kohta on suurepärane blogipostitus. Proovige hoiduda kunagi Paint'i uute eksemplaride või bitikaartide loomisest ja tehke kõik lähtestamine väljas enne mängu algust.

Kui plaanite luua järgmise populaarse Androidi mängu, siis on olemas kindlasti lihtsamaid ja tõhusamaid viise selle saavutamiseks tänapäeval. Kuid lõuendile joonistamiseks on kindlasti veel kasutusjuhu stsenaariume ja see on väga kasulik oskus oma repertuaari lisada. Loodan, et see juhend on mõnevõrra aidanud ja soovin teile edaspidiseks kodeerimise ettevõtmiseks palju õnne!

JärgmineJava tutvustus algajatele

Uuendu: 22. mai 2019 kell 10.59 ET: Mitme kuu pärat on lõpuk aadaval Tor-braueri eimene tabiilne Androidi väljaanne, mida aab Google Play poet alla laadida. Braueri taga oleva meekonna ...

Qualcomm on ametlikult koorinud kardina tagai napdragon 855 kiibikomplektil, mi eeldatavati toidab enamikku peamii lipulaevade nutitelefone 2019. aatal. elle kiibikomplekti on üna palju uui t...

Põnev