Cum să scrii primul tău joc Android în Java

Autor: John Stephens
Data Creației: 1 Ianuarie 2021
Data Actualizării: 19 Mai 2024
Anonim
Cum să scrii primul tău joc Android în Java - Aplicaţii
Cum să scrii primul tău joc Android în Java - Aplicaţii

Conţinut


Există o mulțime de moduri de a crea un joc pentru Android, iar o modalitate importantă este de a o face de la zero în Android Studio cu Java. Acest lucru vă oferă un control maxim asupra modului în care doriți ca jocul dvs. să arate și să se comporte, iar procesul vă va învăța abilități pe care le puteți utiliza și într-o serie de alte scenarii - indiferent dacă creați un ecran splash pentru o aplicație sau doriți doar să adăugați câteva animații. Ținând cont de acest lucru, acest tutorial vă va arăta cum puteți crea un joc 2D simplu folosind Android Studio și Java. Puteți găsi toate codurile și resursele la Github dacă doriți să le urmăriți.

Configurare

Pentru a crea jocul nostru, va trebui să avem de-a face cu câteva concepte specifice: bucle de joc, fire și pânze. Pentru început, porniți Android Studio. Dacă nu îl aveți instalat, consultați introducerea noastră completă la Android Studio, care trece peste procesul de instalare. Acum începeți un nou proiect și asigurați-vă că alegeți șablonul „Activitate goală”. Acesta este un joc, așa că desigur nu aveți nevoie de elemente precum butonul FAB care complică problemele.


Primul lucru pe care vrei să-l faci este să te schimbi AppCompatActivity la Activitate. Aceasta înseamnă că nu vom folosi funcțiile barei de acțiune.

În mod similar, dorim să facem și jocul nostru pe ecran complet. Adăugați următorul cod la onCreate () înainte de apelul la setContentView ():

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

Rețineți că, dacă scrieți un cod și acesta este subliniat în roșu, asta înseamnă probabil că trebuie să importați o clasă. Cu alte cuvinte, trebuie să spuneți Android Studio că doriți să utilizați anumite afirmații și să le faceți disponibile. Dacă faceți clic pe oriunde pe cuvântul subliniat și apoi apăsați Alt + Enter, atunci asta se va face automat!

Crearea vizualizării jocului

Puteți fi folosit pentru aplicațiile care folosesc un script XML pentru a defini aspectul vizualizărilor precum butoanele, imaginile și etichetele. Aceasta este ceea ce linia setContentView face pentru noi.


Dar, din nou, acesta este un joc ceea ce înseamnă că nu este necesar să aveți ferestrele browserului sau defilarea vizualizărilor reciclatorului. În loc de asta, vrem să arătăm o pânză în schimb. În Android Studio, o pânză este la fel ca în artă: este un mediu pe care îl putem folosi.

Așa că schimbați această linie pentru a citi așa:

setContentView (nou GameView (acest))

Veți găsi că aceasta este din nou subliniată roșu. Dar acum dacă apăsați Alt + Enter, nu aveți opțiunea de a importa clasa. În schimb, aveți opțiunea să crea o clasa. Cu alte cuvinte, suntem pe cale să facem propria noastră clasă care să definească ce va merge pe pânză. Acest lucru ne va permite să ne atragem pe ecran, mai degrabă decât să afișăm vizualizări gata făcute.

Așa că faceți clic dreapta pe numele pachetului din ierarhia dvs. peste stânga și alegeți Nou> Clasa. Acum vi se va prezenta o fereastră pentru a crea clasa dvs. și veți apela la aceasta GameView. În SuperClass, scrieți: android.view.SurfaceView ceea ce înseamnă că clasa va moșteni metode - capacitățile sale - de la SurfaceView.

În caseta Interfață (e), veți scrie android.view.SurfaceHolder.Callback. Ca în orice clasă, acum trebuie să ne creăm constructorul. Utilizați acest cod:

