おわらない

index

tips

blog

TIPS

開発中の備忘録をTIPS形式で掲載しています

「......」で口パクアニメーションしないようにしたい

……で口パクを止めている

……で口パクを止めている

シェルの口パク

surfaces.txtのアニメーションインターバル定義には、トークに合わせてanimationを動かすオプションのtalkがあります。 これを使うとトーク時に口を動かす表現が実現できます。ただし、これは「……」のようなセリフ的には無言の部分でも口が動いてしまいます。解決策を考えましょう。

解決策

  • 「……」をクイックセクション(\_q)で囲む。

クイックセクションには以下の特徴があります。

  1. クイックセクション内の文章は一瞬で表示される
  2. ただしウェイトは有効である

クイックセクション内の文章は一瞬で表示されます。一瞬で表示されるということは、当然口パクの対象外になります。
いっぽうで、クイックセクション内でもウェイト(\w9や\_w[500]など)は依然として有効です。

すなわち、以下のようにさくらスクリプトを記述することで、口パクする/しないを指定することができます。

// before
……あいうえお

// after
\_q…\_w[500]…\_w[500]\_qあいうえお

その都度ウェイトを仕込むのは大変なので、里々ならreplace.txt、YAYAならOnTranslateに置換処理を記述するとよいでしょう。

トーク文章の表示速度を辞書側で調整したい

SSPのデフォルト表示速度は50ms/文字(ユーザ側で調整可能)ですが、
早口、ゆったりの表現や長い文章をゆっくり表示したいなど、ゴースト側から表示速度を変更したいことがしばしばあります。

実現するための考え方

  • 遅らせたい場合、1文字ごとにウェイト(\_w[25]など)を入れて表示速度を調整すればよい
  • 早めたい場合は上記に加えてさくらスクリプト\_qでデフォルトのウェイトを消す必要がある

考え方自体は単純ですが、問題はどうやってウェイトを挿入するかです。 機械的に1文字ごとにウェイトを入れようとすると、さくらスクリプトの記述が壊されてしまいます。

\_q -> \\_w[25]_\_w[25]q\_w[25] (さくらスクリプトが機能しない)

具体的な方法(YAYA)

さくらスクリプトを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がよしなにやってくれていますが、デベロッパー側からある程度ルールを設定することも可能です。

前提

トーク被りを避け、出来るだけまんべんなくトークが選ばれるようにしたい。

里々

『$文「○」の重複回避』『$単語群「○」の重複回避』を利用してトーク被りを回避できます。
詳しくはこちらを参照

YAYA

関数のオプション「nooverlap」を指定することでトーク被りを回避できます。
詳しくはこちらを参照

提案:ルーレット選択アルゴリズムを実装する(YAYA)

上記の方法では、直前のトークとの被りのみ考慮されます。つまり極端に言えば、トークがA,B,C,...と用意されているのに、

トークA -> トークB -> トークA

のような順番は依然としてありえます。
このトークさっき聞いたな?となるのはなるべく避けるべきです。
そこで提案したいのがルーレット選択アルゴリズムです。
実装方法として、

  • 各トークに重みを付け、それを考慮したランダム選択を行います。
  • 選択のたびに次の処理を行います。
    • 選ばれたトークは重みを1に減らす
    • 選ばれなかったトークは重みを一定数増やす

これにより、トークが選ばれた直後は被る確率が最小になり、その後少しずつ確率が増えることで前述の問題を軽減し、より自然かつ満遍ないトークが可能になります。

実装例

拙作ゴースト「Crave The Grave」で実装されています。

トークを日本語的にいい感じのところで自動改行したい

トーク毎に改行にこだわるのは面倒

ゴーストのトークを書く際、通常の文章と異なる最も大きな点は改行だと思います。
筆者は文章の中途半端なところで改行が挟まると読みづらいため、読みやすい部分で改行を入れるのですが、 一般的なブログサイトは1行60文字程度であるのに対して、伺かの標準バルーンは24文字(全角、SSPデフォルト+の場合)であり、トークを書いていると改行が頻繁に来るなと感じています。 そこで見栄えの良い改行を自動化し、デベロッパーがトークの内容に専念できるようにするにはどうすればよいかを考えました。

文節を機械的に見分けて処理する

見栄えの良い文章とは、すなわち意味の区切り=文節で改行が入っている文章です。 例えば、

吾輩は猫である。名前はまだない。
 どこで生れたか頓と見当がつかぬ。何でも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している。吾輩はここで始めて人間というものを見た。

という文章をバルーンで表示する場合、そのまま書き込むとこうなります。

吾輩は猫である。名前はまだない。
 どこで生れたか頓と見当がつかぬ。何でも薄暗いじ
めじめした所でニャーニャー泣いていた事だけは記憶
している。吾輩はここで始めて人間というものを見た。

24文字の時点で機械的に折り返されています。ぶつ切りな印象です。
つぎに、以下で紹介する自動改行関数を通した場合こうなります。

吾輩は猫である。名前はまだない。
 どこで生れたか頓と見当がつかぬ。何でも
薄暗いじめじめした所でニャーニャー泣いて
いた事だけは記憶している。吾輩はここで始めて
人間というものを見た。

文節で改行しています。
従来より自然な印象が出ている気がします。

くわしい説明(YAYA)

形態素解析ソフトMeCabを実装したSAORI(kisaragi.dll)で文章を単語に分解し、各品詞から文節を割り出すことが可能です。 これを利用して、文章を文節ごとに改行する関数を作ります。

  • editing

実装例

拙作ゴースト「Crave The Grave」で実装されています。

栞を最新版にしよう

よい

  • 新機能が使える
  • バグが修正され、不自由/危険が解消される
  • 最新版をつかっているという安心感

わるい

  • 更新の手間(複数ゴースト等を抱えていると特に)

解決策

ただし現在の機能ではdllファイルを差し替えるのみなので、更新に伴って必要となる作業がある場合は手作業で行う必要がある。

ある着せ替えパーツの表示順をサーフェスによって変えたい

こういうサーフェスがある。

こういうサーフェスがある。

袖を着せ替えパーツとしている。

袖を着せ替えパーツとしている。

腕を後ろで組むサーフェス(表示の優先度が胴>腕)を作りたいけれど、

腕を後ろで組むサーフェス(表示の優先度が胴>腕)を作りたいけれど、

同一のanimation番号では胴<腕のままなので、後ろに表示されない。

同一のanimation番号では胴<腕のままなので、後ろに表示されない。

だからといって後手のみanimation番号を変えただけだと、別の着せ替えパーツとして認識されてしまう。

解決法

addid(解説)を使うと複数のanimationをまとめて1つの着せ替えパーツとして定義できる。
上述のように後手を別アニメーションとして定義したあと、shellのdescript.txtに以下のように記述する。

sakura.bindoption.group,袖
sakura.bindgroup505318.name,袖,長白
sakura.bindgroup505318.addid,500168

// 注
// animation505318: 前手用の袖アニメーション
// animation500168: 後手用の袖アニメーション
やりたい動作が実現できた。

やりたい動作が実現できた。