Jak napsat první hru pro Android v Javě

Autor: John Stephens
Datum Vytvoření: 1 Leden 2021
Datum Aktualizace: 19 Smět 2024
Anonim
Jak napsat první hru pro Android v Javě - Aplikace
Jak napsat první hru pro Android v Javě - Aplikace

Obsah


Existuje spousta způsobů, jak vytvořit hru pro Android, a jedním důležitým způsobem je to od nuly v Android Studio s Java. To vám dává maximální kontrolu nad tím, jak chcete, aby vaše hra vypadala a chovala se, a proces vás naučí dovednosti, které můžete použít v celé řadě dalších scénářů - ať už vytváříte úvodní obrazovku pro aplikaci, nebo chcete pouze přidat nějaké animace. S ohledem na to vám tento tutoriál ukáže, jak vytvořit jednoduchou 2D hru pomocí Android Studio a Java. Všechny kódy a zdroje najdete v Githubu, pokud je chcete sledovat.

Nastavení

Abychom mohli vytvořit naši hru, musíme se vypořádat s několika konkrétními pojmy: herní smyčky, vlákna a plátna. Začněte tím, že spustíte Android Studio. Pokud ji nemáte nainstalovanou, podívejte se na náš úplný úvod do aplikace Android Studio, která prochází procesem instalace. Nyní spusťte nový projekt a ujistěte se, že jste vybrali šablonu „Prázdná aktivita“. Toto je hra, takže samozřejmě nepotřebujete prvky, jako je tlačítko FAB, které komplikuje záležitosti.


První věc, kterou chcete udělat, je změnit AppCompatActivity na Aktivita. To znamená, že nebudeme používat funkce panelu akcí.

Stejně tak chceme, aby naše hra byla celá obrazovka. Přidejte následující kód do onCreate () před voláním setContentView ():

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

Pokud napíšete nějaký kód a bude podtržen červeně, pravděpodobně to znamená, že budete muset importovat třídu. Jinými slovy, musíte Android Studio sdělit, že chcete použít určitá prohlášení a zpřístupnit je. Pokud kliknete kdekoli na podtržené slovo a stisknete Alt + Enter, bude to automaticky za vás!

Vytvoření zobrazení hry

Můžete být zvyklí na aplikace, které používají XML skript k definování rozvržení pohledů, jako jsou tlačítka, obrázky a štítky. To je ten řádek setContentView dělá pro nás.


Je to však opět hra, což znamená, že nemusí mít okna prohlížeče ani posouvat zobrazení recyklátorů. Místo toho chceme místo toho ukázat plátno. V Android Studio je plátno stejné jako v umění: je to médium, na které můžeme čerpat.

Takže změňte tento řádek takto:

setContentView (nový GameView (toto))

Zjistíte, že je to opět podtrženo červeně. Ale Nyní Pokud stisknete Alt + Enter, nemáte možnost importovat třídu. Místo toho máte možnost vytvořit třída. Jinými slovy, chystáme se vytvořit vlastní třídu, která bude definovat, co se chystá na plátně. To nám umožní čerpat na obrazovku a ne pouze ukazovat hotová zobrazení.

Takže klikněte pravým tlačítkem myši na název balíčku ve vaší hierarchii na levé straně a vyberte Nový> Třída. Nyní vám bude nabídnuto okno pro vytvoření vaší třídy a budete to nazývat GameView. Do SuperClass napište: android.view.SurfaceView což znamená, že třída zdědí metody - své schopnosti - od SurfaceView.

Do pole Interface (s) napíšete android.view.SurfaceHolder.Callback. Stejně jako u jakékoli třídy i nyní musíme vytvořit našeho konstruktéra. Použijte tento kód:

soukromé vlákno MainThread; public GameView (kontextový kontext) {super (kontext); getHolder (). addCallback (this); }

Pokaždé, když je naše třída povolána, aby vytvořila nový objekt (v tomto případě náš povrch), spustí konstruktor a vytvoří nový povrch. Řádek „super“ volá nadřazenou třídu av našem případě je to SurfaceView.

Přidáním zpětného volání můžeme zachytit události.

Nyní potlačte některé metody:

@Override public void surfaceChanged (držitel SurfaceHolder, formát int, šířka int, výška int) {} @Override public void surfaceCreated (držitel SurfaceHolder) {} @Override public void surfaceDestroyed (držitel SurfaceHolder) {}

V zásadě nám umožňují přepsat (odtud název) metody v nadřazené třídě (SurfaceView). Nyní byste v kódu neměli mít žádné červené podtržení. Pěkný.

