全体像
このエンジンを形づくる判断は、ほぼ次の5つです。残りの仕組みは、いずれかの判断から自然に導かれます。
物理ボディは1種類
ユニット、飛翔体、背景物、切断された手足まで、重力・弾性・終端速度・生命力・耐性を持つ同じ64バイトの物体タグを参照します。
時間も空間も整数
毎秒30ティック、位置は1 World Unitの1/512、比率は16.16または8.8固定小数点。ゲームプレイに浮動小数点は入りません。
効果も飛翔体
爆発、血飛沫、軌跡は独立した粒子系ではなく、さらに飛翔体を生む再帰的な飛翔体グループです。
乱数シードがチェックサム
各クライアントは現在の乱数シードを比較します。ほぼすべての分岐が同じLCGを消費するため、シードは差異の履歴を圧縮した指紋になります。
状態ではなく命令を送る
ネットワークを流れるのは、ユニットを動かす7種類の動詞だけです。保存フィルムは映像ではなく、初期シードから試合を再実行するレシピです。
文書で確認 Bungie/Project Magmaの資料、出荷されたエディタ文書、逆解析された構造体定義で裏づけられる項目。
推論 パッチノートと観察された挙動を組み合わせた、妥当だが直接の証言がない解釈。
未解決 到達できた資料から確定できず、推測で埋めない項目。
タググラフ
Myth II のコンテンツは、コンテナ内に置かれた4文字コードのタグ群です。ロード時にIDで解決され、ゲームプレイは「どのタグがどれを指すか」で組み立てられます。
驚くのは間接参照の深さです。マップ上に置かれる unit タグはわずか8バイトで、モンスターと色への参照しかありません。プレイヤーが「ユニット」と考える性質は mons に、物理的な性質はさらに下の obje にあります。
obje にあります。飛翔体がグループへ爆発し、そのグループが新しい飛翔体を生む再帰が、爆発と流血表現の中心です。monsに生命力はありません。 体力はobje.vitality_lower_bound + vitality_deltaで個体ごとに決まり、同じ兵種でも完全に同じ体力にはなりません。- モンスター自身はダメージ値を持ちません。 攻撃力は、攻撃が生成する飛翔体の性質です。戦士を再調整するには「矢」を編集します。
整数の基盤
ゲームプレイに使う量はすべてスケールされた整数です。これはMacとPCを同じロックステップで動かすための根本条件でした。IEEE浮動小数点が現れるのは霧や残響など表示側の量だけです。文書で確認
| 型 | 除数 | 表すもの | 主な用途 |
|---|---|---|---|
World | 512 | World Unit | 位置、速度、半径、重力、反動 |
Fixed | 65,536 | 16.16 | 吸収率、怯み、狂戦士化、ミス率 |
ShortFixed | 256 | 8.8 | 生命力、ダメージ、弾性、マナ、耐性 |
Percent | 65,535 | 確率 | 爆発頻度、軌跡頻度 |
Time | 30 | 秒 | 全継続時間をティックで保存 |
Angle | 65,536 / 360 | 度 | 向き。1周で自然に桁あふれする |
下限 + デルタ
生命力、速度、弾薬、寿命、出現数などのランダム範囲は、すべて X_lower_bound と X_delta の組で表します。ゼロでないデルタは真の幅より1大きく保存され、「乱数なし」と「幅0」を区別します。乱数はシード付きLCGから整数で得られるため、自然なばらつきとビット単位の決定性が両立します。
モンスター
1,024バイトの mons タグは、AIと戦闘システムがユニットに尋ねる質問の一覧のようなものです。
警告を聞く距離
味方の「助けを求める声」に気づく距離。標準的な歩兵で約4 WU。
存在検出の距離
敵の存在を察知し、現在の目標が死んだとき次を探す半径。約8 WU。
空間バブル
味方との最小間隔。歩兵では約0.30 WUで、局所的な混雑回避に使われます。
地形コスト
地形ごとの経路選好。負の値は通行不能。移動速度係数とは別に保持します。
攻撃吸収
名前に反して、ダメージの一部を減らす率ではなく、攻撃全体を無効化する確率と解釈されています。
脅威の指標
AIが目標の優先度を決めるための総合的な戦力値。
アニメーションがゲームプレイを決める
攻撃時間は攻撃定義に直接保存されません。ビュー当たりのフレーム数 × 1フレームのティック数が下限になり、そこへ回復時間が加わります。振りのアニメーションを長くすれば、そのままDPSが下がります。
さらに、ブロック能力の専用フラグはありません。sequence_indexes[5] > -1、つまりブロック用シーケンスを持つこと自体が能力判定です。ここではアニメーションデータが、そのままゲームプレイデータです。文書で確認
ダメージ
ダメージは飛翔体に埋め込まれた16バイトの構造体です。種類、振る舞いフラグ、下限とデルタ、半径、拡大率、ダメージから速度へ変換する係数を持ちます。
距離に応じた減衰曲線はありません。 代わりに rate_of_expansion があり、爆発は静的な球ではなく、時間とともに広がる球面として扱われます。遠いユニットが近いユニットより1〜2ティック遅れて被弾する挙動と整合します。推論
回復も独立した治療系ではなくダメージ種類の一つです。投射、反動、重力、跳ね返りは決定論的なシミュレーションに含まれます。いわゆるラグドールではなく、死体は1点の物体として専用アニメーションを再生しながら地形上を跳ねます。
血と破片も飛翔体グループ
死亡・爆発・燃焼時のタグは、ランダムな数と位置で破片飛翔体を生むグループを指します。身体部位も物理を持つ飛翔体で、投射物の上限数に数えられ、理論上はダメージさえ運べます。血は地形の色マップを破壊的に書き換え、火はメッシュセルの状態ビットとして伝播します。
弾道
各モンスターは最大4つの64バイト攻撃定義を持ちます。攻撃側が照準・タイミング・経験値補正を持ち、参照先の飛翔体がダメージと飛行を持ちます。
LEADS_TARGET— 移動目標を先読みする。IS_INDIRECT— 迫撃弾のような弧を使う。IS_FIXED_PITCH— 射出角を固定し、必要速度を解く。AIMED_AT_TARGETS_FEET— 範囲攻撃を目標の足元へ向ける。AVOIDS_FRIENDLY_UNITS— 弾道が味方を横切るか調べる。
エンジン自身が「firing solution」という語を使い、重力を受ける飛翔体方程式を解いています。経験を積むと recovery_time と initial_velocity_error が減り、兵士はより速く、より正確に攻撃します。
世界と衝突
マップは一般的なポリゴン集合でもナビメッシュでもなく、規則的な高さ場です。正方形セルを2つの三角形へ分割し、セルごとに高さ、法線、フラグ、2種類の地形コード、媒体の高さ、モデル番号を持ちます。
高さ場
すべての地面接触。1セルを2三角形にし、三角形ごとに4ビットの地形コードを持ちます。
スプライト円柱
ユニットと飛翔体の交差判定。スプライト画素で記述した半径・高さをロード時にWorld Unitへ変換します。
ポリゴンモデル
壁、門、巨大な固体など少数の例外。本物の頂点と境界を使う、より高価で不具合の多かった経路です。
変化する通行可能性
スクリプトが地形の4ビット値を書き換えられるため、橋の崩落や門の開放は移動可能性そのものの編集です。
移動とAI
経路探索は二段階です。まず動的障害物を無視し、静的な地形コストだけでA*経路を作ります。その経路が障害物へ当たると、左右の迂回を再帰的に試し、元のA*経路から最も小さく外れる方を選びます。文書で確認
この分割は決定性に有利ですが、密集したユニットが詰まりやすい理由でもあります。pathfinding_radius は局所的な二者間の分離しか表さず、群衆全体を組み替えるモデルを持ちません。
警戒は視覚だけでなく社会的に伝わる
warning_distance は、味方の助けを求める声を聞く距離です。警報は全員へ一度に届くのではなく、隣から隣へ連鎖します。
編隊もハードコードではなく form タグです。行間、ずらし、箱形、包囲半径などのパラメータから、各クライアントが同じ配置を決定論的に展開します。移動命令は配置済み座標ではなく編隊番号と最終方位を運びます。
命令ストリーム
フィルム形式は状態の記録ではなく命令の文法です。各命令は8バイトのヘッダー(サイズ、動詞、プレイヤー番号、絶対ティック)とペイロードからなります。
ユニットを操作する動詞は7つだけ。 これが戦術語彙のすべてです。停止、散開、後退、特殊能力などの差はフラグで表されます。
SELECT命令はありません。 選択UIはローカルだけで働き、各命令が16ビットのユニットID一覧を直接持ちます。範囲選択、種類選択、追加選択はネットワークへ送られません。
命令は一般にはキューされません。 新しい命令が現在の命令を置き換えます。例外は単一の MOVEMENT ペイロード内にあるウェイポイント配列です。
マップスクリプトも、人間と同じ動詞を発行します。 専用のAI制御路を持たないため、スクリプトとプレイヤー制御が自然に合成されます。
決定論
ネットワーク形態はクライアント/サーバですが、シミュレーションは決定論的ロックステップです。ホストは状態の権威ではなく、命令を中継してターンを裁定します。
乱数シードがチェックサム
世界全体をハッシュしません。各プレイヤーの32ビット乱数シードを定期的に比較します。異なる回数だけ乱数を引いたり、異なる値を生成器へ渡したりすれば、シードはすぐ分岐し、再び一致しません。
Mac/PC差をどう見つけたか
x86とPowerPCで除算結果の有効桁が異なり、クロスプラットフォーム対戦だけが同期を失いました。Project Magmaは全 myth_random() 呼び出しを、ファイル名と行番号を記録するデバッグ版へ置換し、両機のログを比較しました。最初に違った乱数呼び出しが、正確なティックとソース行を同時に示しました。
保存フィルムがバージョン間で壊れやすいのも同じ理由です。フィルムは映像でなく再実行レシピなので、ゲームロジックが変われば同じ命令列でも違う世界へ進みます。
マップスクリプト
Bungieは開発途中でJavaベースの言語を断念しました。最終的に出荷されたのは言語というよりトリガーグラフです。
アクションは64バイトのヘッダー配列と、型付きパラメータ列としてメッシュタグに入ります。各ノードは成功・失敗・実行・有効化・無効化・抑制・前提不足などのイベントで他ノードを有効/無効にします。ACTION_IDENTIFIER はどこへでも向けられるため、構造は木ではなくグラフです。
約68種類のアクションの半数は、近接、嫌がらせ、包囲、敗走、分隊、軍団、警備などのユニットAI編成に使われます。エディタのアクション一覧とヘルプもタグから生成されるため、エンジンへ新しい種類を追加するとき、エディタ本体を再ビルドする必要がありません。
未解決点
Myth II のソースコードは公開されていません。利用できる根拠は、Bungieのエディタ文書と事後分析、Project Magmaの変更履歴、バイナリタグ構造のコミュニティ解析です。残る空白を、推測で埋めないことも重要です。
- 未解決 ネットワーク1ターン当たりのティック数と入力遅延。
- 未解決 1ティック内の更新順序。
- 未解決 描画側がティック間を補間するかどうか。
- 未解決 12種類のダメージから9個の耐性スロットへの対応。
- 未解決
phys(ローカル物理)とwindタグの完全な配置。
有力な次の資料は、The Tainにあるbungie.netメタサーバの公開ソース、RoadのMap Action Script Guide草稿、MythingOak wikiのタグ資料です。
出典
- Bungie: Myth: The Fallen Lords 事後分析 — 地形メッシュ、二段階経路探索、決定論的ネットワーク、地形へ書き込む血、Fear/Loathing。
- Project Magma: Myth II 1.5/1.5.1 事後分析 — 30 Hzティック、固定小数点化、シード比較、乱数ログによる診断。
- jwheare/mythextract — タグ、メッシュ、コレクション、記録形式の逆解析パーサー。
- Fear documentation v1.8.5/Loathing documentation v1.8.5 — Bungieのエディタ資料。
- Project Magma リリースノート — 衝突、経路探索、フィルム互換性、飛翔体上限の変更。
- The Tain ソースコード・アーカイブ — 公開されたbungie.netメタサーバコードを含む。
- MythingOak — Category:Tags — コミュニティによるタグ資料。