thread principal MainThread; public GameView (Context context) {super (context); . GetHolder () addCallback (aceasta); }

De fiecare dată când clasa noastră este chemată să creeze un obiect nou (în acest caz suprafața noastră), acesta va rula constructorul și va crea o nouă suprafață. Linia „super” numește superclasa și în cazul nostru, adică SurfaceView.

Adăugând Callback, vom putea intercepta evenimente.

Anulați acum unele metode:

@Override public void surfaceChanged (suport de SurfaceHolder, format int, lățime int, înălțime int) {} @Override public void surfaceCreated (SurfaceHolder holder) {} @Override public void surfaceDestroyed (titularul SurfaceHolder) {}

Practic, acestea ne permit să înlocuim (de aici și numele) metodele din superclasa (SurfaceView). Acum ar trebui să nu mai aveți sublinieri roșii în codul dvs. Frumos.

Tocmai ai creat o clasă nouă și de fiecare dată când ne referim la aceasta, aceasta va construi pânza pentru ca jocul tău să fie pictat. Clase crea obiecte și mai avem nevoie de unul.

Crearea firelor

Noua noastră clasă va fi numită MainThread. Iar meseria sa va fi să creeze o fire. Un fir este în esență ca o furcă paralelă de cod care poate rula simultan alături de principal o parte din codul dvs. Puteți avea o mulțime de fire care rulează toate simultan, permițând astfel lucrurile să apară simultan, mai degrabă decât să adere la o secvență strictă. Acest lucru este important pentru un joc, deoarece trebuie să ne asigurăm că acesta continuă să funcționeze fără probleme, chiar și atunci când se întâmplă multe.

Creează-ți noua clasă așa cum ai făcut înainte și de data aceasta se va extinde Fir. La constructor tocmai vom apela super(). Amintiți-vă, aceasta este super-clasă, care este Thread, și care poate face toată ridicarea grea pentru noi. Acest lucru este ca și cum ai crea un program de spălat vasele care doar sună mașină de spălat().

Când se numește această clasă, se va crea un thread separat care va fi un offshoot al principalului lucru. Și este de la aici că vrem să ne creăm GameView. Asta înseamnă că trebuie să facem referință și la clasa GameView și folosim și SurfaceHolder, care conține panza. Deci, dacă pânza este suprafața, SurfaceHolder este șevaletul. Și GameView este ceea ce face totul împreună.

Lucrul complet ar trebui să arate astfel:

public class MainThread extinde Thread {private SurfaceHolder surfaceHolder; privat GameView gameView; public MainThread (SurfaceHolder surfaceHolder, GameView gameView) {super (); this.surfaceHolder = surfaceHolder; this.gameView = gameView; }}

Schweet. Avem acum un GameView și un fir!

Crearea buclei de joc

Avem acum materiile prime de care avem nevoie pentru a ne face jocul, dar nu se întâmplă nimic. Aici intervine bucla de joc. Practic, aceasta este o buclă de cod care merge în jurul și rotund și verifică intrările și variabilele înainte de a desena ecranul. Scopul nostru este de a face acest lucru cât mai consecvent posibil, astfel încât să nu existe bâlbâieli sau sughițuri în framerate, pe care le voi explora puțin mai târziu.

Deocamdată, suntem încă în MainThread clasă și vom trece peste o metodă din superclasa. Acesta este alerga.

Și merge puțin așa:

@ Supraveghează public void run () {while (running) {canvas = null; încercați {canvas = this.surfaceHolder.lockCanvas (); sincronizat (surfaceHolder) {this.gameView.update (); this.gameView.draw (pânză); }} catch (Excepție e) {} în sfârșit {if (canvas! = null) {try {surfaceHolder.unlockCanvasAndPost (canvas); } captură (Excepție e) {e.printStackTrace (); }}}}}}

Vei vedea mult sublinierea, deci trebuie să adăugăm alte variabile și referințe. Întoarceți-vă în sus și adăugați:

