
2026/02/08 10:37
**「たった5つのタイルで実装するオートタイル」**
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
(その他は元のまま)**
Summary
この記事では、コーナー、サイド、対角コーナー、内向きコーナー、フル/ミドル の 5種類のベースタイルだけを使って、Godot 用に高速で低アセットな自動タイルシステムを構築する方法 を説明しています。これらのタイルをプログラム上で回転・反転させることで、全 16 通りのビジュアルパーミュテーション を生成します。
- 2 層の TileMap を使用:
- 物理層:コライダーを格納
- ビジュアル層:スプライトは –0.5 タイルオフセット で描画され、タイルの角が重なるように表示
各ビジュアルセルについて、その四隣の物理セルから得られる 4 ビットマスク がどのパーミュテーションを表示するか決定します。パーミュテーションはバイナリ値でインデックス付けされた配列に格納され、例として Godot コードでは
tileArray に各ケースの Vector2i 座標が示されています。
ゲームプレイ中にプレイヤーはマウス入力でタイルを配置・削除できます。変更後はシステムが隣接セルのマスクを再計算し、ビジュアル層を更新してグラフィックと衝突判定を同期させます。
- ヘルパー関数 は初期配置後にすべてのビジュアルをリフレッシュでき、エディタ内の UI ボタンで呼び出されます。
レベルデータ(
tile_set パスと両層のセル辞書配列を含む)は dictionary にシリアライズされ、実行時に user:// に保存されます(res:// は読み取り専用)。EditorPlugin の _enter_tree()/_exit_tree() コールバックで追加された EditorInspectorPlugin が「Import」ボタンを提供し、user:// ファイルを読み込み、重複した WorldMap ノードを再構築して該当する res:// シーンを書き換え、エディタのファイルシステムを更新します。
タイル配置、レベル管理、およびツール機能に関する完全なソースコードは著者の GitHub で入手可能です。記事では jess::codes、Nonsensical 2D、Oskar Stålberg などのリソースも引用しています。
本文
5種類のタイルで自動タイル化
著者: [あなたの名前]
日付: 2026年2月5日
概要
自動タイル化は、2Dゲーム開発において非常に便利な手法です。セルを「占有」か「空白」かでマークし、エディターが適切なビジュアルタイルを自動的に配置することで、レベル作成を大幅に簡素化します。
典型的な実装では各セルの8近傍を調べ、16〜47/56個のタイルから選択します。理論上は256通りありますが、多くのゲームではそれよりも遥かに少ない組み合わせしか使用しません。本記事では、Nonsensical 2D からインスパイアを受けた、5種類だけで済むシステムについて説明します。これでもきれいにエッジが描画されます。
コアアイデア
タイルマップは二層に分かれています:
- 物理レイヤー – 衝突判定用の「実際」のタイルを保持
- ビジュアルレイヤー – デコレーションタイルを0.5タイルオフセットし、角で描画
各ビジュアルタイルは物理レイヤー上の四隣セル(1, 2, 3, 4)を見ることができ、これらを 4ビットマスク で表現します。
┌─┬─┐ │1│2│ (近傍) ├─┼─┤ │3│4│ └─┴─┘
ビットはビジュアルタイルの四隅に対応し、各角で物理セルが占有されているかをチェックすることで、16通りのユニークな配置を決定します。
五つの基本タイル
必要なのは 5つ のテクスチャだけです:
| タイル | 説明 |
|---|---|
| コーナー | 1つの象限を占有 |
| サイド | 隣接する2象限を占有 |
| 対角コーナー | 反対側の2象限を占有 |
| 内向きコーナー | 中央に向かう隣接2象限を占有 |
| フル/ミドルピース | 4つすべての象限を占有 |
これらの基本タイルをプログラム上で回転・反転させることで、16通りのビジュアルバリアントを生成できます。Godot では各バリアントの座標をテクスチャアトラスに格納し、インデックスで参照します。
@onready var tileArray : Array[Vector2i] = [ Vector2i(4,0), # 0000 Vector2i(0,3), # 0001 TL Vector2i(0,1), # 0010 BL Vector2i(2,0), # 0011 BL TL Vector2i(0,2), # 0100 TR Vector2i(2,3), # 0101 TR TL Vector2i(1,0), # 0110 TR BL Vector2i(3,2), # 0111 TR BL TL Vector2i(0,0), # 1000 BR Vector2i(1,1), # 1001 BR TL Vector2i(2,4), # 1010 BR BL Vector2i(3,0), # 1011 BR BL TL Vector2i(2,2), # 1100 BR TR Vector2i(3,3), # 1101 BR TR TL Vector2i(3,1), # 1110 BR TR BL Vector2i(4,0) # 1111 BR TR BL TL ]
配列はビットマスク(0000 → 1111)の順序と完全に一致させる必要があります。
実行時配置
- タイルを置く – マウスイベントでグローバルカーソル位置をタイル座標へ変換。物理レイヤーのセルを更新し、周囲4つのビジュアルタイルを再計算します。
- タイルを消す – 同様にセルを空白に設定し、影響を受けるビジュアルタイルを更新します。
便利関数
update_all() はビジュアルレイヤーをクリアして全体を一度に再構築します。レベルデザイン時など、多くのセルが変更された際に有効です。
レベル保存
- WorldMap ノード をシーンツリーから取得
- 各タイルマップレイヤーを反復処理し、次の情報を配列化
– セル位置pos
– タイルIDsource_id
– アトラス内座標atlas_coords
(または回転/フリップデータ)– 任意alt
- これらをタイルセットパスで識別するキーの下に格納
var data = { "physical": _serialize_tilemap(physical), "visual" : _serialize_tilemap(visual) }
結果は次のような JSON になります。
{ "physical": { "tile_set": "res://Tilesets/physical_tileset.tres", "cells": [ { "pos": [x, y], "source_id": 0, "atlas_coords": [u, v], "alt": 0 }, ... ] }, "visual": { "tile_set": "res://Tilesets/visual_tileset.tres", "cells": [ { ... } ] } }
Godot エディタの
res:// フォルダは実行時に読み取り専用ですので、JSON は user:// に保存します。後で再びシーンへインポートできます。
EditorPlugin でのインポート
ワークフローを効率化するために、
EditorInspectorPlugin を作成し WorldMap インスペクタに Import ボタンを追加しました。ボタン押下時:
から保存データを読み込みuser://- 新しい WorldMap ノードを生成してタイルマップを配置
- 元のシーンファイル(
)を書き換えres:// - Godot のファイルシステムをリフレッシュし、エディタに更新されたレベルを表示
@tool extends EditorPlugin func _enter_tree(): add_inspector_plugin( preload("res://addons/WorldMap_importer/world_map_inspector.gd").new() ) func _exit_tree(): remove_inspector_plugin( preload("res://addons/WorldMap_importer/world_map_inspector.gd").new() )
インスペクタプラグイン自体はボタンを作成し、インポートルーチンに接続してシーン保存を行います。
リソース
- jess::codes – GitHub リポジトリ(配置・ツール全コード)
- Nonsensical 2D – このアプローチの元となった動画
- Oskar Stålberg – 自動タイル化に関する追加参考資料
ご覧いただきありがとうございます! フッターにリンクされたプラットフォームでフォローしたり、RSS で次回記事を受け取ることもできます。