Com escriure el teu primer joc Android a Java

Autora: John Stephens
Data De La Creació: 1 Gener 2021
Data D’Actualització: 19 Ser Possible 2024
Anonim
Публичное собеседование: Junior Java Developer. Пример, как происходит защита проекта после курсов.
Vídeo: Публичное собеседование: Junior Java Developer. Пример, как происходит защита проекта после курсов.

Content


Hi ha moltes maneres de crear un joc per a Android i una manera important és fer-ho des de zero a Android Studio amb Java. Això us proporciona el màxim control sobre com voleu que el vostre joc es vegi i es comporti. El procés us ensenyarà les habilitats que podeu utilitzar en diversos escenaris també, tant si creeu una pantalla de presentació per a una aplicació com si voleu afegeix algunes animacions. Tenint això en compte, aquest tutorial us mostrarà com crear un simple joc en 2D mitjançant Android Studio i Java. Podeu trobar tot el codi i recursos a Github si voleu seguir-lo.

Preparant

Per crear el nostre joc, haurem de tractar alguns conceptes concrets: bucles de joc, fils i teles. Per començar, inicieu Android Studio. Si no el teniu instal·lat, consulteu la nostra introducció completa a Android Studio, que supera el procés d'instal·lació. Ara inicieu un nou projecte i assegureu-vos que trieu la plantilla "Activitat buida". Aquest és un joc, per tant, és clar que no necessiteu elements com el botó FAB per complicar els problemes.


El primer que voleu fer és canviar AppCompatActivity a Activitat. Això vol dir que no utilitzarem les funcions de la barra d’acció.

De la mateixa manera, també volem que el nostre joc sigui a pantalla completa. Afegiu el codi següent a onCreate () abans de la trucada a setContentView ():

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

Tingueu en compte que si escriviu algun codi i es subratlla en vermell, això probablement significa que cal importar una classe. Dit d'una altra manera, heu de dir a Android Studio que voleu utilitzar determinades declaracions i posar-les a disposició. Si simplement feu clic a qualsevol lloc de la paraula subratllada i feu clic a Alt + Enter, us ho fareu automàticament.


Creació de la vista del joc

Podeu utilitzar-se per a aplicacions que utilitzin un script XML per definir la disposició de visualitzacions com botons, imatges i etiquetes. Això és el que la línia setContentView ho està fent per nosaltres.

Però, un cop més, es tracta d’un joc que significa que no necessita tenir finestres del navegador ni visualitzacions de reciclador desplaçades. En lloc d'això, volem mostrar una tela. A Android Studio, un llenç és el mateix que a l'art: és un mitjà que podem utilitzar.

Per tant, canvieu aquesta línia per llegir-la així:

setContentView (nou GameView (això))

Trobareu que es torna a subratllar en vermell. Però ara si premeu Alt + Enter, no podreu importar la classe. En canvi, tens l'opció de crear una classe. Dit d’una altra manera, estem a punt de fer la nostra pròpia classe que definirà el que anirem al llenç. Això és el que ens permetrà dibuixar-nos a la pantalla, més que mostrar visualitzacions preparades.

Per tant, feu clic amb el botó dret al nom del paquet de la vostra jerarquia a l'esquerra i trieu Nova> Classe. Ara se us mostrarà una finestra per crear la vostra classe i l’anireu trucant GameView. A SuperClass, escriviu: android.view.SurfaceView cosa que significa que la classe heretarà mètodes (les seves capacitats) de SurfaceView.

Al quadre Interfície (s), escriureu android.view.SurfaceHolder.Callback. Com en qualsevol classe, ara hem de crear el nostre constructor. Utilitzeu aquest codi:

fil principal de MainThread privat; public GameView (Context context) {super (context); getHolder (). addCallback (això); }

Cada vegada que la nostra classe està cridada a crear un objecte nou (en aquest cas la nostra superfície), executarà el constructor i crearà una nova superfície. La línia "super" truca a la superclasse i, en el nostre cas, és el SurfaceView.

Si afegim Callback, podrem interceptar esdeveniments.

Ara substituïu alguns mètodes:

@Override public void surfaceChanged (titular de SurfaceHolder, format int, amplada int, altura int) {} @Override public void surfaceCreated (} titular de SurfaceHolder) {} @Override public void surfaceDestroyed (titular de SurfaceHolder) {}

