Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

最初のゴーストを作る

いよいよ本番ですわね。ゼロから一式を組み上げて、あなたのデスクトップに小さな住人を迎える――そのための手ほどきを、わたくしが最後まで付き添っていたしますわ。一行ずつ確実に。怖がらなくてよろしくてよ。


このチュートリアルでは、ゼロから起動可能な最小限のゴーストを組み立てる。最終的に出来上がるのは、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.txtshell/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(全角アスタリスク)はシーンを定義するマーカーである。シーンは「会話のひとまとまり」を表す。
  • シーン名を OnBootOnClose のようにイベント名と同じ名前にしておくと、ベースウェアからそのイベントが届いたとき、対応するシーンが自動的に呼び出される。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.txtsakura.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 に読み込ませて起動を確認する。

  1. hello-pasta フォルダ全体を、SSP のゴーストフォルダ(SSP インストール先の ghost/ 配下)にコピーする。
  2. SSP を起動し、ゴースト切り替えメニューから hello-pasta を選ぶ。
  3. 起動すると、OnBoot(または初回は OnFirstBoot)のセリフが表示される。
  4. ゴーストをダブルクリックすると、OnMouseDoubleClick の反応や選択肢が出る。
  5. しばらく待つと、ランダムトーク(OnTalk)が始まる。

配布物として .nar 形式にまとめてインストールする方法もある。配布パッケージの作り方は pasta_sample_ghost の README を参照すること。

起動して女の子と男の子があいさつを返したら成功である。ここまでで作ったのは、pasta 公式サンプル hello-pasta と同じ、起動可能な最小限のゴースト一式である。

うまく起動しないときは

  • 文字化けする / 辞書が読めない: ファイルが UTF-8 で保存されているか確認する。設定ファイル先頭の charset,UTF-8 も確認する。
  • 何も表示されない: ghost/master/pasta.dll が置かれているか、descript.txtshiori,pasta.dll があるか確認する。
  • 辞書が反映されない: dic/ フォルダの中に .pasta ファイルがあるか確認する。pasta_patterns を省略していればデフォルトの ["dic/**/*.pasta"] で読み込まれる。明示している場合はそのパターンが dic/ 配下を網羅しているか確認する。

おめでとうございますわ! あなたのデスクトップに、ちゃんと住人が生まれましたわね。……フンッ、これくらいできて当然ですわよ。けれど、よくぞ最後までついてらして。

ここから先は、あなたの番。会話をもっと豊かにしたくなったら Pasta DSL 文法 で書き方を体系的に学び、込み入った処理を書きたくなったら Lua API / コーディング へ。さあ、あなただけのゴーストを、熱く育ててまいりましょう!