paint-brush
Alev Oyununuza HUD Nasıl Eklenir?ile@eugene-kleshnin
1,704 okumalar
1,704 okumalar

Alev Oyununuza HUD Nasıl Eklenir?

ile Eugene Kleshnin8m2023/03/20
Read on Terminal Reader
Read this story w/o Javascript

Çok uzun; Okumak

Bu, Flame motoruyla basit bir Platform oyununun nasıl oluşturulacağını öğrendiğim 4 bölümlük serimin son kısmı. Bu kısımda karakterin toplayabileceği jetonları, oyuncunun ne kadar jetonu olduğunu gösteren HUD'u ve zafer ekranını ekleyeceğiz.

People Mentioned

Mention Thumbnail
featured image - Alev Oyununuza HUD Nasıl Eklenir?
Eugene Kleshnin HackerNoon profile picture
0-item

Bu, Flame motoruyla basit bir Platform oyununun nasıl oluşturulacağını öğrendiğim 4 bölümlük serimin son kısmı. The Boy adını verdiğim animasyonlu bir oyuncu karakterinin nasıl ekleneceğini, Tiled düzenleyiciyi kullanarak kaydırılabilir bir oyun seviyesinin nasıl oluşturulacağını ve çarpışma algılama yardımıyla yerçekimi ve atlamanın nasıl ekleneceğini zaten biliyoruz (bölüm 1 , 2 , 3 ).


Bu kısımda karakter tarafından toplanabilecek jetonları, oyuncunun kaç jetonu olduğunu gösteren HUD'u ve tüm jetonlar toplandığında göstereceğimiz zafer ekranını ekleyeceğiz.


Para ekleme

Oyuna jetonların (veya bu konuda başka bir oyun nesnesinin) nerede ortaya çıkacağını söylememiz gerekiyor. Tahmin edebileceğiniz gibi, Platformları eklediğimiz gibi başka bir nesne katmanı eklemek için Tiled düzenleyiciyi kullanacağız, ancak iki farkla:


  1. Platformlarla seviye verilerine hareketli resim görüntüleri ekledik. Bu yöntem jetonlar için pek uygun değildir çünkü oyuncu onu topladıktan sonra nesneyi kaldırmak istiyoruz. Bu yüzden oyunda jetonların nerede görünmesi gerektiğini bilmek için sadece ortaya çıkma noktaları ekleyeceğiz ve oluşturma Alev bileşenleri kullanılarak yapılacaktır.


  2. Platformlar için her boyutta dikdörtgenler kullandık, ancak madeni paralar için 1 karo boyutunda ortaya çıkma noktaları ekleyeceğiz. Yine de, bir sıra jeton eklemek istiyorsanız (merhaba Mario), oyun kodunu değiştirerek ve jeton nesneleri eklerken ortaya çıkma noktasının boyutunu dikkate alarak bunu kolayca yapabilirsiniz. Ancak bu serinin amaçları doğrultusunda, madeni paraların ortaya çıkma noktalarının 1x1 olduğunu varsayıyoruz.


Tiled düzenleyicide seviyemizi açın ve Coins adında yeni bir nesne katmanı oluşturun. Daha sonra Dikdörtgen aracını kullanarak oyun motorunu kullanarak jeton bileşenleri ekleyebilmemiz için haritaya birkaç ortaya çıkma noktası ekleyin. Seviyem artık şöyle görünüyor:


Madeni paralar için ortaya çıkan puanlar


Oyunumuzun oldukça basit olduğunu ve bu boş dikdörtgenlerin oyun süresinde jetonlara dönüşeceğini bildiğimizi eklemeliyim. Ancak daha fazla nesne türü eklemek istersek bunları ayırt etmek zorlaşacaktır. Neyse ki Tiled'ın bunun için "Döşeme Ekle" adı verilen ve her nesne için görsel ipuçları ekleyebilen bir aracı var, ancak bu görüntüler oyunda oluşturulmayacak.


