Java'daki ilk Android oyununu nasıl yazarsın?

Yazar: John Stephens
Yaratılış Tarihi: 1 Ocak Ayı 2021
Güncelleme Tarihi: 19 Mayıs Ayı 2024
Anonim
Java'daki ilk Android oyununu nasıl yazarsın? - Uygulamaların
Java'daki ilk Android oyununu nasıl yazarsın? - Uygulamaların

İçerik


Android için bir oyun oluşturmanın birçok yolu vardır ve Android Studio'da Java ile sıfırdan başlamak için önemli bir yoldur. Bu size oyununuzun nasıl görünmesini ve davranmasını istediğiniz üzerinde maksimum kontrol sağlar ve süreç size bir uygulama için bir açılış ekranı oluştururken veya sadece bir uygulama için bir açılış ekranı oluştururken de kullanabileceğiniz becerileri öğretir. bazı animasyonlar ekleyin. Bunu akılda tutarak, bu eğitimde size Android Studio ve Java kullanarak basit bir 2D oyun oluşturmayı göstereceksiniz. Takip etmek istiyorsanız tüm kodu ve kaynakları Github'da bulabilirsiniz.

Kurma

Oyunumuzu oluşturmak için, birkaç özel konseptle uğraşmamız gerekecek: oyun döngüleri, iplikler ve tuvaller. Başlamak için Android Studio'yu başlatın. Yüklemiş değilseniz, yükleme işlemine devam eden Android Studio'ya tam girişimizi inceleyin. Şimdi yeni bir proje başlatın ve "Boş Etkinlik" şablonunu seçtiğinizden emin olun. Bu bir oyundur, elbette FAB butonu gibi önemli unsurlara ihtiyaç duymazsınız.


İlk yapmak istediğin şey değişmek. AppCompatActivity için Aktivite. Bu, eylem çubuğu özelliklerini kullanmayacağımız anlamına gelir.

Benzer şekilde oyunumuzu tam ekran yapmak istiyoruz. SetContentView () çağrısından önce onCreate () öğesine aşağıdaki kodu ekleyin:

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

Bir kod yazarsanız ve kırmızı ile altı çizili ise, bunun muhtemelen bir sınıf almanız gerektiği anlamına geldiğini unutmayın. Başka bir deyişle, Android Studio’ya belirli ifadeleri kullanmak ve bunları kullanıma sunmak istediğinizi söylemeniz gerekir. Altı çizili sözcüğün herhangi bir yerine tıklarsanız ve Alt + Enter tuşlarına basarsanız, bu otomatik olarak sizin için yapılacaktır!


Oyun görünümünüzü oluşturma

Düğmeler, görüntüler ve etiketler gibi görünüm düzenini tanımlamak için XML komut dosyası kullanan uygulamalarda kullanabilirsiniz. İşte bu ne setContentView bizim için yapıyor.

Fakat yine de bu, tarayıcı pencereleri veya kayan geri dönüşümlü görünümleri olması gerekmediği anlamına gelen bir oyundur. Bunun yerine, tuvali göstermek istiyoruz. Android Studio'da bir tuval sanatta olduğu gibidir: çizebileceğimiz bir araç.

Öyleyse, şu şekilde okumak için bu satırı değiştirin:

setContentView (yeni GameView (bu))

Bunun bir kez daha kırmızı altı çizili olduğunu göreceksiniz. Fakat şimdi Alt + Enter tuşlarına basarsanız, sınıfı içe aktarma seçeneğiniz yoktur. Bunun yerine, seçeneğiniz var yaratmak Bir sınıf. Başka bir deyişle, tuvalde neler olacağını tanımlayacak kendi sınıfımızı yapmak üzereyiz. Bu sadece hazır görüntüler göstermek yerine ekrana çizim yapmamızı sağlayacak.

Yani, hiyerarşinizdeki paket ismine sağ tıklayın ve sol tarafa tıklayın. Yeni> Sınıf. Şimdi, sınıfınızı oluşturacak bir pencere ile karşılaşacaksınız ve onu arayacaksınız. GameView. SuperClass altında, şunu yazın: android.view.SurfaceView bu, sınıfın SurfaceView'dan yöntemleri - yeteneklerini - miras alacağı anlamına gelir.

