開発中の備忘録をTIPS形式で掲載しています
surfaces.txtのアニメーションインターバル定義には、トークに合わせてanimationを動かすオプションのtalkがあります。 これを使うとトーク時に口を動かす表現が実現できます。ただし、これは「……」のようなセリフ的には無言の部分でも口が動いてしまいます。解決策を考えましょう。
クイックセクションには以下の特徴があります。
クイックセクション内の文章は一瞬で表示されます。一瞬で表示されるということは、当然口パクの対象外になります。
いっぽうで、クイックセクション内でもウェイト(\w9や\_w[500]など)は依然として有効です。
すなわち、以下のようにさくらスクリプトを記述することで、口パクする/しないを指定することができます。
// before
……あいうえお
// after
\_q…\_w[500]…\_w[500]\_qあいうえお
その都度ウェイトを仕込むのは大変なので、里々ならreplace.txt、YAYAならOnTranslateに置換処理を記述するとよいでしょう。
SSPのデフォルト表示速度は50ms/文字(ユーザ側で調整可能)ですが、
早口、ゆったりの表現や長い文章をゆっくり表示したいなど、ゴースト側から表示速度を変更したいことがしばしばあります。
考え方自体は単純ですが、問題はどうやってウェイトを挿入するかです。 機械的に1文字ごとにウェイトを入れようとすると、さくらスクリプトの記述が壊されてしまいます。
\_q -> \\_w[25]_\_w[25]q\_w[25] (さくらスクリプトが機能しない)
さくらスクリプトをRE_REPLACE関数で一時的に制御文字に置き換え、ウェイト挿入後に再度置換することで解決します。
AddWait
{
// _argv[0]: 対象文字列
// _argv[1]: ウェイト[ms]
// メッセージスピードの標準は50ms これに加算すると考えて調整
_text = _argv[0]
_wait = '\_w[' + _argv[1] + ']'
// 適当な制御文字 YAYAは0x0を扱えないので0x1で
_tagmark = CHR(0x1)
// さくらスクリプトは_tagmarkに置き換えて退避
//(さくらスクリプト中にウェイト記述が挟まって破綻するのを防ぐ)
// 置換したさくらスクリプトは配列に保持しておいて適宜取り出す
_t = RE_REPLACE(_text, '\\_{0,2}[a-zA-Z0-9*!&\-+](\d|\[("([^"]|\\")+?"|([^\]]|\\\])+?)+?\])?', _tagmark)
_tags = RE_GETSTR
_tagcount = 0
_textlen = STRLEN(_argv[0])
_result = ""
for _i=0; _i<_textlen; _i++ {
_c = SUBSTR(_t, _i, 1)
if _c == _tagmark {
_result += _tags[_tagcount]
_tagcount += 1
}
else {
_result += _c + _wait // #1
}
}
_result
}
OnTranslateInternal関数にこれを仕込むことでウェイトの調整がトーク全体に適用されます。
たくさんのトーク群からどのようにトークを選び、喋らせるかは、ゴーストの実在感・トークの没入感に関わります。
トーク選択の基本処理はSHIORIがよしなにやってくれていますが、デベロッパー側からある程度ルールを設定することも可能です。
トーク被りを避け、出来るだけまんべんなくトークが選ばれるようにしたい。
『$文「○」の重複回避』『$単語群「○」の重複回避』を利用してトーク被りを回避できます。
詳しくはこちらを参照
関数のオプション「nooverlap」を指定することでトーク被りを回避できます。
詳しくはこちらを参照
上記の方法では、直前のトークとの被りのみ考慮されます。つまり極端に言えば、トークがA,B,C,...と用意されているのに、
トークA -> トークB -> トークA
のような順番は依然としてありえます。
このトークさっき聞いたな?となるのはなるべく避けるべきです。
そこで提案したいのがルーレット選択アルゴリズムです。
実装方法として、
これにより、トークが選ばれた直後は被る確率が最小になり、その後少しずつ確率が増えることで前述の問題を軽減し、より自然かつ満遍ないトークが可能になります。
拙作ゴースト「Crave The Grave」で実装されています。
ゴーストのトークを書く際、通常の文章と異なる最も大きな点は改行だと思います。
筆者は文章の中途半端なところで改行が挟まると読みづらいため、読みやすい部分で改行を入れるのですが、
一般的なブログサイトは1行60文字程度であるのに対して、伺かの標準バルーンは24文字(全角、SSPデフォルト+の場合)であり、トークを書いていると改行が頻繁に来るなと感じています。
そこで見栄えの良い改行を自動化し、デベロッパーがトークの内容に専念できるようにするにはどうすればよいかを考えました。
見栄えの良い文章とは、すなわち意味の区切り=文節で改行が入っている文章です。 例えば、
吾輩は猫である。名前はまだない。
どこで生れたか頓と見当がつかぬ。何でも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している。吾輩はここで始めて人間というものを見た。
という文章をバルーンで表示する場合、そのまま書き込むとこうなります。
吾輩は猫である。名前はまだない。
どこで生れたか頓と見当がつかぬ。何でも薄暗いじ
めじめした所でニャーニャー泣いていた事だけは記憶
している。吾輩はここで始めて人間というものを見た。
24文字の時点で機械的に折り返されています。ぶつ切りな印象です。
つぎに、以下で紹介する自動改行関数を通した場合こうなります。
吾輩は猫である。名前はまだない。
どこで生れたか頓と見当がつかぬ。何でも
薄暗いじめじめした所でニャーニャー泣いて
いた事だけは記憶している。吾輩はここで始めて
人間というものを見た。
文節で改行しています。
従来より自然な印象が出ている気がします。
形態素解析ソフトMeCabを実装したSAORI(kisaragi.dll)で文章を単語に分解し、各品詞から文節を割り出すことが可能です。 これを利用して、文章を文節ごとに改行する関数を作ります。
拙作ゴースト「Crave The Grave」で実装されています。
ただし現在の機能ではdllファイルを差し替えるのみなので、更新に伴って必要となる作業がある場合は手作業で行う必要がある。
だからといって後手のみanimation番号を変えただけだと、別の着せ替えパーツとして認識されてしまう。
addid(解説)を使うと複数のanimationをまとめて1つの着せ替えパーツとして定義できる。
上述のように後手を別アニメーションとして定義したあと、shellのdescript.txtに以下のように記述する。
sakura.bindoption.group,袖
sakura.bindgroup505318.name,袖,長白
sakura.bindgroup505318.addid,500168
// 注
// animation505318: 前手用の袖アニメーション
// animation500168: 後手用の袖アニメーション