【解決済み】Scene_Base を継承した独自の戦闘シーンでのコモンイベント呼び出し

返信する
アクエリス
記事: 3
登録日時: 2025年6月12日(木) 10:04

【解決済み】Scene_Base を継承した独自の戦闘シーンでのコモンイベント呼び出し

投稿記事 by アクエリス »

はじめてこちらに質問させていただきます。

https://raw.githubusercontent.com/munok ... ns/master/
上記のMV用プラグインに関する質問です。
MZで使えるようにこちらで修正し、正常に稼働しておりますが、
戦闘中にコモンイベントを挟みたいと思い、様々試したものの実現できませんでした。

基本的にコモンイベントは、 Scene_Map か Scene_Battle が動いている時だけ
$gameMap.update() や BattleManager.update() 内で Interpreter が実行されるため
Scene_Base を継承しているScene_CardBattleでは、マップ用のInterpreter が更新されないかと思います。

Scene_CardBattle にインタプリタを持たせればよいと思い、以下のように定義しました。

コード: 全て選択

Scene_CardBattle.prototype.create = function() {
  Scene_Base.prototype.create.call(this);
  this.createWindowLayer();
  if (typeof this.createDisplayObjects === "function") {
    this.createDisplayObjects();
  } else {
    if (typeof this.createCardField === "function") this.createCardField();
    if (typeof this.createWindow === "function") this.createWindow();
  }
  this._ceInterpreter = new Game_Interpreter();
  this.createMessageWindow();
};

Scene_CardBattle.prototype.update = function() {
  this.updateMain();

  // ↓ここで毎フレーム interpreter を動かす
  if (this._ceInterpreter) {
    if (this._ceInterpreter.isRunning()) {
      this._ceInterpreter.update();
    } else if ($gameTemp.isCommonEventReserved()) {
      const ev = $gameTemp.retrieveCommonEvent();
      if (ev && ev.list) this._ceInterpreter.setup(ev.list);
    }
  }
  Scene_Base.prototype.update.call(this);
};

Scene_CardBattle.prototype.updateMain = function() {
  var active = this.isActive();
  $gameCardBattle.update(active);
};

しかしコモンイベントは戦闘終了後にしか起爆せず、予約止まりとなります。

以下のように、一旦戦闘処理を止めて実行しようとしましたが、
処理が止まったまま、コモンイベントも実行されませんでした。

コード: 全て選択

Scene_CardBattle.prototype.update = function() {

  // ① Interpreter が動いているなら それだけ更新して return
  if (this._ceInterpreter.isRunning()) {
    this._ceInterpreter.update();           // 共通イベントを 1 フレーム処理
    Scene_Base.prototype.update.call(this); // 画面描画だけ
    return;                                 // ★ バトル更新はスキップ
  }

  // ② 新しく予約が入っていたらセットアップして return
  if ($gameTemp.isCommonEventReserved()) {
    const ev = $gameTemp.retrieveCommonEvent();
    if (ev && ev.list) this._ceInterpreter.setup(ev.list);
    Scene_Base.prototype.update.call(this);
    return;                                 // ★ ここもスキップ
  }

  // ③ 何も無いときだけ通常のバトル進行
  this.updateMain();
  Scene_Base.prototype.update.call(this);
};



実行したい箇所は以下の部分です。

コード: 全て選択

	Game_CardBattle.prototype.updateAttackPhase = function() {
		var attacker = this.attackerDeck();
		var target = this.targetDeck();
		var animationId = attacker.card().attackAnimation();
		target.gainHp(-this._damage);
		if (this._turn) {
$gameTemp.reserveCommonEvent(1);  //ここ
			this.addMessage(2, animationId || TMPlugin.Card.AnimationAttack);
		} else {
$gameTemp.reserveCommonEvent(2); //ここ
			this.addMessage(1, animationId || TMPlugin.Card.AnimationEnemyAttack);
		}
		this.addMessage(0, target.card().name() + ' に ' + this._damage + ' ダメージ');
		this.addMessage(4, 0);
		for (;;) {
			var attackerLastHp = attacker.hp;
			var targetLastHp = target.hp;
			this.checkSkill(attacker, target, true);
			this.checkSkill(target, attacker, false);
			if (attackerLastHp === attacker.hp && targetLastHp === target.hp) break;
		}
		this.addMessage(4, 0);
		this._phase += 1;
	};

ツクールMZの処理構造にお詳しい方のご助言をいただけますと幸いです。
最後に編集したユーザー アクエリス [ 2025年6月12日(木) 13:26 ], 累計 4 回
アバター
Plasma Dark
記事: 736
登録日時: 2020年2月08日(土) 02:29
連絡する:

Re: Scene_Base を継承した独自の戦闘シーンでのコモンイベント呼び出し

投稿記事 by Plasma Dark »