Bàsicament, això ens permet substituir (d’aquí el nom) els mètodes de la superclasse (SurfaceView). Ara no hauríeu de tenir més subratlles vermells al vostre codi. Agradable.

Acabeu de crear una nova classe i, cada vegada que ens referim a això, es crearà el llenç perquè el joc sigui pintat. Classes crear objectes i en necessitem un més.

Creació de fils

La nostra nova classe es dirà MainThread. I la seva feina serà crear un fil. Un fil és essencialment com una forquilla de codi paral·lela que pot funcionar simultàniament al costat de principal part del vostre codi. Podeu tenir molts fils funcionant alhora, de manera que es poden produir coses simultàniament i no adherides a una seqüència estricta. Això és important per a un joc, ja que hem d’assegurar-nos que continuï funcionant sense problemes, fins i tot quan hi passen moltes coses.

Creeu la vostra nova classe tal i com vau fer abans i aquesta vegada s’estendrà Fil. Només anem a trucar al constructor super (). Recordeu que aquesta és la super classe, que és Fil, i que pot fer tots els nostres esforços per a nosaltres. Això és com crear un programa per rentar els plats que acaba de trucar rentadora().

Quan s'anomeni aquesta classe, crearà un fil separat que s'execute com a eix fora de la part principal. I és de aquí que volem crear al nostre GameView. Això vol dir que també hem de fer referència a la classe GameView i també estem utilitzant SurfaceHolder que conté el llenç. Així, si el llenç és la superfície, SurfaceHolder és el cavallet. I GameView és el que ho combina tot.

La cosa completa hauria de ser així:

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

Schweet. Ara tenim un GameView i un fil conductor.

Creació del bucle del joc

Ara tenim les matèries primeres que necessitem per fer el nostre joc, però no està passant res. Aquí és on entra el bucle del joc. Bàsicament, es tracta d’un bucle de codi que fa una volta i una volta i comprova les entrades i variables abans de dibuixar la pantalla. El nostre objectiu és fer que sigui el més coherent possible, de manera que no hi hagi tartamudes o singlot en el framerate, que aprofundirem una mica més endavant.

Ara per ara, encara estem a la MainThread classe i anirem a substituir un mètode de la superclasse. Aquest és correr.

I va una mica així:

@Override public void run () {while (en execució) {canvas = null; proveu {canvas = this.surfaceHolder.lockCanvas (); sincronitzada (surfaceHolder) {this.gameView.update (); this.gameView.draw (tela); }} catch (Excepció e) {} finalment {if (canvas! = null) {try {surfaceHolder.unlockCanvasAndPost (tela); } catch (Excepció e) {e.printStackTrace (); }}}}}}

Subratllareu molt, per la qual cosa hem d’afegir algunes referències i variables més. Torneu cap a la part superior i afegiu:

privat SurfaceHolder surfaceHolder; privat GameView gameView; funcionament booleà privat; llenç estàtic públic de lona;

Recordeu importar el llenç. El llenç és el que realment estarem dibuixant. Pel que fa a "lockCanvas", això és important perquè és el que congela essencialment el llenç per permetre'ns dibuixar-lo. És important perquè, en cas contrari, podríeu tenir diversos fils intentant dibuixar-lo alhora. Només heu de saber que per editar el llenç, primer heu de ser pany el llenç.

L'actualització és un mètode que crearem i aquí és el que succeirà després.

El provar i atrapar mentrestant, simplement són els requisits de Java que mostren que estem disposats a provar les excepcions (errors) que es poden produir si el llenç no està preparat, etc.

Finalment, volem iniciar el nostre fil quan ho necessitem. Per fer-ho, necessitarem un altre mètode que ens permeti posar en marxa les coses. Això és això corrent la variable és per (tingueu en compte que un booleà és un tipus de variable que sempre és veritable o fals). Afegiu aquest mètode a la secció MainThread classe:

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

Però en aquest moment, encara cal destacar una cosa i això actualització. Això és perquè encara no hem creat el mètode d’actualització. Així que tornes a aparèixer GameView i ara afegiu mètode.

public void update () {}

També necessitem començar el fil! Ho farem a les nostres superfície Creada mètode:

@Override public void surfaceCreated (titular de SurfaceHolder) {thread.setRunning (true); thread.start (); }

