ページ 11

Game_Messageからフキダシアイコン表示を行う方法

Posted: 2022年10月16日(日) 17:04
by kyoro
ツクールMVにおける会話でデフォルトの「文章の表示」を使って
名前
「~」
と表示するのは億劫なので、以下の記事を参考にして、次のようなスクリプトを作りました。
https://note.com/asakayu/n/n5611ef004b23

コード: 全て選択

Game_Message.prototype.show = function (it, Message) {
    let str = '「' + Message + '」';
    $gameMessage.newPage()
    $gameMessage.add($gameVariables.value(19))
    $gameMessage.add(str)
    it.setWaitMode('message')
};
これは、スクリプトで$gameMessage.show('会話内容', this)と打ち込むと、\v[19]に格納された名前を一行目に表示。二行目に「会話内容」と表示されます。

このshow関数を拡張して、フキダシアイコンの表示も可能なtalk関数を作成しようと思い、以下のコードを作りました。

コード: 全て選択

Game_Message.prototype.talk = function (Message, it) {
    let Fkind = 0;
    switch (Message) {
        case '!びっくり':
            Fkind = 1;
            break;
        case '!はてな':
            Fkind = 2;
            break;
        case '!音符':
            Fkind = 3;
            break;
        case '!ハート':
            Fkind = 4;
            break;
        case '!怒り':
            Fkind = 5;
            break;
        case '!汗':
            Fkind = 6;
            break;
        case '!くしゃくしゃ':
            Fkind = 7;
            break;
        case '!沈黙':
            Fkind = 8;
            break;
        case '!電球':
            Fkind = 9;
            break;
        case '!zzz':
            Fkind = 10;
            break;
        default:
            let str = '「' + Message + '」';
            $gameMessage.newPage()
            $gameMessage.add($gameVariables.value(19))
            $gameMessage.add(str)
            it.setWaitMode('message')
    }

    if (Fkind != 0) {
        this._character = this.character(-1);
        if (this._character) {
            this._character.requestBalloon(5);
            this.setWaitMode('balloon');
        }
    }
}
'会話内容'の部分に'!びっくり'と打つと、フキダシアイコンのびっくりをウェイトモードで表示できるような仕様を想定しておりましたが、最後のif分に問題があるようで上手く関数が呼び出せません。
そこで、thisが何なのかを調べてみると、Game_Interpreterと置換しているようだったので、thisの部分をGame_Interpreterに変更しましたがGame_Message内では他クラスを呼び出せないのか、それも上手くいきません。別クラスのメソッドを呼び出すにはどうすればよいのでしょうか。

Re: Game_Messageからフキダシアイコン表示を行う方法

Posted: 2022年10月17日(月) 03:49
by Plasma Dark
1. Game_MessageクラスインスタンスとGame_Interpreterクラスインスタンス

解説記事の例では変数の名前に、一般に伝わらない略語を使っているのでGame_Message.prototype.showの引数の意味が取りづらくなっていますね。
itとはおそらくinterpreterの略という意図でつけられた名前だと思います。

また、$gameMessageの正体は、Game_Messageクラスのインスタンスです。
rpg_managers.js内のDataManager.createGameObjectsメソッド内にてインスタンスを生成しています。

それをGame_Messageクラス内のメソッドから参照するのは(スクリプトに書いていた内容をできるだけ変えずに移植することでわかりやすくする意図があったのかもしれませんが)、結果として奇妙なコードになってしまっています。

以上を踏まえて、Game_Message.prototype.showを書き直すと以下のようになります。

コード: 全て選択

Game_Message.prototype.show = function (interpreter, message) {
  this.newPage();
  this.add($gameVariables.value(19));
  this.add(`「${message}」`);
  interpreter.setWaitMode('message');
};
このinterpreterが何者であるかというと、イベントコマンドに書いたスクリプトのthisです。
$gameMessage.show(this, '会話内容');
これは、そのイベントの実行主体であるGame_Interpreterクラスインスタンスです。

Game_Messageクラスに定義したshowメソッドを、$gameMessage.show(引数)で呼び出すことができているので、Game_Interpreterに定義されたメソッドも同様に、
interpreterが渡されたshowメソッドの中であれば、interpreter.メソッド名(引数)で呼び出すことが可能です。

