ML Kit El Hareketi Algılama ve Ashley Sistem Kutuphanesi ile LibGDX Demo Oyun Uygulaması Bölüm 2

Erdal Kaymak
Huawei Developers - Türkiye
8 min readAug 9, 2022

Giriş

Merhaba, Bu makalenin ilk bölümünü okumadıysanız bu bağlantıyı kontrol edin. Bu yazımızda LibGDX Ashley Varlık Sistem Kütüphanesini anlayacağız ve bir Libgdx Oyun Ekranı oluşturacağız. Ayrıca varlık fabrika sınıfı ile oyuncu nesnemizi oluşturacağız, demo oyun uygulamasında bileşenleri, sistemleri ve LibGDX oyun motorlarını öğrenip kullanacağız.

Sınır Bileşeni (Bounds Component)

Bu bileşeni, oyuncuların ve diğer oyun nesnelerinin sınır (daire ya da dikdörtgensel olarak sınırlama)verilerini tutmak için oluşturuyorum.

İlk önce bu sınıfı Component (Bileşen) arabiriminden üretiyorum. Bu basit bir component sınıfıdır. Oyun objelerinde bu bileşenin kullanımı için iki değişken oluşturuyorum. Biri daire şeklindeki oyun nesnelerinde kullanmak için bir daire, diğeri ise dikdörtgen şeklindeki oyun nesnelerinde kullanmak için bir dikdörtgen.

Pozisyon Bileşeni (Position Component)

Bu bileşeni oyun dünyasındaki oyun nesnelerinin x ve y koordinatlarının konum başlangıç ​​değerlerini tutmak için oluşturuyorum.

Oyuncu Bileşeni (Player Component)

Bu bileşen yalnızca oyun nesnesini bir oyuncu olarak belirtmek için kullanılır. Bu sınıfın içinde herhangi bir veri tutmuyorum.

Düşman Bileşeni (Enemy Component)

Oyuncuyla düşmanı vurmayı ve lazerle düşmanı vurmayı anlamak için iki değişken oluşturuyorum. Sıfırlama (reset) fonksiyonunda tüm değerleri sıfırlıyorum. Bu method, düşman oyun dünyasından temizlendiğinde (clean) çağrılır.

Lazer Bileşeni (Laser Component)

Bu bileşen yalnızca oyun nesnesinin bir lazer olduğunu belirtmek için kullanılır. Bu sınıfta herhangi bir veri kullanmadım.

Patlama Bileşeni (Explosion Component)

Patlama animasyonunun bitip bitmediğini anlamak için bir değişken oluşturuyorum. Bu değeri reset fonksiyonunda sıfırlıyorum.

Doku Bileşeni (Texture Component)

Bu sınıf, oyun nesnelerinin doku bölgesi (cizim) verilerini tutmak için kullanılır. Oyun nesnelerinin doku bölgesi verilerini tutmak için bir değişken oluşturuyorum. Doku Bölgesi, Doku Atlası bölgesidir. Texture Atlas, tüm oyun nesnesi dokularını bölgeleriyle birlikte tek bir dosyada tutar.

Boyut Bileşeni (Dimension Component)

Bu bileşeni oyun dünyasındaki oyun nesnelerinin genişlik ve yükseklik ölçü değerlerini tutmak için oluşturuyorum. Genişlik ve yükseklik başlangıç ​​değerlerini 0f olarak ayarladım.

Sargı Bileşeni (World Wrap Component)

Bu bileşen yalnızca oyun nesnesini sarmak ve oyun nesnesinin oyun dünyasının dışına çıkmasını önlemek için kullanılır.

Temizleme Bileşeni (Clean Up Component)

Bu bileşeni oyun dünyasından görevi biten oyun nesnelerini temizlemek için oluşturdum.

Oyun Yöneticisi Sınıfı (GameManager Class)

Tercihler (Preferences)yardımıyla seviye, yüksek puan ve sağlık kontrolü için bu sınıfı oluşturuyorum ve bu sınıfı sistemlerden çağırıyorum.

Oyun Yapılandırma Sınıfı (GameConfig Class)