privat SurfaceHolder surfaceHolder; privat GameView gameView; alergare booleană privată; pânză publică Canvas static;

Nu uitați să importați Canvas. Pânza este lucrul pe care îl vom desena de fapt. În ceea ce privește „lockCanvas”, acest lucru este important, deoarece este ceea ce îngheață în mod esențial panza pentru a ne permite să ne atragem de pe ea. Acest lucru este important pentru că, în caz contrar, ai putea avea mai multe fire care încearcă să-l atragă simultan. Știți doar că pentru a edita pânza, trebuie mai întâi blocare panza.

Actualizarea este o metodă pe care urmează să o creăm și aici este locul în care lucrurile distractive se vor întâmpla ulterior.

încerca și captură între timp sunt pur și simplu cerințe de Java care arată că suntem dispuși să încercăm să facem față excepțiilor (erorilor) care ar putea apărea dacă panza nu este gata etc.

În cele din urmă, dorim să putem începe firul nostru atunci când avem nevoie. Pentru a face acest lucru, vom avea nevoie aici de o altă metodă care să ne permită să punem în mișcare lucrurile. Aceasta este ceea ce alergare variabilă este pentru (rețineți că un boolean este un tip de variabilă care este doar întotdeauna adevărat sau fals). Adăugați această metodă la MainThread clasă:

public void setRunning (boolean isRunning) {running = isRunning; }

Dar în acest moment, un lucru ar trebui totuși subliniat și acesta este Actualizați. Acest lucru se datorează faptului că nu am creat încă metoda de actualizare. Așadar, reveniți la GameView și acum adaugă metoda.

public void update () {}

De asemenea, trebuie să start firul! Vom face acest lucru în cadrul nostru surfaceCreated metodă:

@ Suprafață public void surfaceCreated (SurfaceHolder holder) {thread.setRunning (adevărat); thread.start (); }

De asemenea, trebuie să oprim firul atunci când suprafața este distrusă. După cum ați putut ghici, noi ne ocupăm de acest lucru în surfaceDestroyed metodă. Dar, văzând că acesta poate încerca de fapt mai multe încercări de a opri o fire, vom pune acest lucru în buclă și vom folosi încerca și captură din nou. Ca astfel:

@ Supraversați public void surfaceDestroyed (titularul SurfaceHolder) {reîncercare booleană = true; while (reîncercare) {try {thread.setRunning (false); thread.join (); } catch (InterruptException e) {e.printStackTrace (); } reîncercare = fals; }}

Și în sfârșit, îndreptați-vă către constructor și asigurați-vă că creați noua instanță a thread-ului dvs., altfel veți primi temuta excepție de pointer nul! Și atunci vom face ca GameView să fie focalizat, ceea ce înseamnă că poate gestiona evenimente.

thread = new MainThread (getHolder (), acesta); setFocusable (true);

Acum poti in cele din urma testează de fapt acest lucru! Așa este, faceți clic pe executați ar trebui să rulează de fapt fără nicio eroare. Pregătește-te pentru a fi aruncat în aer!

Este ... este ... un ecran gol! Tot acel cod. Pentru un ecran gol. Dar, acesta este un ecran gol al oportunitate. Aveți suprafața în funcțiune cu o buclă de joc pentru a gestiona evenimente. Acum nu mai rămâne decât să se întâmple lucrurile. Nici nu contează dacă nu ați urmărit totul în tutorial până în acest moment. Ideea este că puteți pur și simplu să reciclați acest cod pentru a începe să faceți jocuri glorioase!

Realizarea unei grafici

Acum, avem un ecran pe care să-l desenăm, tot ce trebuie să facem este să îl desenăm. Din fericire, aceasta este partea simplă. Tot ce trebuie să faceți este să înlocuiți metoda de remiză din cadrul nostru GameView clasa și apoi adăugați câteva poze frumoase:

