はじめに
- Flutterでマルチプラットフォーム対応 (Web, モバイル, PC) のRPGゲームを作成します
- ソースコードはこちら (アセットなど一部差し替えています)
- この記事は5つのPartに分かれていて、今回はそのPart 1です
- Part 1:マップとUIの実装
- Part 2:プレイヤーと当たり判定の実装
- Part 3:マップ移動の実装
- Part 4:アイテムと取得イベントの実装
- Part 5:NPCと会話の実装
- Bonfireという2Dゲームに特化したフレームワーク(Flutterパッケージ)を利用しています
- マップ制作にはTiledという無料のGUIツールを利用しています
Tiledは必須ではありませんが、使い方も簡単で制作作業がとても捗ります - アセットはitch.ioで購入できるものを利用しています
- トップの画像は今回利用するアセットのサンプル画像です
作成するゲームについて
- 見下ろし型のRPGゲームです
- タッチパネルとキーボードの入力に対応しています
- いくつかのイベントがあります
- NPCとの会話する
- アイテムを拾う・使う
- スイッチを押して扉を開く(的なイベント)
- 戦闘はありません (Bonfireは戦闘アクションの実装機能も充実しています)
Bonfireについて
- Flutterで2DのRPGゲーム作るためのフレームワークです
- 画面やロジックの実装から、状態管理までBonfireだけで完結させることができます
- FlameというFlutter用のゲームエンジンに依存しています
- Bonfire 公式HP ← 解説やコードサンプル、Demoゲームがあります
- Flutterドキュメントページ
- Github
開発環境
OS: macOS 12.6
Flutter: 3.3.5
Bonfire: 2.10.10
Tiled: 1.9.2
Xcode: 14.0.1
テスト環境: Chrome, iOS Simulator
今回のパートの大まかな流れ
- Flutterプロジェクトとパッケージ、アセットの準備
- マップ用タイルセットの作成 (Tiled利用)
- マップの作成 (Tiled利用)
- WidgetとUIを実装して動作確認
1. Flutterプロジェクトとパッケージ、アセットの準備
1.1 プロジェクト作成
$ flutter create --platforms=web,ios simple_bonfire
- ターミナルから、プロジェクトを作成するディレクトリで
flutter create
- プラットフォームにiOSとWebを指定
- プロジェクト名
simple_bonfire
はお好みで変更可能
1.2 bonfire
パッケージの追加
- プロジェクトディレクトリで
flutter pub add
$ flutter pub add bonfire
-
pubspec.yaml
ファイルにbonfire
が追加されているのを確認
pubspec.yaml
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
bonfire: ^2.10.10
1.3 アセットの準備
-
こちらなどからタイルセット画像を取得
無料で利用できるのアセットもたくさんあります - ダウンロードした画像を
simple_bonfire/assets/images/maps
に配置
(simple_bonfire
はFlutterプロジェクト名) -
pubspec.yaml
に追加したアセットのディレクトリを記載
pubspec.yaml
flutter:
uses-material-design: true
assets:
- assets/images/
- assets/images/maps/
2. マップ用タイルセットの作成
- 元のpngファイルをタイルセットとして利用するための設定jsonファイルを作成します
- このjsonファイルを作成するためのツールがTiledです
2.1 Tiledプロジェクトの作成
- こちらよりTiledをダウンロードしてください
- Tiledを起動して、
New Project...
を選択しsimple_bonfire/assets/images/maps
下にプロジェクトを作成
simple_bonfire.tiled-project
とsimple_bonfire.tiled-session
の2つのファイルが生成されます
2.2 アセットpngファイルの登録と分割
-
新しいタイルセット
を選択し、ポップアップのフィールドにそれぞれ値を入力
- 名前:タイルセットにわかりやすい名前をつける
- 種類:均等にタイルが… (デフォルト)
- 画像:先にダウンロードしたアセットpngファイルを選択
- タイルの幅、高さ:アセットに合わせて
16px
に変更
-
ファイル名をつけて保存
を選択し.tsj
で保存した後、.json
に変更する
(json
に変更するのはいろいろと便利のため)
assets/maps/franuka_halloween_tileset.json
{
"columns": 32,
"image": "franuka_halloween_tileset.png",
"imageheight": 512,
"imagewidth": 512,
"margin": 0,
"name": "franuka_halloween_tileset",
"spacing": 0,
"tilecount": 1024,
"tiledversion": "1.9.2",
"tileheight": 16,
"tilewidth": 16,
"type": "tileset",
"version": "1.9"
}
3. マップの作成
- まず、作成したタイルセットを使ってマップ生成用jsonファイルを生成します
- Tiledで
ファイル
>新規
>新しいマップ
の順に選択 - ポップアップのフィールドにそれぞれ値を入力
- 種類:四角型タイル (デフォルト)
- 出力形式:CSV (デフォルト)
- 描画順序:左から右、上から下 (デフォルト)
- マップの大きさ:任意の値を入力
- タイルの大きさ:アセットに合わせて幅、高さともに
16px
- マップ編集画面が表示されたら、まず地面のレイヤーを作成
- 壁やオブジェクト用のレイヤーを作成
-
ファイル
>保存
を選択し.tmj
形式で保存後、拡張子は.json
に変更
assets/maps/halloween_map_01.json
{
"compressionlevel": -1,
"height": 16,
"infinite": false,
"layers": [
{
"data":[514, 514, 514, 514, 514, 514, 514, 514, 514, 514, 514, 514, 514, 514, 514, 514, 514, 514, 514, 514,
"...とても長いので中略..."
514, 514, 514, 514, 514, 514, 514, 514, 514, 514, 514, 514, 514, 514, 514, 514, 514, 514, 514, 514],
"height":16,
"id":1,
"name":"\u30bf\u30a4\u30eb\u30ec\u30a4\u30e4\u30fc1",
"opacity":1,
"type":"tilelayer",
"visible":true,
"width":20,
"x":0,
"y":0
},
{
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 13, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 15, 0,
0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0,
"...とても長いので中略...",
0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0,
0, 77, 18, 18, 18, 18, 18, 19, 0, 0, 0, 0, 17, 18, 18, 18, 18, 18, 79, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"height": 16,
"id": 2,
"name": "\u30bf\u30a4\u30eb\u30ec\u30a4\u30e4\u30fc2",
"opacity": 1,
"type": "tilelayer",
"visible": true,
"width": 20,
"x": 0,
"y": 0
}
],
"nextlayerid": 3,
"nextobjectid": 1,
"orientation": "orthogonal",
"renderorder": "right-down",
"tiledversion": "1.9.2",
"tileheight": 16,
"tilesets": [
{
"firstgid": 1,
"source": "franuka_halloween_tileset.json"
}
],
"tilewidth": 16,
"type": "map",
"version": "1.9",
"width": 20
}
4 WidgetとUIを実装して動作確認
- 作成したマップ生成用jsonファイルを使い、FlutterのWidgetを作成します
4.1 マップWidgetの作成
- Statefull Widgetの
build
でBonfireWidget
をreturn
します -
BonfireWidget
内で以下の3つを設定しています- マップ用jsonファイルの読み込み
- 画面上にジョイスティックやボタンと、キーボードの入力の有効化
- 遷移直後の読み込み画面
- 細かな説明はコメントに留めます
lib/maps/halloween_map_01.dart
import 'package:flutter/material.dart';
import 'package:bonfire/bonfire.dart';
import 'package:flutter/services.dart';
class HalloweenMap01 extends StatefulWidget {
const HalloweenMap01({Key? key}) : super(key: key);
@override
State<HalloweenMap01> createState() => _HalloweenMap01State();
}
class _HalloweenMap01State extends State<HalloweenMap01> {
final tileSize = 48.0; // タイルのサイズ定義
@override
Widget build(BuildContext context) {
// ゲーム画面Widget
return BonfireWidget(
// マップ用jsonファイル読み込み
map: WorldMapByTiled(
'maps/halloween_map_01.json',
forceTileSize: Vector2(tileSize, tileSize),
),
// 入力インターフェースの設定
joystick: Joystick(
// 画面上のジョイスティック追加
directional: JoystickDirectional(
color: Colors.white,
),
actions: [
// 画面上のアクションボタン追加
JoystickAction(
color: Colors.white,
actionId: 1,
margin: const EdgeInsets.all(65),
),
],
// キーボード用入力の設定
keyboardConfig: KeyboardConfig(
keyboardDirectionalType: KeyboardDirectionalType.wasdAndArrows, // キーボードの矢印とWASDを有効化
acceptedKeys: [LogicalKeyboardKey.space], // キーボードのスペースバーを有効化
),
),
// ロード中の画面の設定
progress: Container(
width: double.maxFinite,
height: double.maxFinite,
color: Colors.black,
),
);
}
}
4.2 マップWidgetの実装
- いよいよ作成したマップを表示してゲームを動かします
-
MaterialApp
のhome
に作成したマップWidgetを入れます
lib/main.dart
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:bonfire/bonfire.dart';
import 'package:simple_bonfire/maps/halloween_map_01.dart';
void main() async {
// iOSでは横画面にする
WidgetsFlutterBinding.ensureInitialized();
if (!kIsWeb) {
await Flame.device.setLandscape();
await Flame.device.fullScreen();
}
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Simple Bonfire',
debugShowCheckedModeBanner: false,
home: HalloweenMap01(),
);
}
}
4.3 起動して表示と動作の確認
おわりに
アセットやマップの準備には外部のツールも使用し一手間かかりましたが、Flutterの実装部分はとてもシンプルだったと思います。
次回はプレイヤーを実装し、当たり判定などゲームとして必要な要素をさらに追加していきます。
いいね、質問やコメントお待ちしております!