Arayüz (ler) kutusuna yazacaksınız android.view.SurfaceHolder.Callback. Her sınıfta olduğu gibi, şimdi yapıcımızı yaratmamız gerekiyor. Bu kodu kullan:

özel MainThread ipliği; genel GameView (İçerik içeriği) {super (içerik); . GetHolder () addCallback (bu); }

Sınıfımıza yeni bir nesne yapmaya her çağrıldığında (bu durumda bizim yüzeyimiz), yapıcıyı çalıştıracak ve yeni bir yüzey yaratacaktır. "Süper" satırı, süper sınıfı çağırır ve bizim durumumuzda bu, SurfaceView'dur.

Geri arama ekleyerek, olayları ele geçirebiliriz.

Şimdi bazı yöntemleri geçersiz kıl:

@ Genel geçersiz yüzey yüzeyini değiştir (Değiştir)

Bunlar temelde üst sınıftaki (SurfaceView) metodları geçersiz kılmamıza izin verir (dolayısıyla adı). Artık kodunuzda kırmızı alt çizgi olmamalıdır. Güzel.

Az önce yeni bir sınıf yarattınız ve buna her atıfta bulunduğumuzda, oyununuzun boyanması için tuvali oluşturacak. Sınıflar yaratmak nesneler ve bir tane daha lazım.

Konu oluşturma

Yeni sınıfımız çağrılacak MainThread. Ve işi bir iş parçacığı oluşturmak olacaktır. Bir iş parçacığı, eşzamanlı olarak eşzamanlı olarak çalışabilen paralel bir kod çatalına benzer ana kodunuzun bir parçası. Aynı anda çalışan birçok iş parçacığına sahip olabilirsiniz, böylece sıkı bir diziye uymak yerine işlerin eşzamanlı olarak gerçekleşmesini sağlayabilirsiniz. Bu bir oyun için önemlidir, çünkü bir çok şey devam ederken bile sorunsuz bir şekilde devam etmesini sağlamak zorundayız.

Yeni sınıfınızı daha önce yaptığınız gibi yaratın ve bu sefer daha da uzayacak iplik. Yapıcıda sadece arayacağız Süper(). Unutmayın, bu bizim işimiz olan ve tüm ağır yükleri kaldırabilecek süper sınıf, Thread. Bu sadece arayan bulaşıkları yıkamak için bir program oluşturmak gibi çamaşır makinesi().

Bu sınıf çağrıldığında, ana şeyin bir parçası olarak çalışan ayrı bir konu oluşturacak. Ve o İşte GameView'umuzu oluşturmak istediğimizi Bu, GameView sınıfına da başvurmamız gerektiği ve tuvali içeren SurfaceHolder'ı kullandığımız anlamına geliyor. Yani, tuval yüzey ise, SurfaceHolder şövaledir. Ve GameView, hepsini bir araya getiren şeydir.

Dolu olan şey şöyle görünmeli:

genel sınıf MainThread, Thread {private SurfaceHolder surfaceHolder; özel GameView gameView; genel MainThread (SurfaceHolder surfaceHolder, GameView gameView) {super (); this.surfaceHolder = surfaceHolder; this.gameView = gameView; }}

Schweet. Artık bir GameView ve iş parçacığımız var!

Oyun döngüsünü oluşturma

Artık oyunumuzu yapmak için ihtiyacımız olan hammaddelere sahibiz, ancak hiçbir şey olmuyor. Oyun döngüsünün girdiği yer burasıdır. Temel olarak, bu, yuvarlak ve yuvarlak dönen ve ekranı çizmeden önce girişleri ve değişkenleri kontrol eden bir kod döngüsüdür. Amacımız bunu olabildiğince tutarlı hale getirmektir, böylece kare hızda biraz daha sonra keşfedeceğim kekemeler veya hıçkırıklar olmaz.

Şimdilik biz hala MainThread sınıf ve üst sınıftan bir yöntemi geçersiz kılacağız. Bu bir koşmak.

Ve böyle bir şey gider:

@ Genel geçersiz boşluğu çalıştır () {while (çalışıyor) {canvas = null; deneyin {canvas = this.surfaceHolder.lockCanvas (); senkronize (surfaceHolder) {this.gameView.update (); this.gameView.draw (tuval); }} catch (İstisna e) {} en sonunda {if (canvas! = null) {try {surfaceHolder.unlockCanvasAndPost (canvas); } catch (İstisna e) {e.printStackTrace (); }}}}}