@ Supraveghează public void draw (Canvas canvas) {super.draw (pânză); if (canvas! = null) {canvas.drawColor (Color.WHITE); Paint paint = Paint nou (); paint.setColor (Color.rgb (250, 0, 0)); canvas.drawRect (100, 100, 200, 200, vopsea); }}

Rulați acest lucru și acum ar trebui să aveți un pătrat destul de roșu în partea stângă sus a unui ecran altfel alb. Aceasta este cu siguranță o îmbunătățire.

Teoretic ai putea să creezi destul de mult întregul tău joc prin lipirea lui în cadrul acestei metode (și de o importanță superioară onTouchEvent să gestionați contribuția), dar aceasta nu ar fi o modalitate extrem de bună de a aborda lucrurile. Plasarea noii vopsea în bucla noastră va încetini lucrurile considerabil și chiar dacă vom pune acest lucru în altă parte, adăugând prea mult cod a desena metoda ar deveni urâtă și dificil de urmat.

În schimb, are mult mai mult sens să te descurci cu obiecte de joc cu propriile clase. Vom începe cu unul care arată un personaj și această clasă va fi numită CharacterSprite. Mergeți înainte și faceți asta.

Această clasă va atrage o pictură pe pânză și va arăta așa

public class CharacterSprite {private Bitmap image; public CharacterSprite (Bitmap bmp) {image = bmp; } public void draw (Canvas canvas) {canvas.drawBitmap (imagine, 100, 100, nul); }}

Acum pentru a utiliza acest lucru, va trebui să încărcați mai întâi bitmap-ul și apoi să apelați clasa din GameView. Adăugați o referință la private CharacterSprite CharacterSprite și apoi în surfaceCreated metodă, adăugați linia:

CharacterSprite = new CharacterSprite (BitmapFactory.decodeResource (getResources (), R.drawable.avdgreen));

După cum vedeți, bitmap-ul pe care îl încărcăm este stocat în resurse și se numește avdgreen (a fost dintr-un joc anterior). Acum tot ce trebuie să faceți este să treceți acea hartă de bit la noua clasă din a desena metoda cu:

characterSprite.draw (pânză);

Acum faceți clic pe Run și ar trebui să vedeți graficul dvs. apărut pe ecran! Acesta este BeeBoo. Îl deseneam în manualele școlare.

Dacă am vrea să-l facem pe acest tip mic să se miște? Simplu: creăm doar variabile x și y pentru pozițiile sale și apoi schimbăm aceste valori într-un Actualizați metodă.

Așa că adăugați referințele la dvs. CharacterSprite și apoi desenează-ți harta de bit la X y. Creați aici metoda de actualizare și deocamdată vom încerca:

y ++;

De fiecare dată când rulează bucla jocului, vom muta personajul pe ecran. Tine minte, y coordonatele sunt măsurate de sus, deci 0 este partea de sus a ecranului. Desigur, trebuie să apelăm la Actualizați metoda în CharacterSprite de la Actualizați metoda în GameView.

Apăsați din nou redarea și acum veți vedea că imaginea dvs. urmărește încet ecranul. Încă nu câștigăm niciun premiu de joc, dar este un început!

Bine, să fac lucruri puțin mai interesant, o să arunc aici câteva coduri „bile bontate”. Acest lucru va face să răsărim graficul nostru în jurul ecranului în afara marginilor, ca și acele vechi screensavere Windows. Știi, cei ciudat de hipnotici.

public void update () {x + = xVelocity; y + = yVelocitate; if ((x & gt; screenWidth - image.getWidth ()) || (x & lt; 0)) {xVelocity = xVelocity * -1; } if ((y & gt; screenHeight - image.getHeight ()) || (y & lt; 0)) {yVelocity = yVelocity * -1; }}

De asemenea, va trebui să definiți aceste variabile:

private int xVelocity = 10; private int yVelocity = 5; private int screenWidth = Resources.getSystem (). getDisplayMetrics (). widthPixels; private int screenHeight = Resources.getSystem (). getDisplayMetrics (). heightPixels;

Optimizare

