Kagari
キーワードを入力してドキュメントを検索します。

概要

アーキテクチャ

この章では全体像を示します。Kagari のゲームがソースファイルから実行中のゲームになるまでの流れ、ゲームの各部分を何で書くか、各部分がどのようにやりとりできるかです。個々の要素は後の章で厳密に定義します。

ソースから実行中のゲームまで

kagari.toml プロジェクト src/ .kis .kix assets/ 画像、音声、フォント kagari build 検査、解析、生成、 アセットのパック 診断 kagari check、エディタ target/v0/ game.kagari バイトコード *.kiarchive アセットアーカイブ デスクトップ ランタイム native_v0 データディレクトリ 設定、メタ、セーブ 実行中の ゲーム

プロジェクト。 ゲームは一つの プロジェクト です。kagari.toml マニフェスト、src/ 以下のソースファイル、assets/ 以下のアセットをもつディレクトリです。コンパイルは一つのルートファイル(既定では src/main.kis)から始まり、その mod 宣言をたどって他のすべてのソースファイルに至ります。ソースファイルは .kis(素の言語)か .kix(言語に s!(…) や choice!{…} などの フォーム を加えたもの)のどちらかです。拡張子が選ぶのは構文だけで、意味は変わりません。アセットはソース中で const BG_ROOF: ImageAsset = asset("bg/roof.png"); のような定数で名前を付け、各ファイルが存在することをコンパイラが検査します。

ビルド。 kagari build はプログラム全体を一度にコンパイルします。すべてのファイルを構文解析して名前を解決し、型と 関数種別 を検査し、定数とレンダーを評価し、物語とゲームシステムを解析し、プログラムを生成します。エラーが一つでもあればビルドは止まりますが、警告では止まりません。結果は <out-dir>/<target>/、既定では target/v0/ に書き出されます。

出力内容
game.kagariコンパイルされたプログラム:物語、レンダー、ゲームシステム
*.kiarchiveプログラムが参照するアセット。アセットディレクトリの最上位のディレクトリごとに一つのアーカイブ、アセットディレクトリ直下のファイルには data.kiarchive、ゲームが名前で指定したインストール済みフォントには system-fonts.kiarchive、使用する std のシェーダーには std.kiarchive

ビルドは何かを書き出す前に、マニフェストに列挙されたすべてのランタイムプロファイルが、参照されるすべてのアセットをデコードできることを検査します。kagari check は出力を書かずに同じ診断を報告し、言語サーバーは入力中の エディタ にそれを表示します。

ビルドはさらに、プログラムが使うすべてのシェーダーをそのロールに照らして検証し、検証に通らないシェーダーがあれば失敗します。

ランタイム。 デスクトップランタイム kagari-desktop-runtime は、ビルドしたゲームを Windows、macOS、Linux で実行します。ゲームディレクトリ(既定では実行ファイルのあるディレクトリ。したがって出荷するゲームでは実行ファイルを game.kagari とアーカイブの隣に置きます)から game.kagari を読み込み、どの部分も実行する前にプログラムを検証し、fn main を一度実行してゲームシステムの記述を得て、開始ページを表示します。設定、メタ、セーブスロットは、ゲームディレクトリの外にあるデータディレクトリに保存されます。ランタイムが実装するのはランタイムプロファイル native_v0 で、動画のアセットを除く標準ライブラリ全体です。ヘッドレスモード では、同じゲームをウィンドウなしでスクリプトに従って実行でき、自動テストに使えます。

ゲームの各部分を書く種別

ゲームは三つの部分から成り、それぞれを一つの 種別 の関数で書きます。

