1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「連続3回詰まった」は物理エンジンの事実ではない — qiitaコメント欄の議論から生まれた移動仲裁層

1
Last updated at Posted at 2026-10-23

先日公開した 2D 配置エンジン「Kimetron Isle」の Qiita 記事のコメント欄で、Albertn さん(@Albertn)とやり取りをしました。その議論がそのまま1個の OSS になったので、経緯を含めて3回に分けて書きます。

出来上がったのは、ユニット移動の仲裁を担う中間層「SAGBAL(サグバル)」です。MIT ライセンスで公開しています。

この第1回は「なぜ層を作ることにしたか」という設計の話です。

発端: エンジンは何を返すべきか

Kimetron Isle は「配置」をデータとして扱う 2D エンジンです。tryMove という API で移動を試みて、成否と拒否理由を返します。記事で紹介したデモでは、ユニットが建物内を徘徊していました。

そこでコメント欄で話題になったのが、**「移動が拒否されたとき、エンジンはどこまで報告すべきか」**という問題です。議論の中で確立した線引きはこうでした:

  • エンジンが出せるのは一時点の事実だけ。「この移動は成立する/しない」「X がそれを塞いでいる」
  • 「連続 N 回遮られた」「この場所に滞留している」は解釈であって事実ではない。組み立ては外側でやる
  • 拒否情報は二系統で出す。理由コード(機械的分類)とブロッカー id(意味論参照)。id さえあれば、利用側はそれが「壁なのか他のユニットなのか、あのうるさい隣人なのか」を再構成できる
  • 利用側の語彙をエンジンの enum に逆流させない。custom + tag: string で素通しさせる

最後のやつが効きます。「ドア」「敵」「優先度高いユニット」といったアプリ固有の語彙をエンジンに教え込んでしまうと、エンジンはそのアプリ専用になっていきます。語彙を逆流させないために、エンジン側は「素通しできる窓」を用意する——この発想はその後の設計全体を支配しました。

問題: 事実と意味の間に何もない

ここで構図を整理します。

App  ──何をすればいい?──▶  Kimetron
(「隣人が3回目だから怒る」   (「tryMove は失敗。
  という判断がしたい)          ブロッカーは uE」)

エンジンから上がってくるのは刻々の事実、アプリが欲しいのは時間をまたいだ意味。間に何もないと、アプリ側は毎回「事実 → 意味」の組み立てを自前で書くことになります。しかもこれ、移動するユニットを持つゲームなら全部が書いているやつです。譲り合い、詰まり検出、行き詰まりの解消——ゲームごとに微妙に違う実装が散らばっているはずです。

じゃあ真ん中に層を作ればいい。それが SAGBAL の出発点でした。

三層の線引き

App     ──API──▶  SAGBAL   ──API──▶  Kimetron
(意味・ポリシー)  (事象の層)      (物理の真実)
層 担当 例
Kimetron 幾何的事実 tryMove 成否、拒否理由+ブロッカーid、objectsIn
SAGBAL 仕組み 意図の収集、競合の裁定、譲り、行き詰まり検出、拡散
App ポリシー 重みづけ、誰が譲るか、行き先の意味、勝敗

重要なのは、中間層は「交渉の仕組み」までで「交渉の優劣」を持たないことです。「プレイヤーが一番偉い」とか「このユニットは頑固」はアプリ側の値であって、層は数値を受け取って機械的に裁くだけです。

設計原則は自分にも適用する

コメント欄で確立した規則は、作った層自身にも再帰的に適用しました。

  • SAGBAL も事実を飲み込まない。生のエンジンイベント・ブロッカー id は App まで素通し。層が情報のチョークポイントになると、二系統報告の冗長性が死ぬ
  • SAGBAL の出力は「より濃い事実」。「ユニット U は N ティック連続で遮られた」「U と V で互い違いの意図が検出された」——そういう事象として出す。「U はイライラしている」みたいな解釈語彙は出さない。解釈は App の仕事
  • SAGBAL の語彙を Kimetron core に入れない。意図・交渉・swap は層の言葉。依存は SAGBAL → Kimetron の一方向だけ

「事実は上へ、指示は下へ」という流れです。

デモ: スライムの門前渋滞

v0.1.0 のデモでは、プレイヤー P と6体の自律徘徊スライムが建物内を動き回り、中央の門(幅がユニット2体分ほど)で渋滞が起きます。門を抜けたいスライム同士が競合し、譲り合い、行き詰まり、横にどき合います。

sagbal_image.png

何が起きたかは右のイベントログに全部流れます。Kimetron の生の事実(灰)、SAGBAL が組み立てた事象(橙)、App の解釈(緑)で3色に色分けしています。層ごとに違う色で見えるので、設計通りに動いているかが一目で分かる検証装置でもあります。

名前の由来

SAGBAL はシュメール語の sag(前・先)× bal(交差・移し替え)の合成語。「先に通るもの」を「交差」させる層——行き違いそのものが字面に内蔵されています。Kimetron が ki(場)× metron(尺度)で「測る場」なら、その場の上で起きる交差の層です。島(Isle)に積む地層(stratum)、という位置づけを名付けに反映しています。

つづく

第2回は中身の話です。毎ティック集まる「この1歩を取りたい」という意図をどう裁くか、譲ったユニットをどう扱うか、行き詰まった2体をどうほどくか、耐えきれなくなったユニットがどう「爆発」するか——仲裁機構の設計を書きます。

1
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?