🗿

Flutter, Flame を使った画像表示(その3)

4 min read

今回の目標

画面をタップしている間、画像がアニメーションを行い、画像から指を離すとアニメーションが止まるアプリに変える。

用意するもの

  • 前回のプロジェクト
  • 静止画
  • アニメーション画像

今回は動作時のアニメーション画像、静止画の2種類が必要となります。
アニメーション画像は前回の画像を使います。
静止画は前々回利用した画像を 1/10 にした画像を使います。
(80ピクセルx80ピクセルの画像サイズにします)

不要なオブジェクトを除去する

まず、main関数から、今回使わなくなるNoukaクラスを削除します。importも必要なくなるので一緒に削除します。

main
-import 'nouka.dart';

・・・・・

class MyApp extends FlameGame {

+  late NoukaSpin noukaSpin

  
  Future<void> onLoad() async {
-    final nouka = Nouka();
-    add(nouka);
-
-    final noukaSpin = NoukaSpin();
+    noukaSpin = NoukaSpin();
    add(noukaSpin);
  }
  
}

これで左上の農家画像が削除されました。
noukaSpin変数は今後を考えて、onLoad関数の外に出します。

画像の準備

次にアニメーションを動作させるための静止画とアニメーション画像を準備します。
アニメーション画像はその2で利用したものを使いましょう。
静止画はその1で利用した画像を使いましょう。

静止画、アニメーション画像を読み込む

まず初めにenumで、状態を定義します。

NoukaSpin.dart
import 'package:flame/components.dart';
import 'package:flame/game.dart';

+enum NoukaState {
+  idle,
+  spin,
+}

次にNoukaSpinクラスで静止画、アニメーション画像の読み込みを追加しますが、どちらの画像も前回、NoukaSpinクラスで利用した読み込み方法を削除した上で、別の読み込み方法を使います。

onLoad()
class NoukaSpin extends FlameGame {
+  late SpriteAnimationGroupComponent nouka;

  Future<void> onLoad() async {
    await super.onLoad();

-    final noukaSpin = await images.load('nouka_renkon_syukaku_spin.png');
-
-     final noukaSpinComponent = SpriteAnimationComponent.fromFrameData(
-      noukaSpin,
-      SpriteAnimationData.sequenced(
-        amount: 4,
-        textureSize: Vector2(80.0, 80.0),
-        stepTime: 0.5,
-        loop: true,
-      ),
-      size: Vector2(80.0, 80.0),
-      position: size / 2,
-      anchor: Anchor.center,
-    );
-
-    add(noukaSpinComponent);
-
+    final spin = await loadSpriteAnimation(
+      'nouka_renkon_syukaku_spin.png',
+      SpriteAnimationData.sequenced(
+        amount: 4,
+        stepTime: 0.5,
+        textureSize: Vector2.all(80.0),
+        loop: true,
+      ),
+    );
+
+    final idle = await loadSpriteAnimation(
+      'nouka_renkon_syukaku_mini.png',
+      SpriteAnimationData.sequenced(
+        amount: 1,
+        stepTime: 1,
+        textureSize: Vector2.all(80.0),
+      ),
+    );
+
+    nouka = SpriteAnimationGroupComponent<NoukaState>(
+      animations: {
+        NoukaState.idle: idle,
+        NoukaState.spin: spin,
+      },
+      current: NoukaState.idle,
+      position: size / 2,
+      size: Vector2.all(80.0),
+      anchor: Anchor.center,
+    );
+    add(nouka);
  }
}

変数spinはアニメーション画像の定義になります。
変数idleは静止画の定義になります。
アニメーション画像は前回、SpriteAnimationComponentにて読み込んでいましたが、今回はloadSpriteAnimationを利用して読み込みます。
静止画も同様にloadSpriteAnimationを利用して読み込みます。
最後に両方のコンポーネントを持つ、SpriteAnimationGroupComponentを定義します。
画像の読み込みはこれで完了です。

タップのイベントを検知する

タップのイベントはTapDetectorを宣言することで検知できます。
以下のようにすることで、TapDetectorの関数が利用可能となります。

MyApp
-class MyApp extends FlameGame {
+class MyApp extends FlameGame with TapDetector {

TapDetectorを宣言したら、MyAppに関数を追加しましょう。

MyApp
class MyApp extends FlameGame with TapDetector {

  late NoukaSpin noukaSpin;
  
  
  Future<void> onLoad() async {
    noukaSpin = NoukaSpin();
    add(noukaSpin);
  }

+  
+  void onTapDown(TapDownInfo info){
+    super.onTapDown(info);
+
+  }
+
+  
+  void onTapUp(TapUpInfo info){
+    super.onTapUp(info);
+
+  }
}

これでタップを検知出来るようになりました。

タップした時の処理を追加する

タップを検知出来るようになっても、処理がなければ意味がありません。
まずはNoukaSpinクラスに処理を追加しましょう。

NoukaSpin
class NoukaSpin extends FlameGame {

  late SpriteAnimationGroupComponent nouka;

・・・・・・・・・・


+  
+  void noukaSpin() {
+    nouka.current = NoukaState.spin;
+  }
+
+  
+  void noukaIdle() {
+    nouka.current = NoukaState.idle;
+  }
}

静止画とアニメーション画の切り替えは状態を変更することで行えます。
次に先ほど追加したMyApponTapDown, onTapUpNoukaSpinクラスの処理を記述します。

MyApp
  
  void onTapDown(TapDownInfo info){
    super.onTapDown(info);

+    noukaSpin.noukaSpin();
  }

  
  void onTapUp(TapUpInfo info){
    super.onTapUp(info);

+    noukaSpin.noukaIdle();
  }

以上で完了になります。
これでタップしている間は回転し、離すと静止画に戻るようになりました。

使ってみると思っていた動きと違う部分もあります。
僕の場合はタップした状態から指を動かして、指を離すと動きが止まりませんでした。
おそらく必要な処理が足りていないのだと思います。
ただ、まだその辺りの調査が完了していないため、終わり次第ここに載せたいなと考えています。

Discussion

ログインするとコメントできます