【解決済み】イベントでタイルを追加・変更したい。

sou_sitaku

ユーザー
イベントでタイルを追加・変更したりする方法をご存じでしょうか?
何をやりたいかというと、下図の左の状態のキャラクターを、イベント後、
右のように血だまりタイルに倒れさせる、というような演出を考えています。

1642080328292.png

最初は血だまり画像もイベントで表現しようとしました。

キャラクターの隣に「通常キャラの下」に設定した透明イベントを配置する。
 ↓
キャラクターを倒すイベント
 ↓
透明イベントをキャラクターと同タイルに移動させる。
 ↓
スイッチON
 ↓
スイッチON条件のEVページで血だまり画像を表示させる。

これで一応うまくいくんですが、このスレッドでも引っかかっている通り、
セーブ&ロードやマップの移動によって、血だまりが元居た位置に戻ってしまうんですよ……。
イベントは同じ位置に重ねられないし、だったらイベントでタイルを変えてしまうしかないと思っています。
(もしかしてそれができてもセーブ&ロードで元に戻っちゃいますかね?)

「タイルセットの変更」はちょっと違うし、なんとかリファレンスを読んでTilemapクラスにあるaddTileというのに目をつけてみたのですが、ファンクションじゃねーよみたいなエラーが出てうまくいかないんです。

いいお知恵があれば教えてください。
よろしくお願いします。
 
タイルマップの直接書き換え……これ、僕がサンプルゲーム(ルイーゼと秘密の地下室)作った時に
ダンジョンギミックとして、多用していました。

ずばり、これでいけます。
JavaScript:
  const setDataMap = (x, y, z, tileId) => {
    // see Game_Map.prototype.tileId
    const width = $dataMap.width;
    const height = $dataMap.height;
    $dataMap.data[(z * height + y) * width + x] = tileId;
  };
この関数は、(x, y)のレイヤ(z: 最下層から順に 0~3) のタイルを、
tileIdのタイルに置き換えてしまいます。

ただし注意点があって、一度そのマップでセーブして、
新たにロードした時は、書き換えたマップタイルは、全てリセットされます。

前述のゲームでは、それに関する対策も行っています。
具体的には、このゲームのフォルダにある、BrittleFloor.js (2度乗ると崩れる脆い床を作る)が
参考になると思います。

また、若干上級者向けですが、ProcessAllSameTileID.js なんかも、マップを書き換えており、
セーブ、ロードした時も、きちんと書き換えたタイルを反映しています。

以上、参考になれば幸いです。
 
最後に編集:

sou_sitaku

ユーザー
タイルマップの直接書き換え……これ、僕がサンプルゲーム(ルイーゼと秘密の地下室)作った時に
ダンジョンギミックとして、多用していました。

ずばり、これでいけます。
JavaScript:
  const setDataMap = (x, y, z, tileId) => {
    // see Game_Map.prototype.tileId
    const width = $dataMap.width;
    const height = $dataMap.height;
    $dataMap.data[(z * height + y) * width + x] = tileId;
  };
この関数は、(x, y)のレイヤ(z: 最下層から順に 0~3) のタイルを、
tileIdのタイルに置き換えてしまいます。

ただし注意点があって、一度そのマップでセーブして、
新たにロードした時は、書き換えたマップタイルは、全てリセットされます。

前述のゲームでは、それに関する対策も行っています。
具体的には、このゲームのフォルダにある、BrittleFloor.js (2度乗ると崩れる脆い床を作る)が
参考になると思います。

また、若干上級者向けですが、ProcessAllSameTileID.js なんかも、マップを書き換えており、
セーブ、ロードした時も、きちんと書き換えたタイルを反映しています。

以上、参考になれば幸いです。
ありがとうございます。
途中経過ですが、

$dataMap.data[(z * height + y) * width + x] = tileId;

の部分だけ使わせていただき、変数に値を代入してスクリプトに書き込んだところ、タイルをきちんと変化させるところまでいけました。
あとはセーブ&ロード対策です。
 
あとはセーブ&ロード対策です。
とのことですので、前述の関数を定義しているプラグインを添付します。
(ルイーゼと秘密の地下室のプラグインフォルダにあるのと同じもの)
このプラグインでは、「$dataMapを変更している場合、ロード時にマップの再読み込みを行わない
という処理で、セーブ&ロード対策をしています。

解読のためにプラグインの内部処理の簡単な解説を。

