ツクールMVで文字の表示に合わせて処理を実行したい、立ち絵のリップシンク的な(以下みたいな)処理をしたい、という場合に何処に手を加えればいいかということを考えたり、考えたことを書く記事。
以下のプラグインを導入すると、メッセージ表示の文字出力に合わせてコンソールログに出力する文字列を吐き出す機能が実装されます。
※リップシンクがいきなり実装されるわけではないです。
実際に口パクをさせたい場合は、コンソールログを出力している箇所に、アニメーション制御の処理を行えば良いです。
以下よりメッセージ表示周りの仕組みと、フック箇所の理由を解説。
「文章の表示」処理は、Scene_Mapのプロパティ_messageWindowに格納された、Window_Messageが行っている。
Scene_Map :_messageWindow:Window_Message
Window_Messageは、メッセージ出力に関するプロパティやメッセージウィンドウの開閉、ウィンドウ内に文字列を表示・更新処理などを担当している。
Window_Messageは、毎フレーム更新処理が叩かれており、プロパティが変更された場合、状態に応じて内容を書き換え続けようとする。
Window_Message#update:Scene_Mapより毎フレーム実行される。
Window_Message#addText(str)が実行されると、メッセージはビジーや入力待機状態でない限りすぐに文章出力を行おうとする。
Window_Messageの表示の更新処理を担当しているメソッドは、Window_Message#updateMessageである。
Window_Message#addText:メッセージの表示内容を追加(表示のキック) Window_Message#updateMessage:メッセージ表示中の更新処理のメイン部、updateからメッセージウィンドウ表示中実行され続ける。
大まかには以上の仕組みでメッセージは表示されている。
メッセージに追加された文章の出力を行う処理は、Window_Message#updateMessage内のメソッドWindow_Message#processCharacterが行っている。
Window_Messageは自身に独自のprocessCharacterを持たないため、Window_Baseのメソッドを継承している。
Window_Messageは自身に独自のprocessCharacterでは、次に出力する文字が制御文字(\+1字、あるいは改行など)である場合、その文字ではなく専用の処理を実行しようとする。
制御文字でない場合、Window_Base#processCharacterは、processNormalCharacterを実行する。
Window_Message#updateMessage:メッセージ表示中毎フレーム実行 Window_Message:Window_Base#processCharacter:制御文字を含むメッセージ表示処理 Window_Message:Window_Base#processNormalCharacter:制御文字以外の表示処理
制御文字でない場合、Window_Base#processCharacterはprocessNormalCharacterを実行する。制御文字で一括表示単位になった文字列をウィンドウに表示する。
制御文字が含まれる間は、文字を出さない(ウェイトや色変更など)可能性があるため、Window_Message:Window_Base#processCharacterでアニメーションさせると文字表示と同期しない問題が発生する。
よって、制御文字が全て省かれたWindow_Message:Window_Base#processNormalCharacterでアニメをさせることで、1文字(1表示単位)で1コマとなり疑似リップシンクが出来る。ということになる。
ただしこの場合も<>による文字ブロック化の制御がされている場合、その文字ブロックで1単位としてアニメーションする。
ツクールMVの文字表示は、1文字1フレーム。つまり1秒60文字表示される。
この文字速度のままリップシンクさせると、やたらせわしなく口を動かしてしまい様にならない。
なのでいい感じの場所で文字表示にwaitを入れる必要があるよ。