最初のゴーストを作る
いよいよ本番ですわね。ゼロから一式を組み上げて、あなたのデスクトップに小さな住人を迎える――そのための手ほどきを、わたくしが最後まで付き添っていたしますわ。一行ずつ確実に。怖がらなくてよろしくてよ。
このチュートリアルでは、ゼロから起動可能な最小限のゴーストを組み立てる。最終的に出来上がるのは、pasta 公式のサンプルゴースト hello-pasta と同じ構成の一式である。
ここで重要なのは、完成形は確実に起動する完全なファイルセットだという点である。途中の段階だけを取り出しても起動しないことがあるため、最後まで一式をそろえてから SSP に読み込ませること。
前提となる環境やエディタの準備は 前提環境と準備 で済ませてあるものとする。すべてのファイルは UTF-8 で保存すること。
ゴーストのフォルダ構成
伺かのゴーストは、決まったフォルダ構成を持つ。これから作るのは次の構成である。
hello-pasta/
├── install.txt インストール情報
├── ghost/
│ └── master/
│ ├── pasta.dll SHIORI 本体(配置するだけ)
│ ├── pasta.toml pasta の動作設定
│ ├── descript.txt ゴーストの定義
│ └── dic/ 辞書(ここに会話を書く)
│ ├── actors.pasta
│ ├── boot.pasta
│ ├── talk.pasta
│ ├── click.pasta
│ └── choice.pasta
└── shell/
└── master/
├── descript.txt 見た目(シェル)の定義
├── surfaces.txt 表情と画像の対応
└── surface*.png 表情画像
役割を整理すると次のようになる。
| パート | 役割 |
|---|---|
install.txt | このフォルダが「ゴースト」であることと、インストール先を示す |
ghost/master/ | 会話・振る舞いを司る「中身」 |
shell/master/ | 画面に表示される「見た目」 |
用語: 「マスター(master)」は、ゴーストの標準的な中身・見た目を置く既定のフォルダ名である。1 体のゴーストに複数の見た目を持たせることもできるが、本ガイドでは
masterの 1 つだけを扱う。用語: 「シェル」とは、ゴーストの見た目(画像一式)のこと。会話の中身(辞書)とは分かれて管理される。
それでは、hello-pasta というフォルダを作り、その中にこの構成を組み立てていく。
ステップ 1: シェル(見た目)を用意する
ゴーストには表情画像が必要である。hello-pasta は「女の子」「男の子」の 2 キャラクターを持ち、それぞれ複数の表情画像(surface*.png)を使う。
これらの画像と surfaces.txt、shell/master/descript.txt は、サンプルゴーストの配布物にそのまま含まれている。自前で絵を用意するのは大変なので、まずは hello-pasta のシェル一式をそのまま使う。
shell/master/descript.txt は次の内容で、シェルの基本設定を表す。
charset,UTF-8
type,shell
name,master
craftman,ekicyou
craftmanw,どっとステーション駅長
seriko.use_self_alpha,1
sakura.balloon.offsetx,64
sakura.balloon.offsety,0
kero.balloon.offsetx,64
kero.balloon.offsety,0
surfaces.txt は、\s[0] のような番号と実際の画像ファイルを対応づける。次のように、各サーフェス番号に画像を割り当てている(抜粋)。
charset,UTF-8
surface0
{
element0,overlay,surface0.png,0,0
}
surface1
{
element0,overlay,surface1.png,0,0
}
用語: 「サーフェス(surface)」は、ゴーストの 1 枚 1 枚の表情画像のこと。
\s[0]のように番号で指定して切り替える。
画像と surfaces.txt は、pasta のサンプルクレートが自動生成する仕組みになっている。実ファイルは配布物から取得できる。シェル一式(shell/master/ 配下)は hello-pasta のシェル を参照すること。
ステップ 2: アクター辞書を書く(actors.pasta)
ここからが pasta 辞書の執筆である。最初に書くのはアクター辞書で、登場キャラクターと「表情の名前」を定義する。
ghost/master/dic/actors.pasta を作り、次のように書く。
# actors.pasta - アクター辞書(共通定義)
# 全ての .pasta ファイルで共有されるアクター定義
# pasta DSL ローダーが dic/*.pasta パターンで自動読み込み
# 女の子(sakura)- 赤色ピクトグラム surface0-8
%女の子
@笑顔:\s[0]
@通常:\s[1]
@照れ:\s[2]
@驚き:\s[3]
@泣き:\s[4]
@困惑:\s[5]
@キラキラ:\s[6]
@眠い:\s[7]
@怒り:\s[8]
# 男の子(kero)- 青色ピクトグラム surface10-18
%男の子
@笑顔:\s[10]
@通常:\s[11]
@照れ:\s[12]
@驚き:\s[13]
@泣き:\s[14]
@困惑:\s[15]
@キラキラ:\s[16]
@眠い:\s[17]
@怒り:\s[18]
ここでのポイントを説明する。
- 行頭の
#(全角シャープ)から始まる行はコメントで、動作には影響しない。説明用のメモである。 %女の子の%(全角パーセント)はアクター(登場キャラクター)の定義を始めるマーカーである。- インデントした
@笑顔:\s[0]は、「このキャラクターの『笑顔』という表情はサーフェス 0 番」という対応づけである。\s[0]がステップ 1 で見た表情画像の指定にあたる。 - これにより、以降の辞書では
@笑顔のような分かりやすい名前で表情を切り替えられる。番号を直接覚える必要はない。
用語: 「アクター辞書」は、ゴーストに登場するキャラクターと、その表情名を一覧定義したもの。会話辞書はこの定義を共有して使う。
インデントは、行頭に全角スペースを置いて表現している。pasta DSL ではインデントがブロックの内側であることを示す。
actors.pasta はすべての辞書から共有される。一度書けば、他の辞書ファイルから自由に表情名を参照できる。
ステップ 3: 起動・終了のあいさつを書く(boot.pasta)
次に、ゴーストが起動したときと終了するときの会話を書く。ghost/master/dic/boot.pasta を作る。
# boot.pasta - 起動/終了イベント用シーン定義
# pasta DSL では「シーン関数フォールバック」機能を利用
# シーン名とSHIORIイベント名を一致させることで、自動ディスパッチされる
# ※アクター辞書は actors.pasta で共通定義
# グローバル単語定義(ランダム選択用)
@終了挨拶:またね~!、お疲れ様!、ばいばーい!
# OnBoot イベント - 決定的動作(テスト安定性のため単一シーン)
*OnBoot
女の子:@通常 起動したよ~。
男の子:@通常 さあ、始めようか。
# OnFirstBoot イベント - 初回起動時
*OnFirstBoot
女の子:@笑顔 初めまして!\nわたしは女の子、よろしくね。
男の子:@笑顔 ぼくは男の子。ちゃんと使ってよね。
# OnClose イベント - 終了時
*OnClose
女の子:@通常 @終了挨拶
男の子:@通常 また呼んでよね。
>ゴースト終了(300)
# OnClose イベント - 別パターン
*OnClose
女の子:@眠い おやすみなさい...
男の子:@通常 じゃあね。
>ゴースト終了(300)
ここでの要点は次のとおりである。
*OnBootの*(全角アスタリスク)はシーンを定義するマーカーである。シーンは「会話のひとまとまり」を表す。- シーン名を
OnBoot、OnCloseのようにイベント名と同じ名前にしておくと、ベースウェアからそのイベントが届いたとき、対応するシーンが自動的に呼び出される。OnBootは起動時、OnCloseは終了時のイベントである。 - インデントした
女の子:@通常 起動したよ~。はアクション行で、「誰が・どんな表情で・何を話すか」を表す。@通常でステップ 2 で定義した表情を指定し、続けてセリフを書く。 @終了挨拶:またね~!、お疲れ様!、ばいばーい!は単語定義である。読点(、)で区切った候補の中から 1 つがランダムに選ばれる。アクション行で@終了挨拶と書くと、その場でどれか 1 つに置き換わる。>ゴースト終了(300)は、ジャンプ表記で終了処理を呼び出している。- 同じ名前のシーン(ここでは
OnClose)を複数定義すると、実行時にそのうち 1 つがランダムに選ばれる。これで毎回同じ反応にならない自然さが生まれる。 - セリフ中の
\nは改行を表す。
用語: 「シーン」は会話のひとまとまり。「イベント」はベースウェアからゴーストへ届く通知(起動した、終了する、クリックされた等)。シーン名をイベント名に合わせると、そのイベントで自動的に呼ばれる。
ステップ 4: ランダムトークと時報を書く(talk.pasta)
ゴーストは、何もしないときも時々ひとりごとを言う。これをランダムトークと呼ぶ。ghost/master/dic/talk.pasta を作る。
# talk.pasta - ランダムトーク/時報用シーン定義
# OnSecondChange (毎秒) → 仮想イベントディスパッチャ → ランダムトーク/時報
# ※アクター辞書は actors.pasta で共通定義
# ランダムトーク用単語(ランダム選択)
@雑談:何か用?、暇だなあ...、ねえねえ、聞いてる?、うーん、眠くなってきた...
# ランダムトーク - 仮想イベント OnTalk
*OnTalk
%女の子、男の子
女の子:@通常 @雑談
*OnTalk
%女の子、男の子
女の子:@笑顔 Pasta DSL、使ってみてね!
男の子:@笑顔 Lua 側も触ってみなよ。
*OnTalk
%女の子、男の子
女の子:@眠い 今日は何しようかな...
男の子:@通常 宿題やったの?
*OnTalk
%女の子、男の子
女の子:@通常 ねえ、今日の天気どう思う?
男の子:@困惑 さあ、外見てないからわかんないや。
*OnTalk
%女の子、男の子
女の子:@笑顔 一緒にお話しよう!
男の子:@照れ しょうがないなあ。
*OnTalk
%女の子、男の子
女の子:@眠い ふわあ...ちょっと眠いかも。
男の子:@通常 寝てていいよ、ぼくが見てるから。
# プロパティスコープ統合テスト($% 構文)
*OnTalk
%女の子、男の子
$ゴースト名=$%currentghost.name
女の子:@笑顔 わたしの名前は$ゴースト名だよ!
男の子:@通常 名前、ちゃんと取れてる?
# 時報 - 仮想イベント OnHour
# $時12 変数は onhour-date-var-transfer により自動設定される(12時間表記)
# 4段階フォールバック: 時報12 → OnHour12 → 時報その他 → OnHourOther
# 時刻別時報の例(正午専用)
*時報12
%女の子、男の子
女の子:@笑顔 お昼だよ!お腹すいた~。
男の子:@笑顔 もうお昼か、ご飯にしよう。
# 汎用時報(他の時刻別シーンがない場合のフォールバック)
*時報その他
%女の子、男の子
女の子:@笑顔 $時12 だよ!時報だよ~。
男の子:@笑顔 もう $時12 か、早いね。
*時報その他
%女の子、男の子
女の子:@通常 今 $時12 だって。
男の子:@通常 へえ、そうなんだ。
*時報その他
%女の子、男の子
女の子:@通常 $時12 ...時間が経つのって不思議だね。
男の子:@通常 哲学的だね。
新しく出てきた要素を説明する。
- 各シーンの先頭にある
%女の子、男の子は、そのシーンに登場するアクターを宣言している。読点で複数を並べられる。 *OnTalkを複数並べているのは、ランダムトークの候補をたくさん用意するためである。実行時にどれか 1 つが選ばれる。@雑談のように単語定義を使うと、さらに細かいバリエーションを足せる。$ゴースト名=$%currentghost.nameは変数への代入である。$から始まる名前が変数で、ここではゴースト名を取得して$ゴースト名に入れ、セリフ中で$ゴースト名と書いて差し込んでいる。*時報12*時報その他は時報(毎正時のあいさつ)用のシーンである。$時12には現在時刻(12 時間表記)が自動的に入る。特定の時刻専用のシーンがなければ「その他」がフォールバックとして使われる。
変数やシーンの呼び出しについてさらに詳しく学びたくなったら、変数・スコープ や Call / Jump を参照するとよい。
ステップ 5: クリックへの反応を書く(click.pasta)
ゴーストをダブルクリックしたときの反応を書く。ghost/master/dic/click.pasta を作る。
# click.pasta - ダブルクリック反応用シーン定義
# OnMouseDoubleClick イベントに反応
# ※アクター辞書は actors.pasta で共通定義
# ダブルクリック反応(ランダム選択)7種以上
*OnMouseDoubleClick
%女の子、男の子
女の子:@驚き わっ、びっくりした!
男の子:@笑顔 どうしたの?
*OnMouseDoubleClick
%女の子、男の子
女の子:@笑顔 なあに?呼んだ?
男の子:@通常 こっちに用があるんじゃない?
*OnMouseDoubleClick
%女の子、男の子
女の子:@照れ え、なに?
男の子:@キラキラ 照れてるの?
*OnMouseDoubleClick
%女の子、男の子
男の子:@驚き うわっ!なに!?
女の子:@笑顔 反応してくれたね。
*OnMouseDoubleClick
%女の子、男の子
女の子:@怒り もう、そんなにクリックしないで!
男の子:@驚き お、怒った怒った。
*OnMouseDoubleClick
%女の子、男の子
女の子:@笑顔 わ〜い、遊んでくれるの?
男の子:@通常 まあ、暇だしね。
*OnMouseDoubleClick
%女の子、男の子
男の子:@キラキラ ふふん、ぼくのことが気になる?
女の子:@驚き えっ?そんなんじゃないよ!
OnMouseDoubleClick はゴーストがダブルクリックされたときのイベントである。ステップ 3・4 と同じく、同名シーンを複数並べてランダムに選ばせている。書き方の文法はこれまでと変わらない。
ステップ 6: 選択肢を出す(choice.pasta)
最後に、会話の中で選択肢を出して分岐させる例を書く。ghost/master/dic/choice.pasta を作る。
# choice.pasta - 選択肢デモ辞書
# @?マーカーによる選択肢定義と自動ルーティングのデモ
# ※アクター辞書は actors.pasta で共通定義
# 選択肢デモ - ダブルクリックから呼び出し可能
*OnMouseDoubleClick
%女の子、男の子
女の子:@笑顔 何について話す?
@?挨拶
@?天気「天気を聞く」
!select(10)
# コールバックシーン - 省略形「挨拶」の選択時
*挨拶
%女の子、男の子
女の子:@笑顔 こんにちは!挨拶を選んでくれたんだね。
男の子:@通常 よろしく!
# コールバックシーン - 括弧形「天気」の選択時
*天気
%女の子、男の子
女の子:@通常 今日はいい天気だね!
男の子:@笑顔 散歩にでも行こうか。
新しい要素を説明する。
@?挨拶は選択肢を表すマーカーである。@?に続けてシーン名を書くと、その名前のボタンが表示され、押すと同名のシーン(ここでは*挨拶)へ飛ぶ。@?天気「天気を聞く」のように「」で表示名を指定すると、ボタンには「天気を聞く」と表示され、押すと*天気のシーンが呼ばれる。!select(10)は選択待ちの設定(タイムアウト等)を表す。
これで「ダブルクリックすると選択肢が出て、選んだ内容に応じて会話が分岐する」という振る舞いが完成する。
ステップ 7: 設定ファイルを置く
辞書がそろったので、ゴーストとしての設定ファイルを用意する。
install.txt
フォルダ直下に install.txt を置く。これはインストール時の情報である。
type,ghost
name,hello-pasta
directory,hello-pasta
accept,
ghost/master/descript.txt
ゴーストの定義ファイルである。shiori,pasta.dll の行で、頭脳として pasta を使うことを宣言している。
charset,UTF-8
type,ghost
name,hello-pasta
sakura.name,女の子
kero.name,男の子
craftman,ekicyou
craftmanw,どっとステーション駅長
shiori,pasta.dll
homeurl,https://github.com/ekicyou/pasta
ghost/master/pasta.toml
pasta の動作設定ファイルである。辞書ファイルの読み込みパターンや、ランダムトークの間隔、アクターの配置位置などを指定する。
起動に必須なのは [actor] セクションだけである。他の全セクション([loader] / [ghost] / [talk] / [logging] など)は省略でき、省略すると pasta が無難なデフォルト値を自動補完する。[package] は SHIORI 用途では不要で、書いても無視される。したがって、最小構成は次のように [actor] だけで完結する。
# 最小構成: 必須の [actor] のみ。他は SHIORI デフォルトで補完される。
[actor."女の子"]
spot = 0
[actor."男の子"]
spot = 1
"女の子"/"男の子"は、descript.txtのsakura.name/kero.nameと一致させる。spotはバルーン位置(0=sakura 側 /1=kero 側)で、ゴースト固有のためデフォルト化できず、各アクターで必ず指定する。- 辞書は
[loader]を書かなくても、pasta_patternsのデフォルト["dic/**/*.pasta"]によりdic/配下の.pastaファイル(ステップ 2〜6 で書いた 5 つ)がすべて自動的に読み込まれる。
この最小構成をそのまま ghost/master/pasta.toml として保存すれば、hello-pasta は起動する。各セクションの分類(省略可 / 必須 / エンジンプロファイル専用)と全フィールドのデフォルト値、フルリファレンステンプレートは設定ファイルリファレンスにまとまっている。ランダムトーク間隔([ghost])やログ設定([logging])などを明示したくなったら、そちらを参照して必要な項目だけ書き足すとよい。配布版 hello-pasta の完全な設定例は hello-pasta の pasta.toml を参照すること。
pasta.dll と Lua ランタイム
ghost/master/ に pasta.dll を置く。これが SHIORI 本体である。前提環境で触れたとおり、これは自分で書くものではなく、配布物に含まれる実行ファイルを配置する。Lua ランタイム(scripts/ 配下)も同様に配置する。
これらの実行ファイルの入手・ビルド・配置手順は pasta_sample_ghost の README にまとまっている。
ステップ 8: ゴーストを起動する
これでフォルダ構成の冒頭で示した一式がそろった。最後に SSP に読み込ませて起動を確認する。
hello-pastaフォルダ全体を、SSP のゴーストフォルダ(SSP インストール先のghost/配下)にコピーする。- SSP を起動し、ゴースト切り替えメニューから
hello-pastaを選ぶ。 - 起動すると、
OnBoot(または初回はOnFirstBoot)のセリフが表示される。 - ゴーストをダブルクリックすると、
OnMouseDoubleClickの反応や選択肢が出る。 - しばらく待つと、ランダムトーク(
OnTalk)が始まる。
配布物として
.nar形式にまとめてインストールする方法もある。配布パッケージの作り方は pasta_sample_ghost の README を参照すること。
起動して女の子と男の子があいさつを返したら成功である。ここまでで作ったのは、pasta 公式サンプル hello-pasta と同じ、起動可能な最小限のゴースト一式である。
うまく起動しないときは
- 文字化けする / 辞書が読めない: ファイルが UTF-8 で保存されているか確認する。設定ファイル先頭の
charset,UTF-8も確認する。 - 何も表示されない:
ghost/master/にpasta.dllが置かれているか、descript.txtにshiori,pasta.dllがあるか確認する。 - 辞書が反映されない:
dic/フォルダの中に.pastaファイルがあるか確認する。pasta_patternsを省略していればデフォルトの["dic/**/*.pasta"]で読み込まれる。明示している場合はそのパターンがdic/配下を網羅しているか確認する。
おめでとうございますわ! あなたのデスクトップに、ちゃんと住人が生まれましたわね。……フンッ、これくらいできて当然ですわよ。けれど、よくぞ最後までついてらして。
ここから先は、あなたの番。会話をもっと豊かにしたくなったら Pasta DSL 文法 で書き方を体系的に学び、込み入った処理を書きたくなったら Lua API / コーディング へ。さあ、あなただけのゴーストを、熱く育ててまいりましょう!