Bu nesneyi sabit değerleri saklamak için olusturdum. Oyun dünyası yüksekliği, dünya genişliği, yaşamlar, çekirdek, düşman ve oyuncu boyutu, hud genişliği ve yüksekliği vb.

Varlık Üretme Sınıfı (EntityFactory Class)

Bu sınıfı dinamik olarak varlıkları ve oyun nesnelerini oluşturmak için kullanıyorum.

İlk olarak, yapıcının parametresi olarak motor ve entityManager’ı geçiyorum. Oyun dokusu için entityManager’ı ve bileşen ve varlık eklemek için motoru kullanıyorum.

(10–14. satırlarda) Oyun Atlası ve patlama dokusunu başlatmak için init oluşturuyorum. Tüm oyun nesnesi dokuları için gamePlayAtlas’ı ve patlama animasyonları oluşturmak için gamePlayAtlas’tan ayırması gereken oyun nesnesinin patlaması için patlama dokusunu kullanıyorum.

(16–47. satırlarda) Oyuncumu oyun motoru ve bileşenlerinin yardımıyla oluşturuyorum. Engine.createComponent() yöntemiyle bileşenler oluşturuyorum. engine.createEntity() yöntemiyle bir varlık oluşturuyorum. Bundan sonra bu bileşenleri varlığımıza (player) ekleyebiliriz. Bileşenleri sırasıyla ekliyorum. Bileşenlerimizi varlığa eklediğimizde düzen önemlidir. Bu nedenle bileşenleri şu sırayla ekliyorum; bağlı, oyuncu, doku, konum worldWrap ve boyut. Son olarak motor.addEntity() metodu ile oyunumuza bir varlık ekleyebiliriz.

(49–79. satırlarda) Lazerimi oyun motoru ve bileşenlerinin yardımıyla yaratıyorum. Bir varlığa (lazer) bileşenler ekliyorum. Bileşenleri bu sırayla ekliyorum; cilt, lazer, hareket, doku, konum ve boyut. Son olarak bu objeyi (lazer) engine.addEntity() metodu ile oyunumuza ekleyebiliriz.

(81–112. satırlarda) Düşmanlarımı oyun motoru ve bileşenleri yardımıyla yaratıyorum. Bir varlığa (düşmana) bileşenler ekliyorum. (99–101. satırlarda) Tercihler yardımıyla oyunun zorluğunu alıyorum, bundan sonra setDifficulty() yöntemini kullanarak oyunun zorluk derecesini ayarlıyorum. Bileşenleri bu sırayla ekliyorum; sınır, hareket, doku, konum, boyut, temizleme ve düşman. Son olarak bu varlığı (düşmanı) engine.addEntity() metodu ile oyunumuza ekleyebiliriz.

(116–169. satırlarda) oyunun seviyesine göre düşman hızını ve boyutunu değiştirmek için bir setDifficulty() yöntemi oluşturuyorum. Skor arttığında seviyeyi değiştiriyorum ve seviye değiştikten sonra düşmanlar rastgele daha hızlı ve daha küçük oluyor.

(171–191 satırlarında) oyun motoru ve bileşenlerinin yardımıyla arka planımı oluşturuyorum. Bir varlığa (arka plana) bileşenler ekliyorum. Bileşenleri bu sırayla ekliyorum; doku, boyut ve konum. Son olarak bu objeyi (background) engine.addEntity() metodu ile oyunumuza ekleyebiliriz.

(195–232. satırlarda) Patlamalarımı oyun motoru ve bileşenlerinin yardımıyla yaratıyorum. Bu varlık diğerlerinden biraz farklıdır. Düşmanlar öldüğünde patlama animasyonunu hazırlamak için dokuları zamanında değiştiriyorum. Bir varlığa bileşenler ekliyorum (patlama). Bileşenleri bu sırayla ekliyorum; doku, boyut konumu ve patlama. Son olarak bu varlığı (patlamayı) engine.addEntity() metodu ile oyunumuza ekleyebiliriz.

Eşleme Objesi (Mappers)

Components Mapper sınıfının yardımıyla Components’ı eslemek için Mappers nesnesini kullanabiliriz.