プレイヤーキャラクターに吹き出しアイコンを出したいのであれば、こんな感じで書くことによって動かすこと自体は可能です。

コード: 全て選択

Game_Message.prototype.talk = function (interpreter, message) {
  if (message === '!びっくり') {
    const balloonId = 1;
    interpreter._character = interpreter.character(-1);
    if (interpreter._character) {
      interpreter._character.requestBalloon(balloonId);
      interpreter.setWaitMode('balloon');
    }
  } else {
    this.show(interpreter, message);
  }
};
簡単のため、分岐をびっくりのみにし、showメソッドも定義されたものがある前提で書いています。
ただし、characterメソッドに渡す引数が-1で固定であるため、フキダシアイコンはプレイヤーキャラクターにしか出せません。
指定のイベントに出したい場合は、イベントIDを渡す必要があります。

そもそも、これだけであればイベントコマンドの「フキダシアイコンの表示」を使うほうが良いですが、なぜスクリプトから行いたいのかは気になります。
(変数の値に応じたフキダシを出したい、とかでしょうか)

更に細かいことを言うと、カプセル化を無視してクラス外部から_で始まるシンボルを参照・更新してたり、
Game_MessageクラスインスタンスからGame_Interpreterクラスインスタンスへの操作を行っているので、あまり行儀の良いコードではありません。

とりあえず動かすだけで良ければ、ここまでで大丈夫です。

2. プラグインコマンド化する

書いたコードをどのように使うのかわからないので、必ずしもこちらのほうが良いとは言い切れませんが、場合によってはこちらのほうがゲーム開発は楽になるかもしれません。
(基本的に、イベントコマンドのスクリプトはできるだけ書かないほうがメンテナンスしやすいです。必要最小限に留めることを推奨します)

さて、$gameMessage.showは引数に実行主体であるGame_Interpreterクラスのインスタンスを渡す必要がありました。
スクリプトに $gameMessage.show(this, '会話内容'); と書く必要がありましたが、これだけであればプラグインコマンドでも実現可能です。
同じことをするプラグインコマンド ShowMessage を定義してみます。
ついでに、プレイヤーに完了までウェイトするフキダシを出すプラグインコマンド ShowBalloonOnPlayer も書いてみます。

https://gist.github.com/elleonard/5afe0 ... 748c716327

以下のようにプラグインコマンドが実行できるようになりました。

ShowMessage 会話内容
ShowBalloonOnPlayer びっくり

イベントコマンドで毎度スクリプトを書くよりは楽だと思いますが、会話内容やフキダシアイコンの指定に変数を使う場合はこのままでは対応できません。

Re: Game_Messageからフキダシアイコン表示を行う方法

Posted: 2022年10月17日(月) 22:18
by kyoro
Dark様

ご返信ありがとうございます。再びお世話になります。

コード: 全て選択

Game_Message.prototype.show = function (interpreter, message) {
  this.newPage();
  this.add($gameVariables.value(19));
  this.add(`「${message}」`);
  interpreter.setWaitMode('message');
};
1番のクラス関係について、大変勉強になりました。上記のコードにおいて、
interpreter……Game_Interpreterのクラスインスタンス、this……Game_Messageのクラスインスタンス的なモノという認識でよろしいのでしょうか?
私のコードが使用できなかったのは、Game_interpreterのメソッドを、this(∈Game_Message)で呼び出していたから失敗していたのかなと思いました。

コード: 全て選択

Game_Message.prototype.talk = function (interpreter, message) {
  if (message === '!びっくり') {
    const balloonId = 1;
    interpreter._character = interpreter.character(-1);
    if (interpreter._character) {
      interpreter._character.requestBalloon(balloonId);
      interpreter.setWaitMode('balloon');
    }
  } else {
    this.show(interpreter, message);
  }
};
こちらのコードを使わせていただいたのですが、スクリプトに

コード: 全て選択