Tamam, seviyeyi kaydedin ve IDE'ye dönün. Coin sınıfımızı /objects/ klasörüne ekleyelim.

 class Coin extends SpriteAnimationComponent with HasGameRef<PlatformerGame> { late final SpriteAnimation spinAnimation; late final SpriteAnimation collectAnimation; Coin(Vector2 position) : super(position: position, size: Vector2.all(48)); @override Future<void> onLoad() async { spinAnimation = SpriteAnimation.fromFrameData( game.images.fromCache(Assets.COIN), SpriteAnimationData.sequenced( amount: 4, textureSize: Vector2.all(16), stepTime: 0.12, ), ); collectAnimation = SpriteAnimation.fromFrameData( game.images.fromCache(Assets.COIN), SpriteAnimationData.range( start: 4, end: 7, amount: 8, textureSize: Vector2.all(16), stepTimes: List.filled(4, 0.12), loop: false ), ); animation = spinAnimation; final hitbox = RectangleHitbox() ..collisionType = CollisionType.passive; add(hitbox); return super.onLoad(); } }


Döndürme ve toplama için 2 farklı animasyonumuz ve daha sonra oynatıcıyla çarpışmaları kontrol etmek için bir RectangleHitbox animasyonumuz var.


Ardından, game.dart dönün ve coinlerimizi oluşturmak için spawnObjects yöntemini değiştirin:

 final coins = tileMap.getLayer<ObjectGroup>("Coins"); for (final coin in coins!.objects) { add(Coin(Vector2(coin.x, coin.y))); }


Oyunu çalıştırın ve eklenen paraları görün:

Oyun, her ortaya çıkma noktası için CoinComponent'i ekledi


Şimdi oyuncu onları topladığında onları yok edelim.


coin.dart dönün ve collect yöntemini ekleyin:

 void collect() { animation = collectAnimation; collectAnimation.onComplete = () => { removeFromParent() }; }


Bu yöntem çağrıldığında, dönen animasyonu toplama animasyonuna geçireceğiz ve bittiğinde bu bileşeni oyundan kaldıracağız.


Ardından theboy.dart sınıfına gidin ve onCollisionStart yöntemini geçersiz kılın:

 @override void onCollisionStart(Set<Vector2> intersectionPoints, PositionComponent other) { if (other is Coin) { other.collect(); } super.onCollisionStart(intersectionPoints, other); }


onCollision yerine onCollisionStart kullanmamızın nedeni, çarpışma geri çağrısının yalnızca bir kez tetiklenmesini istememizdir.


Paralar artık The Boy ile çarpıştığında kayboluyor. Toplanan paraların sayısını takip etmek için kullanıcı arayüzünü ekleyelim.


HUD'yi ekleme

HUD veya uyarı ekranı, oyunla ilgili her türlü bilgiyi görüntüleyen bir durum çubuğudur: can puanları, cephane vb. Toplanan her para için bir jeton simgesi görüntüleyeceğiz.


Basitlik adına, jetonların sayısını bir değişkende saklayacağım, ancak daha karmaşık arayüzler için, oyun durumunu uygun bir şekilde güncellemenize ve gözlemlemenize olanak tanıyan bir flame_bloc paketi kullanmayı düşünün.


HUD mantığını içerecek yeni bir sınıf ekleyin: lib/hud.dart

 class Hud extends PositionComponent with HasGameRef<PlatformerGame> { Hud() { positionType = PositionType.viewport; } void onCoinsNumberUpdated(int total) { final coin = SpriteComponent.fromImage( game.images.fromCache(Assets.HUD), position: Vector2((50 * total).toDouble(), 50), size: Vector2.all(48)); add(coin); } }


Burada iki ilginç şey var:


  1. HUD'umuzu ekranın köşesine yapıştırmak için positionType PositionType.viewport olarak ayarladık. Bunu yapmazsak kamera hareketi nedeniyle HUD seviyeyle birlikte hareket edecektir.
  2. Oyuncu parayı her topladığında onCoinsNumberUpdated yöntemi çağrılacaktır. Bir sonraki jeton simgesinin uzaklığını hesaplamak için total parametreyi kullanır ve ardından hesaplanan konuma yeni bir jeton grafiği ekler.