Çok fazla altı çizili göreceksiniz, bu nedenle daha fazla değişken ve referans eklememiz gerekiyor. Başa dön ve ekle:

özel SurfaceHolder surfaceHolder; özel GameView gameView; özel boolean koşusu; genel statik Tuval tuval;

Tuvali almayı unutmayın. Tuval, üzerinde çizim yapacağımız şeydir. 'LockCanvas'a gelince, bu önemlidir, çünkü tuvalin üzerine çizmemize izin vermek için esasen dondurur. Bu önemlidir, çünkü aksi takdirde, bir kerede çizmeye çalışan birden fazla iş parçacığınız olabilir. Sadece tuvali düzenlemek için önce yapmanız gerektiğini biliyorum kilit tuval.

Güncelleme, yaratacağımız bir yöntemdir ve eğlenceli şeyler daha sonra gerçekleşeceği yer burasıdır.

Deneyin ve yakalamak bu arada, Java, tuval hazır değilse vb. oluşabilecek istisnaları (hataları) denemeye ve çözmeye istekli olduğumuzu gösteren Java gereksinimleridir.

Sonunda, ihtiyacımız olduğunda ipliğimize başlayabilmek istiyoruz. Bunu yapmak için, olayları harekete geçirmemize izin veren başka bir metoda ihtiyacımız var. Bu ne çalışan değişkeni içindir (Boolean'ın yalnızca doğru veya yanlış olan bir değişken türü olduğunu unutmayın). Bu yöntemi MainThread sınıf:

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

Ancak bu noktada, bir şey hala vurgulanmalı ve bu güncelleştirme. Bunun nedeni henüz güncelleme yöntemini oluşturmadık. Yani tekrar içine pop GameView ve şimdi yöntem ekleyin.

genel geçersiz güncelleme () {}

Ayrıca gerekir başla iplik! Bunu bizim de yapacağız. surfaceCreated yöntem:

@ Genel geçersiz yüzey yüzeyini geçersiz kılındı ​​(Oluşturuldu (SurfaceHolder sahibi)) {thread.setRunning (true); thread.start (); }

Ayrıca yüzey tahrip olduğunda ipliği durdurmamız gerekir. Tahmin edebileceğiniz gibi, bunu biz hallederiz. surfaceDestroyed yöntem. Ancak bir ipliği durdurmak için gerçekten birden fazla girişimde bulunabileceğini görünce, bunu bir döngüye sokacağız ve kullanacağız. Deneyin ve yakalamak tekrar. Gibi:

@Hopal boşluğu geçersiz kılındı ​​yüzeySeçme (SurfaceHolder tutucu) {boolean yeniden deneme = true; while (yeniden dene) {try {thread.setRunning (false); Thread.Join (); } catch (InterruptedException e) {e.printStackTrace (); } yeniden dene = yanlış; }}

Ve son olarak, yapıcıya gidin ve iş parçanızın yeni örneğini oluşturduğunuzdan emin olun, aksi takdirde korkunç boş gösterici istisnası elde edersiniz! Ve sonra GameView'a odaklanabilir hale getireceğiz, yani olaylarla başa çıkabiliyoruz.

thread = new MainThread (getHolder (), bu); setFocusable (doğru);

Şimdi yapabilirsin en sonunda Aslında bu şeyi sınayın! Bu doğru, koş ve tıkla meli aslında herhangi bir hata olmadan çalıştırın. Patlatılmaya hazır olun!

Bu… bu… boş bir ekran! Bütün bu kodlar. Boş bir ekran için. Ancak, bu boş bir ekran fırsat. Olayları işlemek için bir yüzey üzerinde bir oyun döngüsüyle çalışıyorsunuz. Şimdi kalan tek şey şeyleri yapmak. Bu noktaya kadar eğitimdeki her şeyi takip etmemeniz farketmez bile. Demek istediğim, şanlı oyunlar yapmaya başlamak için bu kodu basitçe geri dönüştürebilirsiniz!

Grafik yapmak

Şimdi, çizmek için boş bir ekranımız var, tek yapmamız gereken üzerine çizim yapmak. Neyse ki, bu basit kısmı. Yapmanız gereken tek şey bizim çizim yöntemini geçersiz kılmaktır. GameView sınıf ve sonra bazı güzel resimler ekleyin:

@ Genel geçersiz boşluk çizimini (Tuval tuval) {super.draw (tuval); if (canvas! = null) {canvas.drawColor (Color.WHITE); Boya boya = yeni Boya (); paint.setColor (Color.rgb (250, 0, 0)); canvas.drawRect (100, 100, 200, 200, boya); }}

Bunu çalıştırın; aksi halde beyaz ekranın sol üst köşesinde oldukça kırmızı bir kare olmalıdır. Bu kesinlikle bir gelişmedir.

Bu yöntemin içine sokarak oyunun tamamını teorik olarak oluşturabilirsiniz (ve geçersiz kılar) onTouchEvent girdiyle başa çıkmak için) ancak bu, işleri yürütmenin çok iyi bir yolu olmazdı. Yeni Boya'yı döngümüzün içine yerleştirmek, işleri önemli ölçüde yavaşlatır ve bunu başka bir yere koysak bile, çekmek yöntem çirkinleşir ve takip etmesi zorlaşırdı.