També hem d’aturar el fil quan es destrueix la superfície. Com heu pogut endevinar, ho gestionem a la secció superfícieDestructurada mètode. Però, veient que en realitat es poden dur a terme diversos intents per aturar un fil, ho posarem en bucle i ho farem servir provar i atrapar de nou. Així:

@Override public void surfaceDestroyed (titular de SurfaceHolder) {boolean reintentar = true; while (torna a intentar) {try {thread.setRunning (false); fil.join (); } catch (InterruptException e) {e.printStackTrace (); } reintentar = fals; }}

Finalment, dirigiu-vos al constructor i assegureu-vos de crear la nova instància del vostre fil, si no, obtindreu la temuda excepció del punter nul! I després farem que GameView sigui enfocable, és a dir, que pugui gestionar esdeveniments.

thread = new MainThread (getHolder (), això); setFocusable (true);

Ara pots finalment en realitat prova aquesta cosa! És correcte, feu clic a Executar i feu-ho hauria de realment s’executa sense cap error. Prepareu-vos per ser explotat!

És ... és ... una pantalla en blanc! Tot aquest codi. Per a una pantalla en blanc. Però, aquesta és una pantalla en blanc oportunitat. Tens la teva superfície funcionant amb un bucle de joc per gestionar esdeveniments. Ara només queda que passi. Fins i tot no importa si fins a aquest moment no heu seguit tot el tutorial. L'objectiu és que simplement podeu reciclar aquest codi per començar a fer jocs gloriosos.

Realització de gràfics

Ara, tenim una pantalla en blanc per dibuixar, només ens queda dibuixar-la. Afortunadament, aquesta és la part senzilla. Tot el que heu de fer és substituir el mètode de dibuix en el nostre GameView classe i, a continuació, afegeix algunes fotos boniques:

@Override public void draw (Canvas canvas) {super.draw (tela); if (canvas! = null) {canvas.drawColor (Color.WHITE); Paint paint = Pintura nova (); paint.setColor (Color.rgb (250, 0, 0)); canvas.drawRect (100, 100, 200, 200, pintura); }}

Executeu-ho i ara hauríeu de tenir un quadrat bastant vermell a la part superior esquerra d'una pantalla que no sigui blanca. Sens dubte, és una millora.

Teòricament, podríeu crear pràcticament tot el vostre joc enganxant-lo dins d'aquest mètode (i obtingut de manera important) onTouchEvent per gestionar els inputs), però no seria una manera terriblement bona de fer coses. Situar Paint nou dins del nostre bucle ralentirà considerablement les coses i, fins i tot si ho posem en un altre lloc, afegirà massa codi dibuixar mètode seria lleig i difícil de seguir.

En canvi, té molt més sentit manejar objectes de joc amb les seves pròpies classes. Començarem per un que mostri un personatge i s’anomenarà aquesta classe CharacterSprite. Endavant i fes això.

Aquesta classe dibuixarà un sprite al llenç i així serà

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

Ara per utilitzar-ho, primer haureu de carregar el mapa de bits i, a continuació, trucar a la classe GameView. Afegiu una referència a private CharacterSprite CharacterSprite i després a la superfície Creada mètode, afegeix la línia:

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

Com veieu, el mapa de bits que carreguem s’emmagatzema en recursos i s’anomena avdgreen (provenia d’un joc anterior). Ara només cal que passeu aquest mapa de bits a la nova classe del programa dibuixar mètode amb:

CharacterSprite.draw (tela);

Ara feu clic a Executar i hauríeu de veure que el vostre gràfic apareix a la pantalla. Es tracta de BeeBoo. Jo solia dibuixar-lo als meus llibres de text de l’escola.

Què passaria si volguéssim fer que aquest petit es mogués? Senzill: només creem variables x i y per a les seves posicions i després canviem aquests valors en an actualització mètode.

Afegiu les referències al vostre nom CharacterSprite i, a continuació, dibuixi el mapa de bits de x, y. Creeu el mètode d’actualització aquí i de moment només intentarem:

y ++;

Cada cop que es publiqui el bucle del joc, desplaçarem el personatge per la pantalla. Recordeu, i Les coordenades es mesuren des de la part superior de manera que 0 és la part superior de la pantalla. Per descomptat, hem de trucar al actualització mètode en CharacterSprite de la actualització mètode en GameView.

