これは、Flame エンジンを使用して単純なプラットフォーマー ゲームを作成する方法を学ぶ 4 部構成のシリーズの最終回です。 The Boy という名前のアニメーション化されたプレイヤー キャラクターを追加する方法、Tiled エディターを使用してスクロール なゲーム は既にわかっています。 可能 レベルを作成する方法、衝突検出を使用して重力とジャンプを追加する方法 (パート 1、2、3 ) この部分では、キャラクターが収集できるコイン、プレイヤーが持っているコインの数を表示する HUD、およびすべてのコインが収集されたときに表示される勝利画面を追加します。 コインの追加 コインをスポーンする場所 (またはその他のゲーム オブジェクト) をゲームに伝える必要があります。ご想像のとおり、Tiled エディターを使用して、プラットフォームを追加したのと同様の方法で別のオブジェクト レイヤーを追加しますが、2 つの違いがあります。 プラットフォームでは、スプライト イメージをレベル データに焼き付けました。この方法はコインにはあまり適していません。プレイヤーがオブジェクトを収集したら、オブジェクトを削除したいからです。そのため、スポーン ポイントを追加して、コインがゲーム内のどこに出現するかを把握し、Flame コンポーネントを使用してレンダリングを行います。 プラットフォームには任意のサイズの長方形を使用しましたが、コインにはスポーン ポイントを 1 タイルのサイズになるように追加します。ただし、コインの列を次々と追加したい場合 (こんにちはマリオ)、ゲーム コードを変更し、コイン オブジェクトを追加するときにスポーン ポイントのサイズを考慮することで、簡単に行うことができます。しかし、このシリーズの目的のために、コインのスポーン ポイントは 1x1 であると想定しています。 Tiled エディターでレベルを開き、Coins という新しいオブジェクト レイヤーを作成します。次に、Rectangular ツールを使用して、マップ全体にいくつかのスポーン ポイントを追加し、ゲーム エンジンを使用してコイン コンポーネントを追加します。私のレベルは次のようになります。 私たちのゲームはかなり単純であり、これらの空の四角形がゲームの実行時にコインに変わることがわかっていることを付け加えておきます。しかし、さらにオブジェクト タイプを追加すると、それらを区別することが難しくなります。幸いなことに、Tiled には「Insert Tile」というツールがあり、すべてのオブジェクトに視覚的な合図を追加できますが、これらの画像はゲームでレンダリングされません。 レベルを保存して IDE に戻ります。 クラスを フォルダーに追加しましょう。 Coin /objects/ 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(); } } 回転と収集のための 2 つの異なるアニメーションと、後でプレイヤーとの衝突をチェックするための があります。 RectangleHitbox 次に、 game.dart に戻り 、 spawnObjects メソッドを変更してコインを生成します。 final coins = tileMap.getLayer<ObjectGroup>("Coins"); for (final coin in coins!.objects) { add(Coin(Vector2(coin.x, coin.y))); } ゲームを実行すると、追加されたコインが表示されます: プレイヤーがそれらを収集すると、それらが消えるようにしましょう。 coin.dart に戻り 、 collect メソッドを追加します。 void collect() { animation = collectAnimation; collectAnimation.onComplete = () => { removeFromParent() }; } このメソッドが呼び出されると、回転するアニメーションを収集するアニメーションに切り替えます。終了したら、このコンポーネントをゲームから削除します。 次に、 theboy.dart クラスに移動し、 onCollisionStart メソッドをオーバーライドします。 @override void onCollisionStart(Set<Vector2> intersectionPoints, PositionComponent other) { if (other is Coin) { other.collect(); } super.onCollisionStart(intersectionPoints, other); } の代わりに を使用する理由は、衝突コールバックを 1 回だけトリガーするためです。 onCollision onCollisionStart コインがザ・ボーイと衝突すると消えるようになりました。収集したコインの数を追跡するためのユーザー インターフェイスを追加しましょう。 HUD の追加 HUD (ヘッドアップ ディスプレイ) は、ゲームに関する情報 (ヒット ポイント、弾薬など) を表示する単純なステータス バーです。収集したコインごとにコイン アイコンを表示します。 簡単にするために、コインの数を変数に格納しますが、より複雑なインターフェイスの場合は、便利な方法でゲームの状態を更新および監視できる パッケージの使用を検討してください。 flame_bloc HUD ロジックを含む新しいクラスを追加します: 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); } } ここで興味深いことが 2 つあります。 に設定して、HUD を画面の隅に固定します。そうしないと、カメラの動きにより、HUD がレベルと共に移動します。 positionType PositionType.viewport メソッド 、プレーヤーがコインを収集するたびに呼び出されます。 パラメータを使用して次のコイン アイコンのオフセットを計算し、計算された位置に新しいコイン スプライトを追加します。 onCoinsNumberUpdated total 次に、 game.dart ファイルに戻り、新しいクラス変数を追加します。 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 メソッド コンポーネントを追加します 次に、 onLoad の下部に Hud 。 hud = Hud(); add(hud); そして、新しいメソッドを追加します: void onCoinCollected() { _coins++; hud.onCoinsNumberUpdated(_coins); } 最後に、 の Coin collect メソッド から呼び出します 。 void collect() { game.onCoinCollected(); animation = collectAnimation; collectAnimation.onComplete = () => { removeFromParent() }; } 見事、HUD に収集したコインの数が表示されるようになりました! 勝利画面 最後に追加したいのは、プレイヤーがすべてのコインを集めると表示される Win 画面です。 クラス PlatformerGame に新しい const を追加します 。 late int _totalCoins; 次の行を メソッド そして、レベルにあるコインの数をそれに割り当てます。 spawnObjects の最後に追加します 。 _totalCoins = coins.objects.length; これを メソッドの一番下に追加します。 onCoinCollected 追加する必要がある場合があることに注意してください。手動で。 import 'package:flutter/material.dart'; 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() }); } ここでは、コイン カウンターがレベル内のコインの数と等しいかどうかをチェックし、等しい場合はゲーム画面の上に Win ラベルを追加します。次に、ゲームを一時停止してプレイヤーの動きを止めます。また、ラベルが一時停止する前にレンダリングされるように、200 ミリ秒の遅延を追加しました。 次のようになります。 そして、それがゲームです!もちろん、今は完成したゲームのようには見えませんが、私が説明したすべてのことで、レベル、敵、またはその他の収集可能なアイテムを追加するのはかなり簡単になるはずです. まとめ このパートでシリーズは終了です。 Flame エンジンには、物理エンジンの Forge2D、パーティクル、エフェクト、ゲーム メニュー、オーディオなど、ここでは取り上げなかった多くの機能があります。より複雑なゲームを構築する方法を理解している。 Flame は強力でありながら使いやすく学習しやすいツールです。これはモジュラーであり、Box2D のような他のクールなものを持ち込むことができ、積極的に維持されています。ただし、Flame の最大の利点の 1 つは、Flutter の上に構築されていることです。つまり、少し追加作業を行うだけでマルチプラットフォームのサポートが提供されます。ただし、Flutter 拡張機能であるということは、すべての Flutter の問題が Flame でも存続することを意味します。たとえば、 解決されずに数年間開かれており、私たちが構築したゲームでもそれに気付くかもしれません。しかし、全体として、試してみる価値のあるゲームを構築するための優れたツールです。 Flutter のアンチエイリアシングのバグは シリーズの他のストーリー: キャラクターに Flame での実行を教える Flame でレベルを設計する 衝突検出を使用してゲーム キャラクターをジャンプさせる このチュートリアルの完全なコードは、 にあります。 私の github 資力 各パートの最後に、私が学んだすばらしいクリエイターとリソースのリストを追加します。 GrafxKid のアーケード プラットフォーマー アセット タイル エディターのドキュメント DevKage の Flame ゲーム開発シリーズ: https://youtu.be/mSPalRqZQS8 Craig Oda のチャンネル https://youtu.be/hwQpBuZoV9s Ember Quest ゲーム チュートリアル フレームエンジンのドキュメント