Bunun yerine, oyun nesnelerini kendi sınıflarıyla idare etmek daha mantıklı geliyor. Bir karakter gösteren biriyle başlayacağız ve bu sınıfa çağrılacak CharacterSprite. Devam et ve bunu yap.

Bu sınıf tuval üzerine bir sprite çizecek ve öyle gözükecek

genel sınıf CharacterSprite {private Bitmap image; public CharacterSprite (Bitmap bmp) {görüntü = bmp; } public void draw (Tuval tuval) {canvas.drawBitmap (resim, 100, 100, null); }}

Şimdi bunu kullanmak için önce bitmap'i yüklemeniz ve ardından sınıfı aramanız gerekir. GameView. Referans ekle özel CharacterSprite characterSprite ve sonra surfaceCreated yöntem, satırı ekleyin:

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

Görebildiğiniz gibi, yüklediğimiz bitmap kaynaklarda depolanır ve avdgreen olarak adlandırılır (önceki bir oyundaydı). Şimdi yapmanız gereken tek şey, bu bitmap'i yeni sınıfa geçirmek. çekmek yöntem:

characterSprite.draw (tuval);

Şimdi koş'u tıklayın ve grafiğinizin ekranda göründüğünü görmelisiniz! Bu BeeBoo. Onu okul ders kitaplarımda çizerdim.

Ya bu küçük adamı hareket ettirmek istiyorsak? Basit: Biz sadece onun pozisyonları için x ve y değişkenleri yaratır ve sonra bu değerleri bir güncelleştirme yöntem.

Yani referansları CharacterSprite ve sonra bitmap'inizi x, y. Güncelleme yöntemini burada oluşturun ve şimdilik sadece deneyeceğiz:

y ++;

Oyun döngüsü her çalıştığında, karakteri ekrandan aşağıya taşıyacağız. Hatırlamak, y koordinatlar üstten ölçülür. 0 Ekranın üst kısmıdır. Tabi ki aramamız gerek. güncelleştirme yöntem CharacterSprite -den güncelleştirme yöntem GameView.

Tekrar oynat düğmesine bastığınızda, görüntünüzün ekranı yavaşça takip ettiğini göreceksiniz. Henüz bir oyun ödülü kazanmıyoruz, ancak bu bir başlangıç!

Tamam, bir şeyler yapmak için hafifçe daha ilginç, ben sadece buraya bir 'kabarık topu' kodu bırakacağım. Bu, grafiğimizi ekranın kenarlarından fırlatıyor, bu eski Windows ekran koruyucular gibi. Bilirsin, garip hipnotik olanlar.

genel geçersiz güncelleme () {x + = xVelocity; y + = yHiçbirliği; if ((x & screen; screenWidth - image.getWidth ()) || (x <0)) {xVelocity = xVelocity * -1; } if ((y & gt; screenHeight - image.getHeight ()) || (y <0)) {yVelocity = yVelocity * -1; }}

Ayrıca bu değişkenleri tanımlamanız gerekecektir:

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

