4. マップ表示の基礎知識
はじめに
マップを表示する方法を調べていたのですが、思ったよりややこしいので、まずは情報を整理します。
基本知識
まず、Tileset(マップチップ=画像)とTilemap(マップデータ)があります。マップデータには地形の他にも、衝突判定をしたり、キャラの配置などの情報も必要で、それらはLayerで管理します。
また、マップ作成には、Tiledという別アプリを使うことが一般的なようです。(Phaser Editorでマップ作成する方法もあります。)
- Tilemap : タイル配置情報。Tiled で作成し、Phaser に JSON で読み込む。
- Tileset : タイル画像(マップチップ)。Tiled で切り出す元画像。
- Layer : Tiled 上で地形/衝突/オブジェクトを分ける単位。Phaser 上も同名で扱う。
マップスクロールは、Cameraを使います。プレイヤーにカメラを固定するだけで、簡単にスクロールは実現します。
Phaser Editorのシーンエディタを使う方法
GUIでシーンにTilemapなどのオブジェクトを追加していきます。 マップ表示には、TilemapとEditable Tilemapの2つが用意されています。 最終的にはScene.tsのコードを出力して、それをプロジェクトで使うことになります。
1. Tilemap
- Tiledという別アプリを使ってマップを作成
- JSONでエクスポート
- シーンエディタにTileset、Tilemapを追加
- (他にもあれこれ追加して)
- Scene.tsを出力
- プロジェクトに追加して使う
という流れになります。
2. Editable Tilemap
こちらは別アプリを使わず、Phaser Editor内でマップ作成ができます。 その後の流れは同じですが、マップデータはJSONではなくコード内に埋め込まれてしまいます。
// Editable Tilemapのコード例
this.cache.tilemap.add("editabletilemap_e648ec1d-81f3-4e9c", {
data: {
layers: [
{
type: "tilelayer",
name: "layer",
data: [50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
50, 50, 50, 50, ...],
// ...
},
],
},
});マップデータをコードに埋め込むと、後で大変なことになるのは目に見えています。 さすがにこれはナシでしょう。(なんでこんな仕様にした???)
結論 → シーンエディタは使わない
どちらの方法でも、シーンエディタで出力したコード(Scene.ts)に、さらに自分のコードを追加していくわけなので、後からシーンを修正したい場合には大変になりそうです。 シーンエディタを使うのは、あまり良い方法とは思えません。
自分でコードを書く方法
Phaser Editorのシーンエディタを使わない方法です。作業の流れは以下の通り。
- Tiled でマップ作成
- レイヤ1: terrain(地形)
- レイヤ2: collision(通行不可)
- レイヤ3: objects(プレイヤー初期位置・NPC・ワープなど)
- JSON でエクスポート
- Phaser 側にアセットを読み込む
- AssetPackを使用 or ファイルを指定して読み込み
- Tilemap レイヤーを作成して描画&衝突設定
- createLayer, setCollisionByProperty
- プレイヤー生成、カメラ追従、移動処理
コード例
// 基本コード例
create() {
const map = this.make.tilemap({ key: "world" });
const tiles = map.addTilesetImage("overworld", "tiles");
const ground = map.createLayer("terrain", tiles); // 地形
const collision = map.createLayer("collision", tiles)
.setCollisionByProperty({ collides: true }); // 衝突
const spawn = map.findObject("objects", o => o.name === "playerSpawn");
this.player = this.physics.add.sprite(spawn.x!, spawn.y!, "hero");
this.physics.add.collider(this.player, collision);
this.cameras.main.startFollow(this.player); // カメラ追従
}シーンエディタでも、同じようなコードが出力されるので、自分で書いた方がよさそうです。
また、Asset Packを使わず、直接ファイルを読み書きした方が便利なような気がしてきました。 せっかく課金したのにPhaser Editorを使う理由がどんどん減っていきます😇
Tips
その他、調べている中で知ったことをメモしておきます。
16x16の画像を4倍に拡大したい
キャラやマップチップは16x16ピクセルを使っているので、4倍に拡大して表示したい場合はどうすればいいのか?
前回のプレイヤーの表示の際には、sprite.setScale(4)としていましたが、今後マップチップなど全てに設定するのは大変です。
- ゲーム全体で設定する場合 → GameConfig.zoomを設定
- シーンごとに設定する場合 → Camera.setZoom()を使う
スクロールの種類を変更する
プレイヤー中心でスクロールするのか、画面端に近づくとスクロールするのかを指定する方法です。
this.cameras.main.startFollow(this.player, true); // true: 滑らかに追従
this.cameras.main.setLerp(0.2, 0.2); // 追従のなめらかさ
this.cameras.main.setDeadzone(80, 60); // キャラが画面中心からズレる範囲(デッドゾーン)
2D ライトエフェクトを使う
ダンジョンなどプレイヤーの周りが明るくなる処理はLight2Dというパイプラインで簡単にできるようです。
ground.setPipeline("Light2D");
this.lights.enable().setAmbientColor(0x202020);
this.lights.addLight(this.player.x, this.player.y, 150).setColor(0xffffff);まとめ
というわけで、マップ表示について調べていました。思ったより大変そう。 次回は実装していきます。