JavaScript:
  //
  // when load data, call process drawing routine
  //
  const _Scene_Map_onMapLoaded = Scene_Map.prototype.onMapLoaded;
  Scene_Map.prototype.onMapLoaded = function() {
    _Scene_Map_onMapLoaded.call(this);
    $gameMap._setBrittleFloor();
  };

  // NOTE: this function prevents crack resets when load after project update.
  // When you change the map with brittle floor, map is not modified,
  // To refrect modification, you need to once go to another map
  // and return to the map.
  const _Scene_Load_reloadMapIfUpdated =
    Scene_Load.prototype.reloadMapIfUpdated;
  Scene_Load.prototype.reloadMapIfUpdated = function() {
    if ($gameMap._needsSetBrittleFloor()) {
      return;
   }
    _Scene_Load_reloadMapIfUpdated.call(this);
  };

要するに一言で言うと、Scene_Load.prototype.reloadMapIfUpdatedで、
「$dataMapを変更している場合、マップの再ロードは行わなわない」こと、
Scene_Map.prototype.onMapLoadedの際、$dataMapを書き換えること。
これが一番重要な部分です。

このため、どの座標でタイルが変更されたかを保存する必要があります。
このプラグインでは、ハッシュ形式で保存しています。

JavaScript:
  const aToNum = (x, y) => (y << 12) + x;
  const numToX = num => num & 0xfff;
  const numToY = num => num >> 12;

  Game_Map.prototype._setCracks = function () {
    if (!this._brittleFloors) {
      return;
    }
    const z = 1; // layer 2
    const coords = Object.keys(this._brittleFloors);
    for (const coord of coords) {
      const x = numToX(coord);
      const y = numToY(coord);
      if (this._brittleFloors[aToNum(x, y)]) {
        setDataMap(x, y, z, this._crackTileId);
      }
    }
  };

Game_Map.prototype._setBrittleFloor = function () {
    if (this._needsSetBrittleFloor()) {
      this._setCracks();
    } else {
      this._initBrittleFloors();
    }
  };
このプラグインでは、$gameMap._brittleFloors というハッシュに保存しています。
効率化のため、(x, y)を一つの数字に置き換えています(最初の3行)。

これを参考にして、セーブ&ロード対策をしてみてください。
グッドラック。
 

Attachments

  • BrittleFloor.zip
    4.2 KB · 閲覧: 0

sou_sitaku

ユーザー
とのことですので、前述の関数を定義しているプラグインを添付します。
(ルイーゼと秘密の地下室のプラグインフォルダにあるのと同じもの)
このプラグインでは、「$dataMapを変更している場合、ロード時にマップの再読み込みを行わない
という処理で、セーブ&ロード対策をしています。

解読のためにプラグインの内部処理の簡単な解説を。

(中略)
このプラグインでは、$gameMap._brittleFloors というハッシュに保存しています。
効率化のため、(x, y)を一つの数字に置き換えています(最初の3行)。

これを参考にして、セーブ&ロード対策をしてみてください。
グッドラック。

JavaScriptちょっとしかわからない勢で難航しています……。
とりあえず、参考に添付していただいたプラグインを使ってみようと適用してみたんですが、
プラグインコマンドを設定して、テストプレイでその上を歩き回っても何も起こらないんですよね……。

これ、どう使うものなんでしょうか……?

一応説明通り、
ダミーイベント(イベントID:1)→左上のイベント。1ページ目にひび割れ画像、2ページ目に穴画像
実際のイベント(イベントID:2)→右上のイベント。

パラメータなどはデフォルトのままです。

ちなみに、このプラグインを使っているマップは、「ルイーゼと秘密の地下室」のどのマップで使われていますか?

1642250069737.png
 

sou_sitaku

ユーザー
力技でなら解決できるかも、と思ったけどしなかった。

①マップタイルを変える → スイッチをつける。
②自動実行イベントを仕掛けて、スイッチが付いてたらもう一度マップタイルの変更を行う。→イベントの一時消去

マップの切り替えでならちゃんと読み込んでくれるんですが、セーブ&ロードではいかんですね……。なんか行けちゃうこともあるっぽいんですけど。
それに$dataMap.data[(z * height + y) * width + x] = tileId;だけだとメニューの開閉だけで、切り替えたマップタイルが元に戻ってしまうのか……

なんか神無月サスケ氏のプラグインで、いろいろやってる意味がそこにあるってことなのでしょうね……。

まー本当の力技は、「血だまりの上に倒れたキャラクター」の画像を用意して、切り替えることなんですけどね……。
 
最後に編集:
どうも、最初にお詫びを。
この崩れた床のプラグイン、メニュー開閉やセーブ&ロードでは機能するのですが、
マップを切り替えるとリセットされるように組んでいた模様です。

