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.
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:
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.
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:
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:
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 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:
positionType
PositionType.viewport
olarak ayarladık. Bunu yapmazsak kamera hareketi nedeniyle HUD seviyeyle birlikte hareket edecektir.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!
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:
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ı.
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.
Bu eğitimin tam kodunu github'ımda bulabilirsiniz
Her bölümün sonuna harika yaratıcıların ve öğrendiğim kaynakların bir listesini ekleyeceğim.