部分種別含むもの
物語pushdown fnシーン(#[scene])、即時手続き、物語変数(static mut)、プレイヤーが読み、選ぶ ステップ
演出const fn各ステップで画面を変える レンダー関数、キャラクターのレシピなどのステージング補助関数、テキスト効果、定数
ゲームシステムfnfn main、タイトルページ、メニュー、セーブとロードのページ、設定、バックログ、ゲームビュー。物語を取り巻くすべて

型、定数、設定とメタのための static ハンドル、アセット定数は、三つの部分すべてが共有する通常のアイテムです。一つのモジュールにどの種別を混ぜてもかまいません。種別はファイルではなく関数に属します。

ゲームシステム · fn main、タイトル、メニュー、セーブとロード、設定、ゲームビュー 物語 · pushdown fn シーン、ステップ、選択肢、物語変数 演出 · const fn レンダー、ステージングの補助関数、テキスト効果、定数 エントリーシーンを開始 nav::start 有限型の引数 Narrative ハンドル 入力、台詞、セーブ エンディングの値 書き込み専用のメタ ステップごとに レンダーを選ぶ × レンダーは画面だけを見る。 物語は画面を読まない const fn を呼べる 許される 不可

どの矢印が存在するかは 呼び出し規則 が定めます。

  • fn は fn と const fn を呼べます。pushdown fn を呼ぶことも、物語変数を読むこともできません。
  • pushdown fn は pushdown fn と const fn を呼べ、fn は決して呼べません。実行時に保持する値はすべて 有限型 です。
  • const fn は const fn しか呼べません。物語変数、設定、メタなど、引数以外のものは何も読めません。

関数ポインタとクロージャの型も種別をもつので、これらの規則はポインタやクロージャを経由しても成り立ちます。

入れ子になった二つの機械

実行時のゲームは、一方が他方の内側にある二つの機械です。

  • 外側のシステム機械は モード のスタックを保持します。底にはタイトルやギャラリーのようなルートページ、またはゲームモードがあり、その上に Config、Save、Backlog などのオーバーレイやダイアログが積まれます。入力は最上位のモードだけに届きます。
  • ゲームモードは実行中の物語を一つ保持します。これが 物語機械 です。物語機械はプッシュダウン機械で、その状態 σ は、シーン内の位置、実行中のシーンと即時手続きのコールスタック、物語変数から成ります。ゲームモードはこれに加えて、現在の画面と、プレイヤーの選択のトレースを保持します。

物語のコールスタックはゲームモードの内側にあり、モードのスタックに載ることはありません。したがって、セーブが保持するのは実行中の物語だけで、それを取り巻くメニューは何も含みません。セーブをロードすると、スタックに積むのではなくゲームモードが置き換わります。そして「ゲームが実行中である」とは、ちょうどスタックにゲームモードがあることを意味します。オーバーレイやダイアログがゲームモードの上にある間、物語は一時停止します。

状態寿命セーブに含まれるか
設定永続、大域的いいえ
メタ:解放状況、既読テキスト、表示済みの画像永続、大域的いいえ
セーブスロット永続これがセーブそのもの
モードのスタックと各モードの状態ゲーム終了までいいえ
実行中の物語:σ と画面物語が終わるか、別の物語に置き換わるまではい。そこに到達するトレースとして

部分どうしのやりとり

情報は三つの部分を一方向に流れます。物語が何が起こるかを決め、演出がそれがどう見えるかを決め、ゲームシステムがその周りのすべてを決めます。どの部分も、自分の出力を後段がどう扱ったかを読み返しません。

物語から演出へ

各ステップは自分のレンダーを指定します(s!(render = roof, …))。物語がそのステップに到達すると、エンジンは現在の画面にレンダーを適用し、結果を表示します。レンダーが受け取るのは画面だけなので、物語変数に依存できません。また Screen は有限型ではないので、物語は画面を読めません。物語に依存する演出は、分岐ごとに異なるレンダーを渡すことで、物語の側が選びます。

ゲームシステムと物語の間

ゲームシステムと物語が接するのは次の四か所だけです。

接点方向渡るもの
エントリーシーンシステムから物語へnav::start(entry, args, on_exit) は、有限型の引数で #[entry] シーンから物語を開始します。物語に入る方法はこれだけです
Narrative ハンドル双方向ゲームビューとゲームオーバーレイは、実行中の物語へのハンドルを受け取ります。これを通じて現在の台詞、選択肢、バックログを表示し、物語を進める、アームを選ぶ、セーブする、巻き戻す、といった操作をします。このハンドルから物語変数は読めません
エンディング物語からシステムへエントリーシーンが戻ると、その値は終了ハンドラ on_exit に渡されます。終了ハンドラは起こりうるすべてのエンディングを扱わなければなりません
メタ物語からシステムへ物語は Meta::write でメタに書き込み、実行中にそれを読み返すことはありません。システムはメタを読み、次の物語にエントリー引数として渡せます

設定が物語に届くことはありません。設定に依存するレンダーは、その値を読むのではなく、エンティティを設定でゲートします。設定の値は、描画時にエンジンが適用します。

ゲームの一回の実行

  1. ランタイムは game.kagari を読み込んで検証し、fn main を実行し、それが返す System レコードに指定された開始ページを表示します。
  2. ページ、オーバーレイ、ダイアログはコンポーネント、つまり UI を組み立てる素の fn です。ボタンのハンドラは nav::call(Config) や nav::start(…) などのナビゲーション関数を呼びます。
  3. nav::start はモードのスタックを、エントリーシーンを実行する新しいゲームモードで置き換えます。
  4. 物語は最初のステップまで即座に実行されます。ステップのレンダーが画面を変え、ゲームビューが台詞を表示し、物語は待機します。
  5. プレイヤーの入力が物語を再開させます。s! のステップを先へ進めるか、choice! のアームを選ぶかです。物語は次のステップまで実行されます。エンジンは選択肢ごとに自動セーブします。
  6. エントリーシーンが戻ると、終了ハンドラがエンディングを受け取り、たとえばクレジットへ遷移します。

コンパイラの解析 は、起こりうるすべての実行、つまりすべてのエントリーシーン、その引数のすべての値、すべての選択の列について、手順 3 から 6 を対象とします。

最終更新日 2026年10月29日