Sınırlar Sistemi (Bounds System)

Bu sistemi, varlığın sınırlarını konum ve boyut bileşenleri ile belirlemek için oluşturuyorum.

Bu sistemi Iterating System ile kullanıyorum. Yinelenen Sistem, bir parametre olarak Family alır. Aile, sistem çalışması için kullanılan bileşenleri içermelidir. Bu sistemin processEntity() yöntemi, varlık sınır, konum ve boyut bileşenlerini içerdiğinde çağrılır. Ayrıca GameScreen’de bu sistemi engine.addSystem() metodu ile çağırmalıyız.

Hareket Sistemi (Movement System)

Düşman ve lazer gibi varlıkları hareket ettirmek için bu sistemi kullanıyorum. Bu sistemi Iterating System ile kullanıyorum.

Varlık, Konum Bileşeni ve Hareket Bileşenini birlikte içerdiğinde, bu sistemle hareket ettirilebilir. Ayrıca Oyun Ekranında tüm sistemleri motorumuza (Engine) eklemeliyiz.

Çizim Sistemi (Render System)

Varlıkları işlemek için bu sistemi oluşturuyorum. Bu sistemi Entity System ile kullanıyorum. Bu sistemdeki update methodu her bir frame arasında çağrılır.

Bu sistemi kullanmak için Sprite Batch ve Viewport’u yapıcıya iletiyorum. (3. satırda) Oluşturma varlıklarını kullanmak için bir varlık dizisi oluşturuyorum. (6–16. satırlarda) Önce motor.getEntitesFor(FAMILY) yöntemiyle varlık listemi oluşturuyorum, bu şekilde Aile bileşenlerini (Doku, Konum, Boyut) içeren tüm varlıkları alıyorum. Daha sonra bu varlıkları renderQueue adlı varlık dizime ekliyorum. Daha sonra ViewPort’umu etkinleştirmek için viewPort.apply()’i aradım. (11. satırda) SpriteBatch’i ViewPort’umla bir kamerayla ayarladım. Kombine, birleşik görünüm ve projeksiyon matrisini temsil ettiği anlamına gelir. Diğer bir deyişle; oyun dünyanızdaki şeylerin ekranda nerede gösterilmesi gerektiğini açıklar. (13–15. satırlarda) batch.begin() ve batch.end() arasında çizim yöntemini çağırıyorum. (21–31. satırlarda) İşleme varlıklarımı toplu olarak çizmek için batch.draw() methodunu kullanıyorum.

Durum Çubuğu Çizim Sistemi (HUD Render System)

HUD (heads-up display) veya durum çubuğu, bilgilerin oyunun kullanıcı arayüzünün bir parçası olarak oyuncuya görsel olarak aktarıldığı yöntemdir. Bu sistemi oyun ekranında skorları ve canları göstermek için oluşturuyorum. Yapıcının bir parametresi olarak ViewPort, DarkSpaceGame ve BitmapFont nesnelerini iletiyorum. Bu sistemi Entity System ile kullanıyorum.

(14. satırda) Metin boyutunu almak ve skoru Oyun Ekranında göstermek için GlyphLayout’u oluşturuyorum. Güncelleme işlevinde, toplu iş.begin() ve toplu iş.end() yöntemleri arasında çizim yöntemlerini çağırıyorum. (33–38. satırlarda) layout.setText() yöntemiyle metnin yüksekliğini ve genişliğini elde etmek için puan metnini oluşturuyorum ve metni GlyphLayout olarak ayarladım. Daha sonra bu metni font.draw() fonksiyonu ile çiziyorum.

(43–70. satırlarda) Oyun Ekranında hayatları göstermek için hayat HUD’u ayarladım. Önce Varlık Yöneticisinin yardımıyla yaşam bölgesini almak için Game Play Atlas’ı oluşturuyorum. Bundan sonra, Tercihler yardımıyla kaç can kaldığını alıyorum. Daha sonra oyunda can azalırsa sağlık nesnesinin rengini değiştiririm. Batch.draw() metodu ile canları çiziyorum. (69. satırda) Son olarak rengi eski renge ayarladım.