$gameMessage.talk(this, 'あいうえお' )
$gameMessage.talk(this, 'びっくり' )
$gameMessage.talk(this, 'かきくけこ' )
と打つと、文章が表示される裏でビックリマークが出続けてしまいます。試しに、 this.show(interpreter, message);の最後にinterpreter.setWaitMode('message');と打ち込んでみたのですが、解決しません。
あいうえお をすすめるまでフキダシアイコンが表示されないようにするにはどうすればよいでしょう?

そもそも、これだけであればイベントコマンドの「フキダシアイコンの表示」を使うほうが良いですが、なぜスクリプトから行いたいのかは気になります。
(変数の値に応じたフキダシを出したい、とかでしょうか)
私のゲーム制作方法が関係しております。
イベントシーンを作成する時、私はその場で一つ一つ台詞を打ち込むのではなく、予め一連の会話内容を作ります。いちいち打ち込む形だと、手間がかかりますし、頭に浮かんでいた会話の流れを切ってしまうことがあるからです。
具体的に言うと、ExcelのA〇に台詞を打ち込み、右隣のセル(B〇)に 以下の様に打ち込みます。
= "$gameMessage.talk('"&A〇&"' , this)")
そして、ツクールMV→スクリプトに、一連のセリフをtalk関数の形に書いたB列をコピペする手法をとっています。また、フキダシアイコンもRPGにおいては重要な感情表現の1つなので、Excel上でまとめて書いてしまいたいことも多いので、今回のような質問をした次第です。

そうした理由から、複数行を打ち込めないプラグインコマンドではなくスクリプトで実現しています。

Re: Game_Messageからフキダシアイコン表示を行う方法

Posted: 2022年10月18日(火) 04:51
by Plasma Dark
私のコードが使用できなかったのは、Game_interpreterのメソッドを、this(∈Game_Message)で呼び出していたから失敗していたのかなと思いました。
∈の演算子が適切かどうかというと難しいですが、概ねそのとおりです。
文章が表示される裏でビックリマークが出続けてしまいます。
ツクールで実装されているウェイトは、イベントコマンド同士の間に挟むウェイトです。
したがって、イベントコマンドのスクリプトひとつの中でウェイトまで含めた複数のイベントコマンドの実行の再現は、Game_Interpreterのイベント実行の仕組みそのものに手を加えない限りできません。

以下の記事の返信の中で、プラグインコマンドの処理の中でウェイトをはさみながら複数の処理を逐次実行するようなプラグインのサンプルを書いていますが、プロジェクト次第では問題が起こりうるものなので、利用するにしてもコードを読んで理解した上で判断してください。
viewtopic.php?f=23&t=12798
ツクールMV→スクリプトに、一連のセリフをtalk関数の形に書いたB列をコピペする手法をとっています。
外部ツールに書き出したイベントの流れをMVエディタに直接コピー&ペーストしたいのですね。
確か、ツクールMV/MZではクリップボードに特殊な形式を用いていたはずなので、
誰かがそれを再現するようなツールを作っていないかと探してみましたが、満足に動くものはなさそうでした。

https://github.com/folt-a/rmmz-evcocco
日本語ですが、作りかけで放置されているように見えます。
electron製で比較的平易なjsで書かれているため、参考にはしやすそうです。

https://tamschi.itch.io/clipboard-helper-for-rpg-maker
海外製で、有料でライセンスを売っているようです。
リリースは今年の3月と比較的最近のようですが、実際に使ってみたという話を全く聞かないので、手を出すなら人柱になる覚悟が必要そうです。

rmmz-evcoccoは今回の用途においてはかなり可能性が感じられるので動くようになってほしいものですが……。

あるいは、いっそCSVを直接読み込んでしまえるExternMessage.jsを利用するのも一つの手だと思います。
https://forum.tkool.jp/index.php?thread ... 0%91.4006/

Re: Game_Messageからフキダシアイコン表示を行う方法

Posted: 2022年10月20日(木) 00:39
by kyoro
Plasma Dark様

なるほど、スクリプト単位でウェイトが挟まれるのですね。勉強になります。
既に色々な外部ツールを用いた文章打ち込みの方法があるとは知りませんでした。わざわざお調べ頂きありがとうございます。最後に挙げて下さったExternMessage.jsなどはとても使いやすそうに思いました。

私事ですが、仕事がひと段落しましたらじっくりと触ろうと思います。いつもありがとうございます。