このプラグインでのタイルの設定方法は、プラグインのヘルプを観ながらお願いします。

なお、「ルイーゼと~」でこれが使われているマップは、
「氷冷の研究室・入口」配下にある多くのマップで使われています。
また、ダンジョンギミックとして使われているのは、
「地下巣窟・魔方陣の間」の配下にある「脆い床パズル」です。
ダウンロードしてお確かめ下さい。

本当はもう少しアドバイスしてあげたかったんですが、
昨日あたりから仕事が複数発生して、今は時間がないので。
 

sou_sitaku

ユーザー
どうも、最初にお詫びを。
この崩れた床のプラグイン、メニュー開閉やセーブ&ロードでは機能するのですが、
マップを切り替えるとリセットされるように組んでいた模様です。

このプラグインでのタイルの設定方法は、プラグインのヘルプを観ながらお願いします。

なお、「ルイーゼと~」でこれが使われているマップは、
「氷冷の研究室・入口」配下にある多くのマップで使われています。
また、ダンジョンギミックとして使われているのは、
「地下巣窟・魔方陣の間」の配下にある「脆い床パズル」です。
ダウンロードしてお確かめ下さい。

本当はもう少しアドバイスしてあげたかったんですが、
昨日あたりから仕事が複数発生して、今は時間がないので。

いやいやいや。お忙しいところありがとうございます!
「ルイーゼと~」のほうを一通りプレイしてみて、いろいろ参考にしてみたいと思います。
第3章までプレイしたのですが、ダンジョンのパズルが楽しいゲームですね。
 
わざわざプレイして下さってありがとうございます。
てっきり、自分の必要な部分のマップでの設定をチェックするだけかと思っていたので。

「ルイーゼと~」はMZサンプルなので「MZではこんなことも出来るぞ」というアピール色が強いため
謎解き多いですが、気に入ってくださったようで幸いです。

ちょっと今回の「マップを切り替えてもタイル変更保持」は難しくなってきたので、
他の方が助け舟を出してくれたら助かります。
 
ああ、それでよかったのですか。
確かにプロジェクト更新すると、イベントの位置は元に戻りますからね。
僕は、ゲームを配布するときは、バージョンアップに備えて、
「プロジェクトが更新された時マップを再読み込みする」機能を、
コアスクリプトから、行わないようにして、イベント位置を維持しています。
 

sou_sitaku

ユーザー
ああ、それでよかったのですか。
確かにプロジェクト更新すると、イベントの位置は元に戻りますからね。
僕は、ゲームを配布するときは、バージョンアップに備えて、
「プロジェクトが更新された時マップを再読み込みする」機能を、
コアスクリプトから、行わないようにして、イベント位置を維持しています。

もともとマップタイルの変更に走った理由は、イベントの位置情報がリセットされてしまうところからだったので……。

神無月さんからご紹介いただいたプラグインだと、マップタイルの変更内容をセーブするところまでできているようだったのですが、自分の理解度ではそこまでできなかったので「スイッチがONになっていればマップのロード時に変更し直す」という考え方に変更しました。そしてそこまではできるようになりました。

ただ、即座に元に戻したいときの処理も考えておくべきだと思ったのですが、このスレッドにある通り、スイッチをOFFにしたあと、マップを再読み込みするということができなかったのですよね……。(OFFにした後、メニューの開閉をしたり、マップの切り替えを行うと処理が反映される)
 

sou_sitaku

ユーザー
このスレッドのタイトル的な意味でも完全解決できたと思います。

マップタイルを変更し、その後元に戻す処理ができるようになり、プラグインが一通り完成しました。

神無月サスケ氏からご提示いただいたプラグイン「BrittleFloors.js」を元に作成した「ChangeMapTiles.js」というプラグインを置いときます。

パラメータとして、マップID、xy座標、レイヤー、マップタイルIDと対応するスイッチIDを設定しておき、そのスイッチがONになってたらOnMapLoad時にタイルを変更します。

また、プラグインコマンドから即座に変更を反映することもできます。
プラグインコマンドから変更を解除することもできます。変更時に、変更前のタイルマップIDを $dataMap に保存しておき、元のタイルマップを上書きする形で変更前のタイルに戻します。

……ただし、プラグインコマンドから実行した場合、変更が反映されるまでにちょっとだけタイムラグを感じますね。ちょっとだけ……。
 

Attachments

  • ChangeMapTile.js
    14.2 KB · 閲覧: 4
トップ