Enemy Spawn System

Bu sistemi her zaman aralığında düşman yaratmak için kullanıyorum.

Bu sistemi Interval System ile kullanıyorum. Interval System parametre olarak Float değerini alır. Bu değer, bu sistemin her aralık zamanında çağrılacağı anlamına gelir. Örneğin; Bu değer için 1f’yi seçiyorum, böylece düşmanlarım her saniye ortaya çıkacak. Bu sistem her saniye updateInterval() yöntemini çağırıyor, böylece düşmanların x konumunu rastgele bir işlevle değiştirebiliyorum ve düşman oluşturmak için addEnemies() yöntemini çağırıyorum.

Oyuncu Sistemi (Player System)

Oyuncuyu el hareketi algılama ile hareket ettirmek için bu sistemi oluşturuyorum.

I store the hand gesture situation in the TOUCH_LEFT_RIGHT variable. When the player moves with hand gesture detection I change the player position with that value.

Lazer Oluşturma Sistemi (Laser Spawn System)

Bu sistemi her saniyenin yarısında lazer oluşturmak için kullanıyorum. Bu sistemi Interval System ile kullanıyorum.

Her saniyenin yarısında iki lazer yaratıyorum. Ayrıca player dinamik pozisyonu ile lazer pozisyonunu değiştiriyorum.

Dünya Sarma Sistemi (World Wrap System)

Bu sistemi oyun dünyasını sarmak için yaratıyorum. Bu sistemi Iterating System ile kullanıyorum.

MathUtils.clamp() işleviyle x ve y konumunu sabitliyorum. Bu sistemi Iterating System ile kullanıyorum. Varlık, Dünya Sarma Bileşeni, Konum Bileşeni ve Boyut Bileşeni’ni birlikte içerdiğinde, sarılabilir.

Varlıkları Temizleme Sistemi (Clean-Up System)

Ekranin altından geçilirse düşmanları temizlemek için bu sistemi kullanıyorum.

processEntity() yönteminde düşman konumunu düşman boyutuyla kontrol ediyorum. Ardından GameManager nesnesi ile sağlığı, puanı ve seviyeyi güncelliyorum.

Çarpışma Sistemi (Collision System)

Entity System kullanarak varlıkların çarpışma işlemi için bu sistemi oluşturuyorum. Burda dört aile oluşturdum. Bunlar oyuncu, düşman, lazer ve patlama ailesidir.

Öncelikle EntityFactory nesnesini yapıcının parametresi olarak iletiyorum. Puanları ve sağlığı güncellemek için GameManager nesnesini kullanıyorum.

(6–15. satırlarda)Önce motor.getEntitiesFor(FAMILY) yöntemiyle oyuncu, düşman, lazer ve patlama varlıkları alıyorum. Ardından patlamaların boyutunu kontrol ediyorum ve ilk patlamayı motor.removeEntity() yöntemiyle kaldırıyorum.

(16–33. satırlarda) İlk önce oyuncu boyutunu ve konumunu alıyorum, ardından tüm düşman varlıklarını alıyorum ve oyuncuyla çarpışmayı kontrol ediyorum. Bu işlem için chekCollisionShip() yöntemini kullanıyorum. Oyuncu ve düşmanın çarpışması durumunda düşmanı kaldırıyorum ve fabrika.addNewExplosion() ile bir patlama oluşturuyorum ve GameManager nesnesi ile sağlığı ve puanı güncelliyorum.

(35–55. satırlarda)Önce düşman bileşenlerini, boyutlarını ve konumlarını alıyorum. Ardından lazerlerin düşmanlarla çarpışmasını kontrol ediyorum. Bu işlem için checkCollisionLaser() yöntemini kullanıyorum. Ondan sonra varlığı kaldırıyorum ve yeni bir patlama oluşturuyorum ve skoru güncelliyorum.

(57–62. satırlarda) Bu yöntemi, oyuncu ve düşmanlar arasındaki çarpışmayı kontrol etmek için kullanıyorum. Öncelikle Mapper sınıfının helper’ı ile oyuncu ve düşman sınırlarını alıyorum. Daha sonra Intersector.overlaps() metodu ile çarpışmalarını kontrol ediyorum.