ぱっと見動きそうなものですが、どうやってコモンイベントが起動していないと判断したのか、気になります。

文章の表示やピクチャの表示等、シーンに特定の描画に関する仕組みがないと動かないイベントコマンドもあります。
例えば文章の表示は、インタプリタでは$gameMessageオブジェクトを操作するだけで、実際にメッセージを描画するのはシーン側の責務になっています。(詳細はScene_Messageを参照してください)

変数の操作であれば、シーンに依存せずに処理できます。
コモンイベントの内容を変数の操作だけにして試してみていただけると、実際にはScene_CardBattle内でも処理できていることがわかるかもしれません。
アクエリス
記事: 3
登録日時: 2025年6月12日(木) 10:04

Re: Scene_Base を継承した独自の戦闘シーンでのコモンイベント呼び出し

投稿記事 by アクエリス »

早速ご返信いただき、大変感謝申し上げます。

まさにご指摘のとおり、[文章の表示]をコモンイベントの最初に置いておりました。
console.logやピクチャの表示といった処理を手前に置いたところ、しっかり処理されており、コモンイベントが起爆できていることが確認できました。ありがとうございます。

要するに、
1, Game_Message が「表示待ち」状態になる
2, Scene 側にある Window_Message が draw / 入力待ち / 閉じる
3, Game_Message.isBusy() が false になった瞬間に Interpreter 再開
という3段階が必要で、今の Scene_CardBattle には 2 の窓がないため、
1 → 3 に進めず永久待ち=フリーズ、というわけですね。

以下のようにしたところ、正常に機能しました。

コード: 全て選択

  const _create = Scene_CardBattle.prototype.create;
  Scene_CardBattle.prototype.create = function () {
    _create.call(this);
    this._createRpgMessageWindows();
  };

  Scene_CardBattle.prototype._createRpgMessageWindows = function () {

    const msgRect = new Rectangle(
      0, 0,
      Graphics.boxWidth,
      this.calcWindowHeight(4, false) + 8
    );
    this._messageWindow = new Window_Message(msgRect);
    this.addWindow(this._messageWindow);

    const goldRect = new Rectangle(0, 0, 0, 0); 
    this._goldWindow = new Window_Gold(goldRect);
    this._goldWindow.openness = 0;
    this.addWindow(this._goldWindow);

    const scrollRect = new Rectangle(0, 0, 0, 0);
    this._scrollTextWindow = new Window_ScrollText(scrollRect);
    this.addWindow(this._scrollTextWindow);

    this._nameBoxWindow     = new Window_NameBox();
    this._choiceListWindow  = new Window_ChoiceList();
    this._numberInputWindow = new Window_NumberInput();
    this._eventItemWindow   = new Window_EventItem(
      new Rectangle(0, 0, Graphics.boxWidth,
                    this.calcWindowHeight(4, true))
    );
    [
      this._nameBoxWindow,
      this._choiceListWindow,
      this._numberInputWindow,
      this._eventItemWindow
    ].forEach(w => this.addWindow(w));

    const m = this._messageWindow;
    m.setGoldWindow(this._goldWindow);
    m.setNameBoxWindow(this._nameBoxWindow);
    m.setChoiceListWindow(this._choiceListWindow);
    m.setNumberInputWindow(this._numberInputWindow);
    m.setEventItemWindow(this._eventItemWindow);

    this._nameBoxWindow.setMessageWindow(m);
    this._choiceListWindow.setMessageWindow(m);
    this._numberInputWindow.setMessageWindow(m);
    this._eventItemWindow.setMessageWindow(m);
  };
大変助かりました。
今後ともよろしくお願いいたします。
アバター
Plasma Dark
記事: 736
登録日時: 2020年2月08日(土) 02:29
連絡する:

Re: 【解決済み】Scene_Base を継承した独自の戦闘シーンでのコモンイベント呼び出し

投稿記事 by Plasma Dark »

解決されたようで何よりです。

Scene_CardBattleにはスコープの関係でそのままでは利用できないと思いますが、指定シーンにメッセージウィンドウを表示するプラグインを公開しているので、類似した問題で困っている方にはこちらをおすすめしておきます。
https://github.com/elleonard/DarkPlasma ... geMixIn.js
アクエリス
記事: 3
登録日時: 2025年6月12日(木) 10:04

Re: 【解決済み】Scene_Base を継承した独自の戦闘シーンでのコモンイベント呼び出し

投稿記事 by アクエリス »

素晴らしいプラグインですね。

これがあれば、Scene_Shop や Scene_Menu といったあらゆるシーンで $gameMessage.add() が使えそうです。
競合対策も非常に丁寧にされていますし、コードも綺麗だと感じました。

有難く活用させていただきます。
様々手厚くご対応くださり、感謝申し上げます。
返信する

“MZ:質問”に戻る