基本的に物置き

作例で学ぶ、ゴーストの作り方


はじめに

当記事は伺か・伺的 Advent Calendar 2024に参加したものです。
なお、アドカレは現在第一会場は満席となり、当記事は第二会場での参加となります。
第二会場はまだ(12月2日現在)そこそこ空席があります。お手すきの方はどうぞ!

はじめましての方ははじめまして。古閑未善と申します。
普段はシンプルなほのぼの雑談ゴーストふくふくアフターライフ(仮)や、とても長いストーリー付きゴーストぐれすけいる
ブラウザでトークGIF画像を生成するソフトうかじふなどを公開しております。
よかったら見ていってくださいね。宣伝終わり。

さて、当記事はゴーストを作る際の手順、その際に必要となる記述の解説などを実際にゴーストを作りながら説明する、ちょっと進んだ解説記事です。
「ゴーストは作りたいけどまだ右も左も」「トーク書いてみるくらいから試したいな」という方は、はじめてのゴーストの作り方をお読みになることをおすすめします。
少しばかり長い話とはなりますが、「ゴーストを作ってみたい!」「ゴーストがどう作られるのか知りたい!」という方はぜひご覧になっていってくださいね。

(作例ゴースト「カナタノアオ」だけダウンロードしたい方はこちら

★まずはイメージを固めよう

まずは何から作るんだ!? とやる気満々の方には申し訳ないのですが、千里の道も一歩から。
まずはしっかり地盤固めとして、作りたいゴーストのイメージを固める作業をしていきましょう。

メモできるものを用意し、どういうゴーストにしたいかを一言で書くのです。
雰囲気や性格のようなふんわりした設定で構いません。
今回の作例に使われた設定もこんな感じです。

とあるお屋敷で、お嬢様とユーザが和やかに語らう。

具体性がほぼゼロですが、書き始めゆえまったく問題ありません。
メモは手元など、参照しやすい場所においておきましょう。

続けてシェルを用意します。絵が描けるなら自前で描くことも可能ですが、今回はフリーシェルを使います。
フリーシェルを使う場合は、設定が固まりきらないうちにシェルを探すことをおすすめします。
というのも、イメージに完全一致するフリーシェルなどというものはそうそう見つからないからです。
「長い時間を掛けて完璧な設定ができたぞ! でもしっくりくるシェルがない!! あれはここが違う! これもそこが違う!! やめる!!!」
……なんてことになると折角の設定もお蔵入りルートまっしぐらです。

イメージが固まりきらないうちにシェルを用意し、続きはそれを眺めながら考えていきましょう。
そうすれば自然と作りたいゴーストとシェルのイメージを統合することができます。

★イメージを膨らませてみよう

今回の作例ゴーストには塔書館さんのフリーシェル「あおいけがわ」を拝借させていただくことにしました。
とても可愛らしいシェルで、どこか寝そべるようなポーズ、獣人らしい犬っぽさと設定を膨らませてくれそうな要素も含まれています。

というわけでこのポーズから設定を膨らませ、彼女は寝そべったまま喋るということに。
話す内容も、自身が見た夢の話……とすることにしました。
これを既存の設定と組み合わせます。

とあるお屋敷で、寝そべったお嬢様がユーザに夢の話を聞かせる。

ちょっぴり具体性が付与されてきましたが、まだ足りません。
ここは自己ツッコミを入れることで話をより膨らませることにしましょう。
書いた設定の、不満だったり疑問の残る箇所を見つけ、それに答えをつける形で記述していきます。
これを連鎖させることで設定を固めていくことができます。早速進めていきましょう。まずは……

★なぜユーザが話し相手に?
→お嬢様が寝てばかりいるため、少しでも興味を惹いて起こしておくためにユーザが呼ばれた。

★ユーザを呼んだ理由は?
→他の話し相手もいたが、すぐに寝られてしまった。なのでユーザが試された。

★なぜユーザ相手なら眠らないのか?
→今までの話し相手は、彼女を楽しませようと自分の話だけを聞かせていた。それが悪かった。
彼女はむしろ話を聞いてもらいたかったのだ。ユーザは話題を持たない反面聞き上手だったため、それが功を奏した。

★そもそもなぜ寝てばかりだったり、寝た体勢のまま話してるのか?
→過去に何かしらの出来事があり、精神的なショックによるもの。

★何かって何...(省略)

実際に使用したものから一部を抜粋しました。
ツッコミが連鎖することで設定が詳細になっていく過程がわかると思います。
うまくツッコミが入れられない時は一旦別のことをしたり、作業から離れたりしてみましょう。
記憶が薄れることで客観視しやすくなります。

ただし、ツッコミを入れすぎないように注意しましょう。
何から何までガチガチに設定を固めると、そのときはすごく満足するのですが、その設定に縛られすぎて何も書けずにお蔵入り……なんて自体が起きやすくなります(実体験)。
ある程度内容がまとまったら、清書してあらすじ状にまとめてみましょう。

一般人のユーザは、とあるお屋敷の令嬢の話し相手として招かれた。
彼女は過去のある出来事から心を痛め、過度に眠りにつくようになっていた。
そこで彼女の興味を少しでも惹くため、話し相手が求められたのだ。
何故面識もないユーザかといえば、今まで試した人々では駄目だったからだ。
彼らは一様に優秀な人々だった。だから自分の貴重な経験を聞かせて興味を惹こうとした。
しかし彼女はむしろ、話すことに飢えていたのだ。ユーザは口下手だが、システム的にも天性の聞き上手であった。
ユーザと話している間、彼女は久々に時を忘れ、楽しんで起きていることができたのだ。
かくして2人は今日も、彼女の部屋で雑談に興じる。

★キャラ設定を明確にしよう

だいぶイメージが固まり、「こういうゴーストだよ」と人に説明できるくらいになりましたね。
では早速、出会いとなる初回起動イベントを……といきたいところですが、もう少しだけ設定を詰めましょう。
ゴーストの主体となるお嬢様には、お嬢様、話したがり、よく寝るくらいの設定しか決まっていません。
名前や口調、性格、他者の呼び方など、統一したい部分を事前にまとめておきましょう。

名前:アオ
性格:誰にでも丁寧で優しい
一人称:わたくし
ユーザの呼び方:ユーザ様
口調:ですわ、ですの等のお嬢様口調

他者への接し方:目上、目下に関わらず誰にでも丁寧で親切

こういった呼び方、接し方は読み手にとっては意外に気になる部分です。 身内や目上など、ユーザ以外との接し方も設定しておきましょう。登場させないとしても、頭の中のイメージが固まります。


そしてさらに、キャラクターの現状認識をまとめておきましょう。
現在の自分をどう思うか、ユーザについてどう思うか、周りの人間についてどう思っているのか。
今回は特に、一風変わったキャラクターなのでユーザさんが疑問を持ちやすい箇所かと思います。しっかり決めておきましょう。

★現在の状況について
夢ばかり見ていることに不満はあるが、抵抗する気力がなかった。ユーザと出会い、少し気力を取り戻しかけている。

★身内の人々への思い
心配させていることには申し訳なく思っていたが、諦めてほしいとも思っていた。

★ユーザへの思い
夢の話に初めて耳を傾けてくれた人として好感を持っている。


最後に過去についても書いておきましょう。
要はちょっとしたエピソードを作るのです。何もシリアスでなくても構いません。
詳細は詰められなくても構いませんが、何が起き、それにどういう感情を抱いたかはしっかり決めておきます。

浮かびづらい場合は、喜怒哀楽に寄せて考えてみてもいいでしょう。
友達と遊べて喜んだ、家族と喧嘩して怒った、何かを失って悲しんだ、密かな楽しみを持っていた……
などなど。一つ一つはちょっとしたことでも、並べていくとイメージに奥行きが出てきます。

日常系のほのぼのゴーストでも、ある程度の過去は決めておくといいでしょう。
設定も固まり、のちのちトークのネタにすることもできるといいことづくめです。

そしてある程度書けたら、改めて情報をまとめなおし、整頓しておきましょう。
同じことを二度書くのは無駄な手間に思えるかもしれませんが、俯瞰することで気付ける矛盾や浮かぶアイデアもあります。

★ゴースト設定
話したがりのお嬢様「アオ」と聞き上手のユーザが、お屋敷の寝室で雑談する。

名前:アオ
性別:女
年齢:13歳
備考:『獣人』の少女。犬の耳と尻尾を持つ、この世界では一般的な人種。

性格:誰にでも丁寧で優しい。
一人称:わたくし
ユーザの呼び方:ユーザ様
口調:ですわ、ですの等のお嬢様口調
他者への接し方:目上、目下に関わらず誰にでも丁寧で親切。

★現状への感情
現在の状況について:夢ばかり見ていることに不満はあるが、抵抗する気力がなかった。ユーザと出会い、少し気力を取り戻しかけている。
身内の人々への思い:心配させていることには申し訳なく思っていたが、諦めてほしいとも思っていた。
ユーザへの思い:夢の話に初めて耳を傾けてくれた人として好感を持っている。

★過去の出来事
喜:父は子煩悩な獣人で、幼少期のアオに自分と同種の動物のぬいぐるみをたくさん贈り、娘に気に入ってもらおうとしていた。
作戦は成功し、その影響でアオは今もぬいぐるみ集めが趣味になっている。

怒:過眠を心配した父に無理に運動させられたが、突発的な眠りで怪我をしてしまった。そのことで心配を掛けさせ、自分自身への怒りを抱いた。

哀:一般人も通う小学校に1年だけ通っていたが、様々な常識の違いから悪目立ちしてしまい、結局転校してしまった。

楽:幼少期はお転婆で、屋敷内をかけずり回り、広い庭で様々なスポーツを楽しんだ。

★夢を見るようになった理由(※一応作例のネタバレ注意、反転で表示)

アオには姉がいた。姉は夢見という不思議な能力を持っていた。
それはただ夢を見るだけではなく、夢を通して異世界に移動する能力である。
夢の世界での立場は不安定で、夢を見るたびに事情も背景も異なる人間になってしまう。
それでも元来行動的だった彼女は、昼は現実、夜は夢の世界を生きることで常人の2倍の人生を楽しんでいた。
アオにとって彼女は、話題も豊富で、優しく、母代わりでもあり、憧れであった。

ところが彼女は、とある異世界で恋に落ちる。だが不安定な立場では、仲を深めることにも限度があった。
募るフラストレーションから、彼女は徐々に破滅的な衝動を抱えるようになっていく。
それが許容量を越えた時、彼女は完全にこの世から消えてしまった。

こんな身勝手な私のことなど、みんな忘れてしまえばいい。
そんな願いを残して。願いは夢の世界を通じて拡散し、現実世界の人々から彼女の記憶を奪った。

だが、人の存在がそう簡単に消えるわけがない。
特に彼女と親しかった人々は、喪失感や欠落感に、その原因がわからないことに余計に苦しませられることとなる。

アオもまた、その1人だった。
さらに夢の世界から強い影響を受けたことにより、彼女にも夢見の力が目覚めてしまう。
現実世界では決して自覚できない心の傷に苦しむアオは、自由な夢の世界に依存していく。
睡眠時間も徐々に増加し、いつしか起きる時間が異常に少なくなっていた。

それが心配を掛けていると知りながらも、苦しみから逃れるために夢を見る。
こんな身勝手なわたくしのことなど、みんな忘れてしまえばいい。そんな願いを抱えながら。

★初回起動イベントを書くために

設定が固まり、しっかりとした土台ができあがりましたね。後はしっかりとした建物を築き上げるだけです。
ゴースト本体の制作には一点の曇りもないさんのさとりすとを使用します。 制作に必須ではありませんが、極めて便利で使いやすく、難しい設定も視覚的にわかりやすく把握できるなど……
知れば知るほど凄さを実感できる素晴らしいエディタとなっています。
ぜひ使ってみましょう。

それでは早速さとりすとを開き、上部メニューの「ファイル→ゴースト新規作成」ボタンから制作をスタートしましょう。
新規ゴーストは空のゴーストから作るか、ある程度の必要なイベントを用意してくれているテンプレートゴーストから作るかを選択できます。
テンプレートは書き換えるだけでゴーストが作れるお手軽なものですが、今回は使用しません。
ちょっと手順は増えますが、最低限何が必要かの理解をしやすくするためです。

作成された空のゴーストは、本当に空っぽです。
トークの書かれた辞書ファイルは存在せず、シェルがあるだけという構成になっています。
まずはシェルから導入しましょう。一旦さとりすとを閉じ、元のmasterシェルの入ったフォルダを削除します。
そしてダウンロードしたシェルフォルダをmasterに名前変更し、代わりに配置します。
後はさとりすとを再度開けば、無事に読み込まれます。「サーフェスビューワv3」タブから確認してみます。
(タブがない場合は上部メニューの「表示→サーフェスビューワv3」ボタンから表示させます)

様々な表情がしっかり読み込まれていることを確認できました。
これにてシェルの導入は完了です。

次は初回起動イベントを制作してみましょう。
まずはイベントを書き込む辞書ファイルが必要です。辞書ファイルとは、伺かのシステムが『ここにトークが書かれている』と認識するための目印がついたテキストファイルです。
……といっても単に法則に従った名前をつけるだけです。名前の先頭に「dic_」とつければそれは辞書ファイルとして認識されます。
メニューから里々辞書ファイルの作成を選択し、dic_StartEnd.txtという名前の辞書を作成しましょう。

「ファイルイベントツリー」タブのdic_StartEnd.txtを右クリックし、項目の追加を選択。
「文」「単語群」の選択肢がありますが、今は特に選択せずに大丈夫。
今回は初回起動から作っていくので、「初回起動イベント」と入力して決定しましょう。

これでトーク*初回起動イベントが作成されました。
ダブルクリックして開いてみましょう。ここに内容を書いていくことになります。
ちなみに、この「*」は伺かのシステムに「ここからがトークだよ」と認識してもらうための記号です。
さとりすとを使っていれば、特に気にする必要はありません。内容を考えていきましょう。

初回起動イベントには、トーク同様「こうしなければ」という決まりはありませんが、私はゴーストの「普段」につなげるエピソードを書くことが多いです。
つまり、数秒後にランダムトークが始まったり、つついてメニューを出したりできても違和感がない状態につながる……そんなイメージです。
アオとユーザが寝室で夢の話をしている状態。これが今回の初回起動イベントの着地点となります。

着地点を決めたら、次にユーザさんに伝えておくべきことをリストアップします。
真っ先に候補に上がるのは「言わないとわからないこと」です。
例えば今回だと、ユーザがアオの私室にいることは、説明されないとわからないですよね。

他には「疑問に思うだろうことに対する答え」も候補となります。
「あなたはアオちゃんの私室にいます」と言われても「え? なんで?」となりますよね。
「アオは夢の話をしてくれます」というのも「え? どういう関係性?」となってしまいます。
ランダムトークやイベントで疑問が解けていくのも楽しいものですが、「普段」の段階で疑問だらけだとうまくゴーストを楽しめません。

・ユーザは縁もゆかりもない屋敷に、令嬢アオの話し相手として招かれた。
・彼女は普段は寝てばかりいるが、夢の世界の話をすることに興味を持ち、今は起きている。
・夢の世界の話をするのは、ユーザが求めたからである。

リストアップができたら、そこからエピソードの流れを作ります。

・ユーザはアオの私室にいる。アオは眠っているが、声を掛けられ目を覚ます。
・アオはユーザを思い出す。父の呼んだ「話し相手」だ。お互いに名乗り、話すことにする。
・……が、反応は芳しくない。ユーザは苦し紛れに逆に話を聞くことを思いつく。
・意外にも好感触で、アオは嬉しそうに夢の話を始めるのだった。

と、こんな感じです。流れが決まったら、これでようやく書き始めます。
慣れないうちは多少説明っぽくなるかもしれませんが、さほど問題ではありません。
情景描写がうまくいかない! となるかもしれませんが、これも問題ではありません。
変に婉曲的に伝えようとして何も伝わらないことが一番の問題なのですから。

それでもどうしても出来に納得がいかない場合は、数時間、数日など期限を決めて考えてみましょう。
「細かな出来に納得いかない→拘っているうちに視野が狭くなる→「出来ない」ことしか考えられなくなるので自信がなくなる→制作を投げ出す」
……というのは挫折の黄金パターンです。適度に自分を急かし、足が止まってしまわないように心がけましょう。

★初回起動イベントに必要な文法

さて、ここから先は実際のイベントの書き方、つまりは文法にも触れていきましょう。
これは物書き的な意味での文法ではなく、伺かのシステムに意図した演出をしてもらうために必要な記述を指しています。
こちらは「カナタノアオ」の初回起動イベントから抜粋したものです。

\t\*:(10)
:……………
:(すぅ……すぅ……)
:白を基調とした、欧風の気品ある寝室。
天蓋付きのベッドから、少女の穏やかな寝息が聞こえてくる……

「\」マークで始まる不思議な記号がありますね? これはさくらスクリプトと呼ばれるものです。
……スクリプト、と聞くとなんだか難しそうに思うかもしれませんが、必要な分をコピペする程度でも大丈夫なので身構えることはありません。
では早速、使われている2つについて紹介しましょう。

\t

「\t」を書くと、そのトークの中で他のトークが呼び出されるのをロックしてくれます。
要は「これは重要なトークだから、他のトークで遮らないでね」と伺かのシステムに伝えるわけです。
これがないと、ちょっとした動作で初回起動イベントが中断されてしまいます。

\*

「\*」もまた、途中終了を防止するさくらスクリプトで、こちらは選択肢を選ぶ際に時間切れになるのを防止してくれます。
初回起動イベントのように、比較的長いイベントは単純に喋り続けるだけでなく、何らかの選択肢を選びながら進行するケースも多いでしょう。

でもユーザさんが考え事をしていたり、急に電話がかかってきたり……そんな状況になると時間切れでイベントが途中終了。
微妙なモヤモヤを抱えたままトークを聞くことになってしまいます。
ですのでこの2つを文頭に書いておき、イベントの途中終了を防止することが重要です。

\*の方は選択肢のないイベントでは不要ですが、両方まとめてコピペしておくことをおすすめします。どうせユーザさんには見えないし
なお、この記述はトークごとに書く必要があります。選択肢でいくつものトークにまたがる一連のイベントなら、その全てに書かなければならないということです。覚えておきましょう。

★名前入力を実装しよう

さて、続いてもう一つ、初回起動イベントにつきものなアレを紹介しましょう。
ちょっと長い話にはなりますが、大切な内容なのでしっかり読み進めてくださいね。
それがこちら。

InputBoxです。ゴーストに触れたことがあれば、一度は目にしていると思われます。
これもさくらスクリプトから呼び出しています。記述は少し長くなります。こうです。

\![open,inputbox,,,]

openにinputbox...そのままですね。ですが謎の「,(カンマ)」記号が並んでいたりと見慣れぬ感じもするでしょう。
カンマは区切り文字です。\![]のカッコの中にカンマで区切った指示を入れることで、システムは条件に従ったInputBoxを開いてくれます。
……といってもちんぷんかんぷんでしょう。まず基本的な例を書いてみます。

\![open,inputbox,ユーザ名,120,ユーザ]

open,inputboxは言わずもがな。その次からを見ていきましょう。
ユーザ名:これはIDです。簡単に言えばそのInputBoxの名前のようなものです。のちのち参照することになります。
120:これは時間制限です。InputBoxが出てからこの秒数が経過すると時間切れとなり、勝手に閉じてしまいます。
ユーザ:これは初期値です。こう書いておくと、初めから「ユーザ」と入力された状態でInputBoxが開きます。

これらのうち、ID以外は任意入力。すなわち空っぽにすることが出来ます。
その場合は何も記入する必要がありません。つまり……

\![open,inputbox,ユーザ名,,]

これでも問題なく動作してくれます。特に時間制限を空白にすることは初回起動イベントで重要となるため、適当に数値を入れたりはしないようにしましょう。

さて、開いたInputBoxに早速文字を入力して、OKを押してみます。すると……何も起こりません。
実はInputBoxは、それ単体で何かをなすものではないのです。
何かをするためには専用のトーク……「OnUserInput」に必要な処理を書いてあげる必要があります。
と言ってもそう難しくはありません。単純な名前入力をするためのOnUserInputを覗いてみましょう。

*OnUserInput
>(R0)を教えてもらった

処理自体は一行です。が、少し見慣れない記号、書き方がありますね。順を追って解説しましょう。

まずはこの「>」マーク。これはジャンプ記号です。後に続く名前のトークを呼び出してくれます。
このトークだと、一文字目が読まれた瞬間に「(R0)を教えてもらった」トークの再生が始まるわけです。

(R0)

そしてこの(R0)。これは様々な要因により変化する数値。「変数」です。
変数という言葉に耳馴染みがなければ、名前が付いた箱のようなもの、とイメージしてみてください。
「R0」という名の箱の中には、先ほど開いていたInputBoxのIDが入っています。IDは「ユーザ名」でしたね。

そして箱の名前が記述されていれば、伺かのシステムは自動でそれを中身と取り替えてくれます。
つまりこのトークは、システムにはこう読み替えられることになるのです。

>ユーザ名を教えてもらった

続けて、ジャンプ先のトークの方も覗いてみましょう。
こちらもたった一行で書かれています。

*ユーザ名を教えてもらった
$ユーザ名=(R1)

……なんとなく内容はわかるのではないでしょうか?
「$」記号は続く名前が変数名であることを意味しています。
その次の「=」は上書きの指示です。
つまり変数「ユーザ名」の中身を(R1)に取り替えて、と指示しているわけです。

そして先ほど解説した通り、(R1)には別の中身が入っています。
R0はIDでしたね。するとR1の中身とは……そう、入力した文章です。
ここでは「ユーザ」と書かれていたとしましょう。すると最終的にこういう指示になります。

$ユーザ名=ユーザ

後は他の文中で(ユーザ名)と書けば、それらは自動で「ユーザ」と書き換えられることになります。
「InputBoxにユーザが名前を入力し、その名前をゴーストが覚えてくれる」というよくある仕組みは、こうして出来上がっているのです。

これでユーザとの出会い、そしてお互いの自己紹介と流れを済ませる方法を書けました。
最後に一連の使用例を載せておきます。

*初回起動イベント2
\t\*
\![open,inputbox,ユーザ名,,ユーザ]

*OnUserInput
\t\*
>(R0)を教えてもらった

*ユーザ名を教えてもらった
\t\*
$ユーザ名=(R1)

初回起動イベント2からユーザの名前入力に移り、入力後は初回起動イベント3のトークを読み上げる……
そんな仕組みになっています。なお、今回は省略しましたが、実際の作例ファイルにはInputBoxを間違えて閉じちゃったりした場合の対応なども記載されていますので、興味があれば覗いてみてください。

★トークを書いていこう

トークは新たな辞書ファイル「dic_Talk.txt」に書いていきましょう。
しかし……実はネタの出し方、記法などの大部分は「はじめての~」でも書いています。
と、いうことでここでは実際にアオのトークを書く際に考えていたこと、注意したことをまとめます。

初期に用意されたトークは50個。内訳はおおむねこのようになります。

・夢の話(剣と魔法の世界)
・夢の話(銃の世界)
・夢の話(ノージャンル)
・夢の世界の話
・アオの個人的な話

夢の話とコンセプトが決まっているので、もちろん夢の話が大部分を占めています。
後は人となりを伺える過去の話や、現状認識についての話なども。これは設定で決めていたものを利用しています。
全体的な傾向として、夢の世界では外交的、現実世界では内向的な印象を受けてもらえるように書いています。
こだわった点として、表情切り替えの少なさがあります。そのラインナップも真顔、悲しい、悩み、ジト目……と何やら切なげです。
数少ない笑顔は、アオのユーザさんへの期待、その辺りを表現する際に向けられます。

ただ設定欄に書いた、致命的な変化をもたらした過去のことや、アオの夢が本当にただの夢なのかといった要素は現時点ではぼかしています。
設定を用意したからといって、表に出さなければいけないというものではないからです。
幸い、ゴーストには更新という形で文章を追加できる余地が用意されていますし、アマチュアの創作ゆえに資金不足で続きが書けない、なんてこともありません。
全部織り込まないと完成とはいえない、なんて心境に至らないよう、適度に気楽に書いていきましょう。
……と、こんな感じです。実際に出来上がったものは作例の方を覗いていただければ幸いです。

★さわり反応を作ろう

新たな辞書ファイル「dic_Touch.txt」を作りましょう。ここに書いていきます。
さわり反応を実装するためには、シェルにより当たり判定がセットされた箇所に、対応した名前のトークを書く。それだけです。
名前は「キャラのID」「部位名」「動作名」を区切らず並べたもの、という形式になっています。
キャラのIDについては少し複雑なので、今は「メインキャラが0、サブキャラが1」で大丈夫。
具体的なトークの例を見てみましょう。

*0Headなでられ
:えへへ。

「メインキャラの」「Headが」「なでられた」時にこのトークが呼び出されます。
たったこれだけでさわり反応は実装することができるのです。

ただし、それには「Head」のような部位名を調べることが必要になります。
例えばシェルに記載されている部位名が「Head」ではなく「head」だったり「atama」だったりすると、上記の文名では反応してくれません。
シェルのsurfaces.txtを覗いて調べる必要がありますが、ちょっとばかし面倒です。
ああ、そんな便利な機能がさとりすとに付いて……

います。それがサーフェスビューワv3に搭載された、触り判定箇所の表示機能です。
サーフェスビューワv3タブをクリックすると、上部メニューの右に緑色の「設定」が表示され、そこから実行できます。

(一部抜粋)
「head」や「mimi」など、きちんと部位名が取得できました。
あとは満足するまで書いていくだけです。

初回起動イベント、トーク、さわり反応……だいぶ形ができあがってきましたね。
もう少し作り込んでいけば、一つのゴーストとして立派に完成させられます。
あと3歩、まずはその1歩。メインメニューを作ることから続けていきましょう。

★メインメニューを作ろう

これも新たな辞書「dic_Menu.txt」に書いていきます。辞書ファイルが増えてきましたね。
「まとめて書いちゃえば良くない?」と横着したくなるかもしれませんが、これはやめておいたほうがいいです。
手持ちの本を何も考えずに詰め込んだだけの本棚から、目当ての本を引っ張り出すには相当な時間が掛かりますよね?
小さな苦労を積み重ねないためにも、詰め込む段階からきっちりと整頓しておきましょう。

機能はシンプルに絞り、こんな感じに。アオをつつかれ(クリックされ)たことで開けるようにします。
部位名に指定せず、「0つつかれ」と続けて書けば、当たり判定のない部位をクリックした時に呼び出されます。
それでは早速中身を見てみましょう。

*0つつかれ
_何か話して
_喋り間隔の変更
_なんでもない

「_(アンダーバー)」は続く記述が選択肢であることを示します。
選択肢は、クリックすることで同名のトークへのジャンプを行ってくれます。

さっそくトークの内容も作っていきましょう。まずは1つ目。

*何か話して
()

空っぽの変数が一つあるだけ……? いえ、違います。
()と書くと、名前の付いていないトークが内容として読み込まれる仕様となっているのです。
名前のないトークは先ほどたくさん用意しました。複数あるので、その中からランダムで呼び出されます。
つまりこれだけで「何か話して」でランダムトークを呼び出せるようになるのです。
次は喋り間隔の変更です。

*喋り間隔の変更
_30秒
_60秒
_120秒
_180秒
_やめとく 0つつかれ

選択肢から秒数を選ぶ……のですが、ちょっと妙な記述が紛れていますね。
これはエイリアスと呼ばれる記述。要は「こちらを真のジャンプ先として使ってね」という指令です。
つまり、ユーザが「_やめとく」をクリックした場合、ジャンプ先となるのは真のジャンプ先……「0つつかれ」の方になります。
これで「やめとく」を押すとメインメニューに戻る、のような見栄えの動作を行う事ができます。

このように便利なエイリアスですが、ちょっと注意点があります。
「_やめとく」と「0つつかれ」に空白のスペースが入っていますよね?
これはスペースではありません。タブ記号と呼ばれる、特殊な空白を表す記号です。

日常生活ではあまり縁の無い記号ですが、キーボードの「Tab」キーを押すだけで入力できます。
通常の空白ではエイリアスが機能しないので注意しましょう。私も散々苦しめられました。

……と、話が脱線してしまいましたね。
話を戻して、秒数の選択肢のジャンプ先となるトークを見てみましょう。

*30秒
$喋り間隔=30秒

この$喋り間隔は特別な意味を持った名前の変数です。
システムがこれを読み取り、自動で喋り間隔を合わせてくれます。
単位は「秒」です。きちんとつけないと認識してくれないので注意しましょう。
60、120、180も同様に数値だけ変えれば実装できます。

これで喋り間隔の変更も実装完了です。
最後に、メインメニューをキャンセルするための「なんでもない」の処理を作りましょう。
といっても……

*なんでもない
\e

いっそすがすがしいほど単純です。閉じるだけなので当たり前なのですが。
ちなみに、この「\e」こそ、かの有名な「えんいー」。
バルーンを閉じさせるさくらスクリプトです。

これにてメインメニューも実装完了です。
機能がシンプルだったこともあり、拍子抜けするほど簡単な内容に思えたのではないでしょうか。
ですが、実はここでは変数やジャンプ、文名など今まで説明したことがしっかり省略されています。
これで内容を理解できたということは、今までの説明が頭に入っている証となるのです。
もしわからずとも、一歩戻って読み直せば徐々に身についていきます。
あと2歩、焦らずゆっくり進めていきましょう。

★ゴーストの起動時、終了時に喋らせよう

ゴーストの起動時、終了時のトークは初回起動と同じ、dic_StartEnd.txtに書いていきましょう。
ゴーストの起動時、終了時には「OnBoot」「OnClose」という名前のトークが呼び出されます。
それを3つほど用意すれば出来上がり……なのですが、せっかくなので少し凝った仕様のトークも書いてみましょう。

*OnClose (初回終了)!=した
\t\*
$初回終了イベント読了=した
:(6)……え? ……そう、ですか。
:アオは古めかしい掛け時計を見た……

これは初回起動の終了時のみ呼び出されるトークです。
選択肢のエイリアスと同様、トークの名前の後にタブ文字区切りで何か書かれていますね?

これは条件分岐です。変数「初回終了」が「した」ではない場合のみ呼び出して、という指示をしています。
見慣れない「!=」は「左側と右側が同じではない場合」という条件を表す記号です。
反対に「左側と右側が同じである場合」を示したい場合は「==」となります。「=」ではダメなので注意しましょう。

$初回終了に初期値は設定されていません。なので(初回終了)の中身は「した」とは一致しません。
ということで、このトークは問題なく呼び出されます。そして文頭の上書き処理により、(初回終了)は「した」となり……
これ以降に終了しても、(初回終了)が「した」と一致するため、このトークは呼び出されなくなります。

これにより、初回起動の終了時のみ呼び出されるトークが実装できるというわけです。
それではうまく動くかチェックしてみましょう

……おや? 違う終了トークが呼び出されてしまいました。
といっても理由は呆れるほど単純です。初回起動の終了時に呼び出すトークが、先ほどのトークに限定されていないからです。
ならばOnCloseはそれ一つだけにして、他のトークは別の名前に……ともいきません。
ゴーストを終了する時に呼ばれるトークの名前はOnCloseと決まっています。他の名前にはできないのです。

では一体、どうすれば……? その答えはこうです。

*OnClose
>初回起動終了 (初回終了)!=した
>終了トーク

OnCloseトークの内容を、ジャンプのみに書き換えました。
ジャンプもまた、タブ文字区切りで条件を書くことで条件分岐させることができます。
その場合、まず条件に満たすかが判定され、満たした場合のみジャンプが行われるのです。

OnCloseはこの1つだけにします。これで終了時は必ずこのトークが呼び出されます。
そしてジャンプが設定されていることにより、初回終了時は専用トークを優先して呼び出す。
それ以外の場合は通常の終了トークを呼び出す……この流れが実装できるのです。

よく使うテクニックなので覚えておきましょう。
例えばそう、初回の起動時のみ呼び出される、あのイベントなどにも……

*OnBoot
>初回起動イベント (初回起動)!=した
>起動トーク

初回起動イベントの最後に呼び出されるトークに、変数「初回起動」を「した」する処理を書き加えれば完成です。

★ネットワーク更新に対応させよう

初回起動で出会い、メニューでちょこっと設定も変えられ、ランダムトークし、出会いと別れでちゃんと反応してくれる。
しっかりとした形ができあがりました。あともう一息。最後の一歩です。
ここからは実際にゴーストを公開する際に行う、各種設定の仕方を説明します。

伺かユーザの絶対的な楽しみの一つ、それが更新です(※個人的な願望を含みます)。
公開後のゴーストに更新を掛けるため、ちゃんと設定をしておきましょう。
設定には今まで同様、指定された名前の文……ではなく単語群を作成します。

単語群は文と似ていますが、一度に呼び出せるのは一行のみという制約があります。
例えば、このように……

@魚名
サンマ
サバ
マグロ

と3行書かれていても、読まれるのは「サンマ」「サバ」「マグロ」のいずれか一つのみです。
そんなの何に使うの? という話ですが、このように使えます。

*釣り
:(魚名)が釣れました。

ランダムに一つの単語を取ってくる。文字通りの単語群ですね。
一風変わったトークを作ってみたいな、なんて時に使えるので頭の片隅にでも入れておきましょう。

それではネットワーク更新の話に戻りましょう。
設定するためには、@homeurlにアドレスを記載する。それだけです。
今回は実際に「カナタノアオ」で使う、dic_Menu.txtに記載された更新用アドレスから引用します。

@homeurl
https://kogami.sakura.ne.jp/ghost/kanata_no_ao_update

ここからデータを引っ張ってくることで更新が行われるわけですね。
データはこのように自分のサーバーに置くこともできますが、専用アップローダーのななろだを利用するのが手軽です。
ななろだにゴーストをアップロードすれば更新用URLも発行してもらえるので、それを記述しましょう。
なお、単語群だからと複数行書く必要は全くありません。

★文字置換でトークを楽に書こう

ゴーストには辞書ファイル以外にも、テキストファイルを配置することができます。
descript.txt、replace/replace_after.txt、install.txt……などなど。
専用のファイルをいくつか作成し、設定を入力していくわけなのですが……

さとりすとではこれも手軽に設定することが可能です。
ファイルはさとりすとが自動で作成してくれます。便利……!
いずれも上部メニューの「表示」から、サーフェスビューワv3を開いた時のように開けます。
ともかく設定項目を見ていきましょう。まずはトークを書くのが便利になる設定から。

文字置換リストに単語を登録すれば、トーク中の単語を自動で置換してくれます。
なんだかマニアックに思えますが、これが大助かりな機能なのです。
実際に「カナタノアオ」に書かれているこんなトークを見てみましょう。


:(6)……将来の夢、ですか。昔はあった気がします。
今は……(5)記憶もおぼろげで、思い出せません。

何か話しにくそうに話している、そんな印象を受けるのではないでしょうか。
しかしこれを実際に読ませてみると、思いの外スラスラと読み上げます。
読み上げを一時停止するウェイトが設定されていないからです。
ウェイトはさくらスクリプトで「\w9」このように書くことができ、数字部分を変えて長さの調整も可能です。なので、このように……


:(6)…\w9…\w9将来の夢、\w6ですか。\w9昔はあった気がします。\w9
今は…\w9…\w9(5)記憶もおぼろげで、\w9思い出せません。

と書けば、適切なウェイトが入るわけです。面倒ですね。
こんな時こそ自動置換が役立つのです。

このように句読点や三点リーダなどに設定してしまえば、いちいちウェイトを設定する必要はありません。
ただしこの機能は強力な反面、弱点もあります。例えばこんな選択肢があるとします。

_弱点って何?

一見普通の選択肢ですが、選択肢は名前に含まれるさくらスクリプトを無効にします。
なのでこれを実際に読ませてみると……

_弱点って何?\w6

と、ユーザさん視点では完全に謎の記号が出現してしまいます。
これを防止するためには、トーク中の置換される文字の手前にφ(ふぁい)の小文字を書く必要があります。
つまり、_弱点って何φ? と、このように。
これも頭の片隅に置いておいてください。

★最後に細かな設定をしよう

どれもメニュー上部の「表示」から表示させることができます。

ゴーストプロパティ

ゴーストのプロパティです。ゴースト名や作者名、キャラ名をここに記載します。
英数で書く必要がある場所があったりと、ちょっぴりややこしいのですが……
さとりすとでは丁寧な注釈が付いているので説明の必要は消え去りました。
必須項目には必須と書かれているため、その辺りと、作者名辺りは書いておきましょう。

インストール設定

ゴースト名、インストール先のフォルダ名を設定します。
注釈通り、あなたのゴーストを誰かがインストールする時に必須となっていますので、ちゃんと設定しましょう。
フォルダ名に関しては少し注意があります。それは長めに付けることです。

同じフォルダ名のゴーストをインストールすると、伺かのシステムは警告を出してくれます。しかしそこで間違った選択をすれば、新しいゴーストに上書きされてしまいます。
なのでゴースト名、フォルダ名は決める前に検索して、被りがないか事前チェックしておきましょう。
それでゴースト名をローマ字に変換したものを用いるなどすれば、ほぼ安全です。

変数の初期化

変数の初期値を設定します。ここでは独断と偏見で選んだ最低限のものをセットしていきます。

$喋り間隔に180秒
上述した喋り間隔は、実は初期値は入っていません。
なので設定してあげないと、メインメニューで喋り間隔を設定するまでダンマリを決め込んでしまいます。
180秒に設定されることが多い値なので、180秒にしておきましょう。

$喋り間隔誤差に10%
上記の喋り間隔に若干のズレが生まれるようになります。

$会話時サーフェス戻しに有効
会話が始まる時に自動で素の表情に戻るようになります。
素の表情は以下のデフォルトサーフェス0で指定します。

$デフォルトサーフェス0に0
素の表情となるサーフェス番号です。
トーク終了から一定時間経過後、自動で切り替わる表情でもあります。
セットしておかないと延々笑顔のままだったり、泣いたままだったりとちょっぴり不気味です。



以上で基本的な設定項目はおしまいです。全部さとりすと上で完結します。恐ろしいほどの便利さです。
ただ、ここまで書いたのならついでにもう一つ。readme.txtも作ってしまいましょう。

readme.txt

テキストファイルの作成から、readme.txtを追加します。
ここに書いた内容はインストール時に表示されたり、ゴースト起動中に右クリック→情報→キャラクタについてを選ぶことで閲覧できます。
必須ではありませんが、ゴーストの基本的な紹介などを書いておくと見栄えが良くなります。
これで本当に最後です。あとちょっとだけ頑張ってみましょう。

★終わりに

お疲れ様でした。結構長い文章で、読むだけでも大変だったことでしょう。
しかしこれで、ゴースト制作の際の流れを知っていただけたと思います。
あなたがゴーストを作る際、どこから取り掛かるか。どう考えるか……
そうした道に迷った時、この記事があなたの助けになれば幸いです。

あくまでこの記事の作り方は最低限のものとなっています。
より作りこみたい時は、まず里々wikiを覗いてみましょう。様々な事例に対応したTIPSが揃い、当記事の執筆にも参考とさせていただきました。
それからSSPの公式文書も。さくらスクリプトの一覧を見ることができます。
もちろん、このページの拍手ボタンや、X(Twitter)や各種SNS、掲示板に相談してみるのも手です。

また、アドカレ1日目にはnetai98さんがwhenと変数でゴリ押せ!里々わからないという、条件分岐に使うwhenや変数について詳しく解説した記事を投稿されています。そちらもご参考ください。
アドカレでは他にも様々なゴースト制作者さんにノウハウや思考を公開していただけるようなので、チェックしてみましょう。
ちなみに明日(2024年12月3日)は第一会場にてDonさん、第二会場にてponapaltさんがそれぞれ記事を投稿されますのでお楽しみに。

最後に、今回作成した「カナタノアオ」のnarファイルをご用意しました。
お手持ちのSSPでお楽しみになったり、作例の参考として利用していただければ幸いです。
公開ページへ

それでは今度こそ、記事はここでおしまいです。
このページがあなたの創作に、そしてあなたが生み出したゴーストと出会うユーザさんの喜びに少しでも寄与できれば幸いです。
読んでいただきありがとうございました。よい伺かライフを!