(64–69. satırlarda) Lazerler ve düşmanlar arasındaki çarpışmayı kontrol etmek için bu yöntemi kullanıyorum. Öncelikle Mapper sınıfının helper’ı ile lazer ve düşmanın sınırlarını öğreniyorum. Daha sonra Intersector.overlaps() metodu ile çarpışmalarını kontrol ediyorum.

Oyun Ekranı (Game Screen)

Bu ekranı ScreenBaseAdapter ile kullanıyorum. DarkSpaceGame nesnesini yapıcı parametresi olarak iletiyorum. Bu ekranı Oyun Ekranı olarak kullanıyorum. Tüm oyun işlemlerini bu ekranda çalıştırıyorum. Ayrıca oyunu bu ekranda kameradan El Hareketi algılama ile oynayabilirsiniz.

Öncelikle AssetManager, Viewport, ShapeRenderer, PooledEngine, EntityFactory, OrthographicCamera, RenderSystem, BitmapFont, Preferences ve GameManager’ın nesnesini show() yönteminde oluşturuyorum.

(33–47. satırlarda) sistemleri sırasıyla engine.addSystem() yöntemiyle ekliyorum. Sistemlerimizi varlığa eklediğimizde düzen önemlidir. Bu nedenle sistemleri şu sırayla ekliyorum; Oyuncu Sistemi, Hareket Sistemi, World Wrap Sistemi, Sınırlar Sistemi, Düşman Doğma Sistemi, Lazer Doğma Sistemi, Temizleme Sistemi, Çarpışma Sistemi, Render Sistemi ve HudRenderSystem. Ardından EntityFactory nesnesiyle arka plan ve oynatıcı ekliyorum. GameScreen açıldığında Show() yöntemi bir kez çalışacaktır.

(49–61. satırlarda) Her oyun karesini işlemek için bu yöntemi kullanıyorum. İlk olarak, system update() ve processEntity() yöntemlerini tetiklemek için engine.update(delta) yöntemini çağırıyorum. Sonra Preferences nesnesinden can alıyorum. Sonrasında checkPlayerHealth() metodu ile oyuncunun sağlığını kontrol ediyorum. Oyuncunun canları sıfıra eşit olduğunda, motor oluşturmayı durdurmak için system.update(0f) çağırırım.

(66–86. satırlarda) Oyuncunun canı olmadığında oyuncu sağlığını kontrol etmek için bu yöntemi oluşturuyorum, ardından oyuncu boyutunu ve konumunu alarak oyuncu üzerinde yeni bir patlama oluşturuyorum.

(88–91 satırlarında) Kamerayı yönetmek ve dünya koordinatlarının ekrana ve ekrandan nasıl eşlendiğini belirlemek için viewport.update() ve hudViewport.update() yöntemlerini çağırmalıyız.

İp Uçları ve Püf Noktalar

Bu demo uygulaması için Ashley Entity System Library kullandım. Bu sistem kitaplığını kullanmadan, modern oyunları oluşturmak oldukça zordur. Bu sistem kitaplığını kullanarak oyun mantığını işleme mantığından ayırıyoruz. Ayrıca, statik sınıf varlıkları yerine dinamik varlıklar oluşturmak için EntityFactory kullanıyoruz.

Sonuç

Şimdi bir LibGDX demo oyun uygulamasını nasıl oluşturacağımızı ve Oyun Ekranını nasıl oluşturacağımızı öğrendik ve LibGDX Ashley Entity System Library’yi anladık. Ayrıca entity fabrika sınıfı ile oyuncu nesnemizi oluşturduk, bu demo oyun uygulamasında bileşenleri, sistemleri ve motorları öğrendik ve kullandık. LibGDX ve hizmetleri hakkında daha fazla bilgi edinmek istiyorsanız bu bağlantıya göz atabilirsiniz. Bu demo uygulaması ile Libgdx Ashley Entity System Library’nin ileri düzey konularını öğretmeye çalıştım. Umarım faydalı olur.

Bir dahaki sefere kadar kendinize iyi bakın..

--

--