Právě jste vytvořili novou třídu a pokaždé, když se na to budeme odkazovat, vytvoří se pro vaši hru plátno, na které se bude malovat. Třídy vytvořit objekty a potřebujeme ještě jeden.

Vytváření vláken

Naše nová třída se bude jmenovat MainThread. Jeho úkolem bude vytvořit vlákno. Vlákno je v podstatě jako paralelní vidlička kódu, která může běžet současně podél hlavní část vašeho kódu. Můžete mít najednou spuštěno mnoho podprocesů, což umožňuje, aby se věci objevovaly současně, spíše než se držely přísné posloupnosti. To je důležité pro hru, protože se musíme ujistit, že běží plynule, i když se hodně děje.

Vytvořte novou třídu stejně jako předtím a tentokrát se bude rozšiřovat Vlákno. Ve konstruktoru prostě zavoláme super (). Pamatujte, že to je super třída, kterou je Thread, a která pro nás může udělat vše těžké. Je to jako vytvořit program na mytí nádobí, které právě volá pračka().

Když se tato třída nazývá, vytvoří se samostatný podproces, který bude běžet jako odnož hlavní věci. A je to od tady že chceme vytvořit náš GameView. To znamená, že musíme také odkazovat na třídu GameView a také používáme SurfaceHolder, který obsahuje plátno. Takže pokud je plátno povrch, stojan je SurfaceHolder. A GameView je to, co vše spojuje dohromady.

Celá věc by měla vypadat takto:

public class MainThread rozšiřuje vlákno {private SurfaceHolder surfaceHolder; soukromý GameView gameView; public MainThread (SurfaceHolder surfaceHolder, GameView gameView) {super (); this.surfaceHolder = povrchHolder; this.gameView = gameView; }}

Schweet. Nyní máme GameView a vlákno!

Vytvoření herní smyčky

Nyní máme suroviny, které potřebujeme k výrobě naší hry, ale nic se neděje. Zde přichází herní smyčka. V zásadě se jedná o smyčku kódu, která obchází kolo a kontroluje vstupy a proměnné před nakreslením obrazovky. Naším cílem je, aby to bylo co nejkonzistentnější, aby ve framerátu nebyly žádné koktání nebo škytavost, kterou prozkoumám o něco později.

Prozatím jsme stále v MainThread třídy a přepíšeme metodu z nadřazené třídy. Tohle je běh.

A vypadá to trochu takto:

@Override public void run () {while (running) {canvas = null; try {canvas = this.surfaceHolder.lockCanvas (); synchronized (surfaceHolder) {this.gameView.update (); this.gameView.draw (canvas); }} catch (Výjimka e) {} konečně {if (canvas! = null) {try {surfaceHolder.unlockCanvasAndPost (canvas); } catch (Výjimka e) {e.printStackTrace (); }}}}}

Uvidíte mnoho podtržení, takže musíme přidat další proměnné a odkazy. Vraťte se na vrchol a přidejte:

private SurfaceHolder surfaceHolder; soukromý GameView gameView; soukromý booleovský běh; veřejné statické plátno;

Nezapomeňte importovat plátno. Canvas je věc, na kterou budeme skutečně kreslit. Pokud jde o „lockCanvas“, je to důležité, protože právě to v podstatě zamrzne na plátně, což nám umožňuje čerpat z něj. To je důležité, protože v opačném případě byste se mohli pokusit čerpat více vláken současně. Stačí vědět, že pro úpravu plátna musíte nejprve zámek plátno.

Aktualizace je metoda, kterou se chystáme vytvořit, a to je místo, kde se zábavné věci stanou později.

Snaž se a úlovek mezitím jsou jednoduše požadavky Java, které ukazují, že jsme ochotni vyzkoušet výjimky (chyby), ke kterým může dojít, pokud plátno není připraveno atd.

Nakonec chceme být schopni zahájit naše vlákno, když to potřebujeme. K tomu potřebujeme jinou metodu, která nám umožní uvést věci do pohybu. To je to, co běh proměnná je pro (všimněte si, že logická proměnná je typ proměnné, která je vždy pravdivá nebo nepravdivá). Přidejte tuto metodu do MainThread třída:

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

V tomto bodě je však třeba ještě zdůraznit jednu věc a to je Aktualizace. Je to proto, že jsme dosud nevytvořili metodu aktualizace. Tak se vraťte zpět GameView a nyní přidejte metodu.

public void update () {}

Musíme také Start vlákno! Uděláme to v našem povrchVytvořeno metoda:

@Override public void surfaceCreated (Držitel SurfaceHolder) {thread.setRunning (true); thread.start (); }

Musíme také zastavit vlákno, když je povrch zničen. Jak jste možná uhodli, my to zvládneme v povrchDestroyed metoda. Ale protože to může ve skutečnosti trvat několik pokusů zastavit vlákno, budeme to dát do smyčky a použít Snaž se a úlovek znovu. Jako tak:

@Override public void surfaceDestroyed (držitel SurfaceHolder) {boolean retry = true; while (opakovat) {try {thread.setRunning (false); thread.join (); } catch (InterruptedException e) {e.printStackTrace (); } opakovat = false; }}

A konečně, zamiřte k konstruktoru a ujistěte se, že vytvoříte novou instanci svého vlákna, jinak získáte obávanou výjimku nulového ukazatele! A pak uděláme GameView zaměřitelným, což znamená, že zvládne události.

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

Teď můžeš Konečně tuto věc skutečně vyzkoušejte! To je pravda, klikněte na tlačítko Spustit a je to by měl ve skutečnosti běží bez jakýchkoli chyb. Připravte se na útěk!

Je to ... je to ... prázdná obrazovka! Celý ten kód. Pro prázdnou obrazovku. Ale toto je prázdná obrazovka příležitost. Máte povrch a běží s herní smyčkou pro zpracování událostí. Nyní zbývá jen to, aby se věci staly. Nezáleží ani na tom, zda jste až do tohoto bodu nenasledovali vše v tutoriálu. Jde o to, že můžete jednoduše recyklovat tento kód a začít dělat skvělé hry!

Dělám grafiku

Dobrá, nyní máme prázdnou obrazovku, kterou musíme čerpat, vše, co musíme udělat, je čerpat ji. Naštěstí je to jednoduchá část. Vše, co musíte udělat, je přepsat metodu remízy v našem GameView třídy a pak přidejte pár pěkných obrázků:

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

Spusťte toto a nyní byste měli mít pěkně červený čtverec v levém horním rohu jinak bílé obrazovky. To je určitě zlepšení.

Teoreticky byste mohli celou svou hru vytvořit tak, že ji vložíte do této metody (a převažujete) onTouchEvent zvládnout vstup), ale nebyl by to strašně dobrý způsob, jak jít o věcech. Vložení nové barvy do naší smyčky výrazně zpomalí věci, i když to dáme jinam, přidáme do kódu příliš mnoho kódu kreslit metoda by byla ošklivá a obtížně dodržitelná.

Místo toho má mnohem větší smysl manipulovat s herními objekty s jejich vlastními třídami. Začneme tím, který ukazuje postavu a tato třída bude nazvána CharacterSprite. Jděte do toho a udělejte to.

Tato třída bude kreslit sprite na plátně a bude vypadat tak

public class CharacterSprite {private bitmap image; public CharacterSprite (Bitmap bmp) {image = bmp; } veřejné neplatné kreslení (Canvas canvas) {canvas.drawBitmap (image, 100, 100, null); }}

Chcete-li toto použít, musíte nejprve načíst bitmapu a poté zavolat třídu GameView. Přidejte odkaz na soukromý CharacterSprite characterSprite a pak v povrchVytvořeno metoda, přidejte řádek:

characterSprite = nový CharacterSprite (BitmapFactory.decodeResource (getResources (), R.drawable.avdgreen));

Jak vidíte, bitmapa, kterou načítáme, je uložena ve zdrojích a nazývá se avdgreen (pocházela z předchozí hry). Nyní stačí jen předat tuto bitmapu nové třídě v kreslit metoda s:

characterSprite.draw (canvas);

Nyní klikněte na tlačítko Spustit a na obrazovce by se měla zobrazit vaše grafika! Toto je BeeBoo. Kreslil jsem ho do školních učebnic.

Co kdybychom chtěli, aby se tento malý kluk pohnul? Jednoduché: pro své pozice vytvoříme pouze x a y proměnné a poté tyto hodnoty změníme v Aktualizace metoda.

Takže přidejte odkazy na svůj CharacterSprite a poté nakreslete bitmapu na x, y. Vytvořte zde metodu aktualizace a prozatím se pokusíme:

y ++;

Při každém spuštění herní smyčky přesuneme postavu dolů po obrazovce. Pamatuj si, y souřadnice se měří shora 0 je horní část obrazovky. Samozřejmě musíme zavolat Aktualizace metoda v CharacterSprite z Aktualizace metoda v GameView.