Torna a prémer la reproducció i ara veuràs que la teva imatge descobreix lentament la pantalla. Encara no hem guanyat premis del joc, però és un començament!

D'acord, per fer coses lleugerament més interessant, només vaig a deixar anar aquí el codi "bola rebot". Això farà que el nostre rebot gràfic al voltant de la pantalla fora de les vores, com els antics salvapantalles de Windows. Ja ho sabeu, els estranyament hipnòtics.

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

També haureu de definir aquestes variables:

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

Optimització

N’hi ha molt més per aprofundir aquí, des de la manipulació de l’entrada del reproductor, fins a l’escala d’imatges, fins a aconseguir que molts personatges es desplacin alhora per la pantalla. Ara mateix, el personatge està rebotant, però si mires molt de prop hi ha una tartamudesa lleugera. No és terrible, però el fet de veure-ho a simple vista és un signe d’avís. La velocitat també varia molt en l'emulador en comparació amb un dispositiu físic. Ara imagina què passa quan tens tones passant a la pantalla alhora!

Hi ha algunes solucions a aquest problema. Amb el que vull fer és crear un nombre enter privat MainThread i truqueu a això targetFPS. Això tindrà el valor de 60.Intentaré que el meu joc funcioni a aquesta velocitat i, mentrestant, comprovaré que sigui. Per això, també vull un doble privat anomenat mitjanaFPS.

També actualitzaré el programa correr mètode per mesurar el temps que triga cada bucle de joc i després fer una pausa aquest bucle de joc temporalment si està per davant del targetFPS. A continuació, calcularà quant temps ara agafeu i, a continuació, imprimiu-ho de manera que el puguem veure al registre.

@Override public void run () {long startTime; temps llargMillis; llarg esperaTime; llarg totalTime = 0; int frameCount = 0; llarg targetTime = 1000 / targetFPS; while (en execució) {startTime = System.nanoTime (); tela = nul; proveu {canvas = this.surfaceHolder.lockCanvas (); sincronitzada (surfaceHolder) {this.gameView.update (); this.gameView.draw (tela); }} catch (Excepció e) {} finalment {if (canvas! = null) {try {surfaceHolder.unlockCanvasAndPost (tela); } catch (Excepció e) {e.printStackTrace (); }}} timeMillis = (System.nanoTime () - startTime) / 1000000; waitTime = targetTime - timeMillis; proveu {this.sleep (waitTime); } catch (Excepció e) {} totalTime + = System.nanoTime () - startTime; frameCount ++; if (frameCount == targetFPS) {averageFPS = 1000 / ((totalTime / frameCount) / 1000000); frameCount = 0; totalTime = 0; System.out.println (averageFPS); }}}

Ara, el nostre joc està intentant bloquejar el FPS a 60 i hauríeu de trobar que generalment mesura un nivell pràctic constant de 58-62 FPS en un dispositiu modern. Tot i que a l'emulador podríeu obtenir un resultat diferent.

Proveu de canviar això de 60 a 30 i vegeu què passa. El joc s’alenteix hauria de ara llegiu 30 al vostre logcat.

Pensaments de cloenda

Hi ha algunes altres coses que podem fer per optimitzar el rendiment. Hi ha una publicació al bloc sobre aquest tema. Proveu d’abstenir-vos de crear mai noves instàncies de Paint o mapes de bits dins del bucle i feu tot el que es inicialitzi fora abans que comenci el joc.

Si teniu previst crear el proper joc Android amb èxit, n'hi ha certament formes més fàcils i eficients de fer-ho en aquests dies. Però, definitivament, encara hi ha escenaris de casos per poder utilitzar-se en un llenç i és una habilitat molt útil per afegir al vostre repertori. Espero que aquesta guia us hagi ajudat una mica i us desitgem la millor sort en els vostres propers esdeveniments de codificació.

PròximGuia per a principiants a Java

Veient com ’han convertit el telèfon intel·ligent mé popular durant el darrer dotze any, penaria que el reproductor de MP3 e convertiria en una nota a peu de pàgina. No ha etat aix...

A partir de 2.099 dòlar, aquet ordinador portàtil ultra prim e va preentar al gener, meurava 0,75 polzade de gruix i pea 4,96 lliure. Porta una pantalla de nivell IP de 17,3 polzade amb una ...

Articles Per A Tu