Ardından game.dart dosyasına dönün ve yeni sınıf değişkenleri ekleyin:

 int _coins = 0; // Keeps track of collected coins late final Hud hud; // Reference to the HUD, to update it when the player collects a coin


Daha sonra onLoad yönteminin altına Hud bileşenini ekleyin :

 hud = Hud(); add(hud);


Ve yeni bir yöntem ekleyin:

 void onCoinCollected() { _coins++; hud.onCoinsNumberUpdated(_coins); }


Son olarak, Coin collect yönteminden çağırın :

 void collect() { game.onCoinCollected(); animation = collectAnimation; collectAnimation.onComplete = () => { removeFromParent() }; }

Harika, HUD'ımız artık kaç para topladığımızı gösteriyor!


Sol üst köşedeki HUD, toplanan paraları gösterir


Kazanma ekranı

Eklemek istediğim son şey, oyuncu tüm paraları topladığında görüntülenecek olan Kazanma ekranıdır.


PlatformerGame sınıfına yeni bir const ekleyin :

 late int _totalCoins;


Ve ona seviyede sahip olduğumuz jeton sayısını atayın. Bu satırı spawnObjects yönteminin altına ekleyin :

 _totalCoins = coins.objects.length;


Ve bunu onCoinCollected yönteminin altına ekleyin.


import 'package:flutter/material.dart'; eklemeniz gerekebileceğini unutmayın. manuel olarak.

 if (_coins == _totalCoins) { final text = TextComponent( text: 'U WIN!', textRenderer: TextPaint( style: TextStyle( fontSize: 200, fontWeight: FontWeight.bold, color: Colors.white, ), ), anchor: Anchor.center, position: camera.viewport.effectiveSize / 2, )..positionType = PositionType.viewport; add(text); Future.delayed(Duration(milliseconds: 200), () => { pauseEngine() }); }


Burada jeton sayacının seviyedeki jeton sayısına eşit olup olmadığını kontrol ediyorum ve oyun ekranının üstüne bir Kazanma etiketi ekleyip eklemediğimi kontrol ediyorum. Daha sonra oyuncunun hareketini durdurmak için oyunu duraklatın. Ayrıca etiketin duraklatmadan önce işlenmesi için 200 ms'lik bir gecikme ekledim.


Şunun gibi görünmeli:

Son parayı topladıktan sonra Kazanma ekranı görüntülenir


Ve oyun budur! Elbette şu anda bitmiş bir oyun gibi görünmüyor ancak anlattığım her şeyle birlikte daha fazla seviye, düşman veya diğer toplanabilir öğeler eklemek oldukça kolay olmalı.


Özet

Bu bölüm seriyi sonlandırıyor.


Flame motorunun, Forge2D fizik motoru, parçacıklar, efektler, oyun menüleri, ses vb. dahil olmak üzere ele almadığım çok daha fazlasını sunması mümkündür. Ancak bu seriyi tamamladıktan sonra motorun neye benzediğini anladım ve artık Daha karmaşık oyunların nasıl geliştirileceğine dair bir anlayışa sahip olun.


Alev, güçlü ancak kullanımı kolay ve öğrenmesi kolay bir araçtır. Box2D gibi diğer harika şeylerin getirilmesine olanak tanıyan modülerdir ve aktif olarak bakımı yapılır. Ancak Flame'in en büyük avantajlarından biri Flutter'ın üzerine kurulmuş olması, bu da küçük bir ek çalışma ile çoklu platform desteği sağlaması anlamına geliyor. Ancak Flutter eklentisi olmak, tüm Flutter sorunlarının Flame'de de devam ettiği anlamına gelir. Örneğin, Flutter'ın kenar yumuşatma hatası birkaç yıldır çözülmeden açıktı ve bunu bizim geliştirdiğimiz oyunda da fark edebilirsiniz. Ancak genel olarak denemeye değer oyunlar oluşturmak için harika bir araçtır.


Serinin diğer hikayeleri:

Bu eğitimin tam kodunu github'ımda bulabilirsiniz

Kaynaklar

Her bölümün sonuna harika yaratıcıların ve öğrendiğim kaynakların bir listesini ekleyeceğim.