Stiskněte znovu tlačítko Přehrát a nyní uvidíte, že váš obraz pomalu sleduje obrazovku. Zatím nezískáváme žádná ocenění, ale je to začátek!

Dobře, dělat věci mírně ještě zajímavější je, že tady prostě vypustím nějaký kód „skákací koule“. To způsobí, že se naše grafické odskočení kolem okraje obrazovky, stejně jako staré spořiče obrazovky Windows. Víte, ty podivně hypnotické.

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

Budete také muset definovat tyto proměnné:

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

Optimalizace

Tady je spousta více se zde ponořit, od manipulace se vstupem hráče, po změnu měřítka obrázků, až po správu, kdy se po obrazovce bude pohybovat celá řada znaků najednou. Právě teď se postava poskakuje, ale pokud se podíváte velmi pozorně, dochází k mírnému koktání. Není to hrozné, ale skutečnost, že to vidíte pouhým okem, je něco jako varovný signál. Rychlost se také velmi liší v emulátoru ve srovnání s fyzickým zařízením. Nyní si představte, co se stane, když budete mít tun na obrazovce najednou!

Existuje několik řešení tohoto problému. Co chci udělat pro začátek, je vytvořit soukromé celé číslo v MainThread a zavolej to targetFPS. To bude mít hodnotu 60.Pokusím se nechat svou hru běžet takovou rychlostí a mezitím se ujistím, že to tak je. Z tohoto důvodu také chci soukromé dvojité volání průměrný FPS.

Budu také aktualizovat běh metoda k měření, jak dlouho každá herní smyčka trvá, a poté pauza tuto herní smyčku dočasně, pokud je před cílovým FPS. Potom si spočítáme, jak dlouho to bude Nyní vzal a vytiskl, že můžeme vidět v protokolu.

@Override public void run () {long startTime; dlouhý časMillis; dlouhé waitTime; long totalTime = 0; int frameCount = 0; long targetTime = 1000 / targetFPS; while (running) {startTime = System.nanoTime (); canvas = null; try {canvas = this.surfaceHolder.lockCanvas (); synchronized (surfaceHolder) {this.gameView.update (); this.gameView.draw (canvas); }} catch (Výjimka e) {} konečně {if (canvas! = null) {try {surfaceHolder.unlockCanvasAndPost (canvas); } catch (Výjimka e) {e.printStackTrace (); }}} timeMillis = (System.nanoTime () - startTime) / 1000000; waitTime = targetTime - timeMillis; zkuste {this.sleep (waitTime); } catch (Výjimka e) {} totalTime + = System.nanoTime () - startTime; frameCount ++; if (frameCount == targetFPS) {průměrný FPS = 1000 / ((totalTime / frameCount) / 1000000); frameCount = 0; totalTime = 0; System.out.println (průměrná FPS); }}}

Nyní se naše hra pokouší uzamknout FPS na 60 a měli byste zjistit, že obecně měří poměrně stabilní 58-62 FPS na moderním zařízení. Na emulátoru však můžete získat jiný výsledek.

Zkuste to změnit na 60 a 30 a uvidíte, co se stane. Hra se zpomaluje a to by měl nyní si ve svém logcatu přečtěte 30.

Závěrečné myšlenky

Pro optimalizaci výkonu můžeme udělat i několik dalších věcí. K tomuto tématu je zde skvělý blogový příspěvek. Pokuste se zdržet se vytváření nových instancí programu Paint nebo bitmapy uvnitř smyčky a proveďte veškerou inicializaci mimo před začátkem hry.

Pokud plánujete vytvoření další hitové hry pro Android, pak tam jsou rozhodně jednodušší a efektivnější způsoby, jak toho dosáhnout dnes. Určitě však existují scénáře případu, kdy je možné čerpat na plátno, a je to velmi užitečná dovednost, kterou můžete přidat do svého repertoáru. Doufám, že tento průvodce poněkud pomohl a přeji vám hodně štěstí ve vašich nadcházejících programovacích aktivitách!

dalšíPrůvodce pro začátečníky po Java

Google Pixel 3a a 3a XL byl puštěn včera a brzy byl zpřítupněn online. Pokud jte ji již viděli v obchodech nebo narazili na předchozí netěnoti, možná jte i všimli její odlišné...

amung Galaxy M10 a Galaxy M20 doud nebyly zcela odhaleny, tapety e však již dotaly na internet.amMobile zveřejnil tapety Galaxy M10 a Galaxy M20 online a v porovnání obrázky amung Gala...

Naše Doporučení