Există mulțime mai mult pentru a ne dedica aici, de la manipularea intrării jucătorului, la scalarea imaginilor, la gestionarea multor personaje care se mișcă pe ecran simultan. Momentan, personajul este săritor, dar dacă te uiți foarte atent, este ușor bâlbâie. Nu este groaznic, dar faptul că îl poți vedea cu ochiul liber este un semn de avertizare. Viteza variază foarte mult și la emulator, comparativ cu un dispozitiv fizic. Acum imaginați-vă ce se întâmplă când aveți tone mergând pe ecran deodată!

Există câteva soluții la această problemă. Ce vreau să fac pentru a începe este să creez un număr întreg privat în MainThread și sună asta targetFPS. Aceasta va avea valoarea de 60.Voi încerca să fac ca jocul meu să funcționeze cu această viteză și, între timp, voi verifica să fie sigur. Pentru asta, vreau și un dublu privat numit averageFPS.

O să actualizez și alerga metoda pentru a măsura cât timp durează fiecare buclă de joc și apoi pauză acea buclă de joc temporar dacă este înaintea targetului FPS. Vom calcula atunci cât timp acum a luat și apoi a imprima asta, astfel încât să o putem vedea în jurnal.

@ Supraveghează public void run () {long startTime; mult timpMillis; lungă așteptare Timp; long totalTime = 0; int frameCount = 0; long targetTime = 1000 / targetFPS; while (running) {startTime = System.nanoTime (); pânză = nul; încercați {canvas = this.surfaceHolder.lockCanvas (); sincronizat (surfaceHolder) {this.gameView.update (); this.gameView.draw (pânză); }} catch (Excepție e) {} în sfârșit {if (canvas! = null) {try {surfaceHolder.unlockCanvasAndPost (canvas); } captură (Excepție e) {e.printStackTrace (); }}} timeMillis = (System.nanoTime () - startTime) / 1000000; waitTime = targetTime - timeMillis; încercați {this.sleep (waitTime); } catch (Excepție e) {} totalTime + = System.nanoTime () - startTime; frameCount ++; if (frameCount == targetFPS) {averageFPS = 1000 / ((totalTime / frameCount) / 1000000); frameCount = 0; totalTime = 0; System.out.println (averageFPS); }}}

Acum, jocul nostru încearcă să blocheze FPS-ul la 60 și ar trebui să constatați că acesta măsoară în general o cantitate destul de constantă de 58-62 FPS pe un dispozitiv modern. Pe emulator, deși este posibil să obțineți un rezultat diferit.

Încercați să schimbați 60 - 30 și vedeți ce se întâmplă. Jocul încetinește și ar trebui să citeste acum 30 in jurnalul tau.

Gânduri de închidere

Mai putem face și alte lucruri pentru a optimiza performanța. Există aici o postare excelentă pe blog. Încercați să vă abțineți de la a crea vreodată instanțe noi de Paint sau bitmap-uri în buclă și faceți toate inițializările in afara înainte de a începe jocul.

Dacă intenționați să creați următorul joc Android, atunci există cu siguranță modalități mai ușoare și mai eficiente de a merge despre asta în aceste zile. Cu toate acestea, există cu siguranță încă scenarii de caz pentru a putea să te atragi pe o pânză și este o abilitate extrem de utilă de adăugat în repertoriul tău. Sper că acest ghid a ajutat oarecum și vă doresc cel mai mult noroc în viitoarele dvs. proiecte de codare!

Următor →Ghidul unui începător în Java

Android ete tot depre peronalizare, dar multe dipozitive vin în continuare cu dimeniuni de pictograme fixe. Dacă pot fi redimenionate, opțiunea ete de obicei acună într-un loc necunocut din ...

Acer tocmai a introdu Chromebook 315 în cadrul expoziției CE 2019 din La Vega. Programat ă ajungă în acet trimetru, aceta va fi primul Chromebook al companiei bazat pe un proceor „APU” all-i...

Cea Mai Citire