Optimizasyon

Var bol buraya girip oynatmak, oynatıcı girişini tutmaktan, görüntüleri ölçeklendirmeye, ekranda bir kerede tüm karakterleri dolaşan birçok karaktere sahip olanı yönetmeye kadar. Şu anda, karakter zıplıyor ama çok yakından bakarsanız hafif kekemelik var. Korkunç değil ama çıplak gözle görebilmeniz bir uyarı işareti. Hız aynı zamanda emülatörde fiziksel bir cihaza kıyasla çok fazla değişiklik gösterir. Şimdi sahip olduğunda ne olacağını hayal et ton bir kerede ekranda oluyor!

Bu sorunun birkaç çözümü var. Başlamak istediğim şey, içinde özel bir tam sayı oluşturmak. MainThread ve onu ara targetFPS. Bu 60 değerinde olacaktır.Oyunumu bu hızda çalıştırmaya çalışacağım ve bu arada, emin olmak için kontrol edeceğim. Bunun için de denilen özel bir çift istiyorum averageFPS.

Ben de güncelleyeceğim koşmak Her oyun döngüsünün ne kadar sürdüğünü ölçmek için Duraklat targetFPS öncesinde ise o oyun geçici olarak geçici. Daha sonra ne kadar süreceğini hesaplayacağız şimdi aldı ve yazdırın, böylece kütükte görelim.

@ Genel geçersiz void run () {long startTime; uzun süreMillis; long waitTime; uzun totalTime = 0; int frameCount = 0; uzun targetTime = 1000 / targetFPS; while (çalışıyor) {startTime = System.nanoTime (); tuval = boş; deneyin {canvas = this.surfaceHolder.lockCanvas (); senkronize (surfaceHolder) {this.gameView.update (); this.gameView.draw (tuval); }} catch (İstisna e) {} sonunda {if (canvas! = null) {try {surfaceHolder.unlockCanvasAndPost (canvas); } catch (İstisna e) {e.printStackTrace (); }}} timeMillis = (System.nanoTime () - startTime) / 1000000; waitTime = targetTime - timeMillis; deneyin {this.sleep (waitTime); } catch (İstisna e) {} totalTime + = System.nanoTime () - startTime; framecount ++; eğer (frameCount == targetFPS) {averageFPS = 1000 / ((totalTime / frameCount) / 1000000); frameCount = 0; totalTime = 0; System.out.println (averageFPS); }}}

Şimdi oyunumuz FPS’yi 60’a kilitlemeye çalışıyor ve modern bir cihazda genellikle oldukça sabit bir 58-62 FPS olduğunu ölçmelisiniz. Öykünücüsünde farklı bir sonuç alabilirsiniz.

Bunu 60 ile 30 arasında değiştirmeyi deneyin ve ne olacağını görün. Oyun yavaşlar ve meli Şimdi logcat içinde 30 oku.

Düşünceleri Kapatmak

Performansı optimize etmek için yapabileceğimiz başka şeyler de var. Burada konuyla ilgili harika bir blog yazısı var. Döngüde her zaman yeni Paint örnekleri veya bitmapler oluşturmaktan kaçının ve tüm başlatma işlemlerini yapın. dışında Oyun başlamadan önce.

Bir sonraki hit Android oyununu yaratmayı planlıyorsanız kesinlikle Bugünlerde bunun için daha kolay ve daha verimli yollar. Ancak bir tuval üzerine çizim yapabilmek için kesinlikle kullanım senaryoları vardır ve repertuarınıza eklemek oldukça yararlı bir beceridir. Umarım bu rehber biraz yardımcı olmuştur ve yaklaşan kodlama girişimlerinizde başarılar diliyoruz!

SonrakiYeni başlayanlar için Java rehberi

amung ve LG, Güney Kore anavatanlarında iki yekpare şirket olarak durmaktadır. Her iki şirket de 2019'un ilk yarıında amiral telefonlarını, ilk önce Galaxy 10'lu amung'u, ardında...

amung Galaxy 10 cep telefonunun 2019 yılının en çok atan telefonlarından biri olduğu neredeye kein. Bu aynı zamanda en pahalı olanlardan biri olacak ama peki premium fiyat etiketi taşımayan premi...

Size Önerilir