FlutterでSpineアニメーションを再生してみる
Flutter用のSpineランタイムが登場
Spine公式よりFlutterランタイムがアナウンスされていましたので、早速触ってみました。
spine_flutterパッケージの導入方法
FlutterアプリでSpineアニメーションを再生するには、spine_flutter パッケージが必要です。
早速組み込んでいきます。
動作環境
ツール | バージョン |
---|---|
fvm | 2.4.1 |
Flutter | 3.10.0 |
spine_flutter | 4.1.1 |
flutterアプリ作成
まずはflutterアプリを作成します。
私はfvmを使っているので、fvm 〜
でコマンドを実行します。
fvm flutter create pub_flutter_spine_animation_example
pubspec.yamlを更新
dependenciesにspine_flutterを追記
spine_flutter 4.2.13 | pub devのコピーアイコンを押下して、yamlに記載する文字列をコピーします。
コピーした文字列をpubspec.yamlのdependenciesに貼り付けます。
name: pub_flutter_spine_animation_example
description: A new Flutter project.
…中略…
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
spine_flutter: ^4.1.1 # ←新規追加
※Flutterとspine_flutterのバージョンの整合性は要チェックです!
現時点(2023.07.09時点)の最新のspine_flutter(v4.2.13)を動作させたい場合は、Flutterはv3.10.5以上である必要があります。
assetsを更新
次にpubspec.yamlのassetsを更新します。
ここで指定したassetsディレクトリに、Spineエクスポートファイルを格納先になります。
name: pub_flutter_spine_animation_example
description: A new Flutter project.
…中略…
flutter:
assets:
- assets/ # ←新規追加
pub get を実行
pubspec.yamlを更新後に fvm flutter pug get
を実行します。
これでspine_flutterがインストールされたはずです。
spineエクスポートファイルをFlutterアプリに格納する
次に、spineアニメーションのエクスポートファイルをFlutterアプリに格納します。
出力形式ですが、.jsonでも.skelでも、どちらでも良いみたいです。
./
├── lib
│ └── main.dart
├── assets
│ ├── spineboy-pro.atlas ← 新規追加
│ ├── spineboy-pro.json ← 新規追加
│ └── spineboy-pro.png ← 新規追加
└── その他 …
main.dartを更新する
最後にmain.dartを更新します。要点は以下の4点です。
import 'package:flutter/material.dart';
import 'package:spine_flutter/spine_flutter.dart'; // …1.
void main() async {
WidgetsFlutterBinding.ensureInitialized(); // …2.
await initSpineFlutter(enableMemoryDebugging: false); // …2.
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const SpineExamplePage(),
);
}
}
class SpineExamplePage extends StatelessWidget {
const SpineExamplePage({super.key});
@override
Widget build(BuildContext context) {
final controller = SpineWidgetController(onInitialized: (controller) {
controller.animationState.setAnimationByName(0, "walk", true);
});
return Scaffold(
appBar: AppBar(title: const Text('Spine Example')),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
decoration: const BoxDecoration(
color: Colors.pink,
),
height: 400,
width: 400,
child: SpineWidget.fromAsset("assets/spineboy-pro.atlas",
"assets/spineboy-pro.json", controller), // …3.
),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () {
// …4.
if (controller.animationState
.getCurrent(0)
?.getAnimation()
.getName() ==
"walk") {
controller.animationState.setAnimationByName(0, "idle", true);
} else {
controller.animationState.setAnimationByName(0, "walk", true);
}
},
child: const Text('Toggle Animation'))
],
)),
);
}
}
- spine_flutter パッケージを読み込みます。
- main関数にて、
WidgetsFlutterBinding.ensureInitialized
とinitSpineFlutter
を実行します。- spine_flutter Setupに記載されている通り、2行分をmain関数内に記載します。main関数にasyncをつけるのを忘れないように。
- SpineWidgetを利用して、Spineエクスポートファイルを読み込みます
-
example/lib
/simple_animation.dartの通りに実装します。Spineをjsonでエクスポートしている場合は、SpineWidget.fromAsset
の第一引数の拡張子を.jsonにします。.skelなら、.skelにします。
-
example/lib
- ボタン押下時のアニメーション切り替え処理を実装
-
controller.animationState.setAnimationByName
でアニメーションを切り替えています。引数は順にトラック番号、アニメーション名、ループするか です。 -
controller.animationState.getCurrent(0)?.getAnimation().getName()
でトラック0のアニメーション名を取得しています。取得したアニメーション名が walk なのか idle なのかを判定して、それ以降の処理につなげています。
-
実際に動かしてみる
作成したFlutterプロジェクトのGithib リポジトリはこちら
まとめ
サンプルコードが用意されているおかげで、簡単に試せました。
spine-flutter Runtime Documentationを見てみると、Flutter Flameにも対応しているようなので、クロスプラットフォームゲームの作成にも使えそうですね。
FlutterだとRiveという強力なライバルがいますので、そちらとの棲み分けも気になるところ。
では、また。
Discussion