【解決済み】指定したマップのイベントの個数を取得したい

アバター
たくろう
記事: 22
登録日時: 2020年7月01日(水) 18:18
連絡を取る:

【解決済み】指定したマップのイベントの個数を取得したい

投稿記事by たくろう » 2020年8月06日(木) 16:40

こんにちは! いつも大変お世話になっております!

プラグインの勉強を兼ねて、セルフスイッチを操作するプラグインを作成しようとしています。
(何度目の車輪の再開発かわかりませんが、ご容赦を……)
(プラグインいじりが楽しくて全然ゲーム制作が進まない…………)

*===**===**===*
◆やろうとしてること
指定したマップのセルフスイッチの状態をコンソールに出力する処理を準備しようとしています。
そこで、セルフスイッチの状態を取得するスクリプト
 $gameSelfSwitches.value([mapId, eventId, "A");
を使って、対象マップのイベント個数だけループしよう、と考えました。

eventId の部分が 1,2,3,4……と変わってループするイメージです。
今いるマップは取得できました。
SelfSwitchController_質問用.png
SelfSwitchController_質問用.png (3.95 KiB) 閲覧数: 4354 回


◆困っていること
viewtopic.php?t=5062
こちらの記事から、今いるマップ以外はロードされていないということを知りました。
記載いただいている内容を参考に、別の変数に情報をロードしようと思ったのですが、
ロード反映の方法が分からず、エラーが発生し行き詰まっております。

◆対象のコード

対象の処理部分のみ抜粋

コード: 全て選択

// プラグインコマンドで呼び出された関数
function SelfSwitchControllerStatus(mapId){

  // セルフスイッチリスト
  var selfsws = ["A", "B", "C", "D"];
  // 各セルフスイッチの状態をいれる配列
  var selfswstatusarray = [];

// ################
// 別マップの情報を$dataSSCにロードしようとしている
var filename = 'Map%1.json'.format(mapId.padZero(3));

ResourceHandler.createLoader('data/' + filename, DataManager.loadDataFile.bind(this, '$dataSSC', filename));
DataManager.loadDataFile('$dataSSC', filename);

// いろいろ反映しようとしたが、方法がわからず……
// DataManager.onLoad('$dataSSC');
// DataManager.isMapLoaded();
// DataManager.isDatabaseLoaded();
// DataManager.loadMapData();
// DataManager.onLoad();
// DataManager.loadMapData(mapId);
// ResourceHandler.retry();

// ################

  for (var eventId = 1; eventId < $dataSSC.events.length; eventId++) { // ★☆ここでエラーが発生する☆★
    // セルフスイッチ ABCD の分だけループ
    for (var i = 0; i < selfsws.length; i++) {
      // 対象のセルフスイッチの状態を確認する
      if ($gameSelfSwitches.value([mapId, eventId, selfsws[i]])){
        selfswstatusarray.push("ON")
      } else {
        selfswstatusarray.push("__")
      }
    }
    // コンソールに出力
    console.log(eventId,selfswstatusarray)
    // セルフスイッチ状態管理の配列をリセットしておく
    selfswstatusarray=[];
  }
}



上記コードで発生するエラー

コード: 全て選択

rpg_managers.js:1949 TypeError: Cannot read property 'events' of null
    at SelfSwitchControllerStatus (SelfSwitchController.js:440)
    at SelfSwitchControllerShow (SelfSwitchController.js:399)
    at Game_Interpreter.pluginCommandSelfSwitchController (SelfSwitchController.js:177)
    at Game_Interpreter.pluginCommand (SelfSwitchController.js:159)
    at Game_Interpreter.command356 (rpg_objects.js:10508)
    at Game_Interpreter.executeCommand (rpg_objects.js:8930)
    at Game_Interpreter.update (rpg_objects.js:8838)
    at Game_Map.updateInterpreter (rpg_objects.js:6115)
    at Game_Map.update (rpg_objects.js:6022)
    at Scene_Map.updateMain (rpg_scenes.js:608)

※SelfSwitchController.jsは今回作成しているプラグインです。

マップ情報をロードする前に参照しようとして、中身が空です、といわれているという風に解釈しました。
エラー後にコンソールに直接 >$dataSSC.evnets を入力すると、情報が取れていることが確認できました。

コード: 全て選択

TypeError: Cannot read property 'events' of null
    at SelfSwitchControllerStatus (SelfSwitchController.js:349)
    at SelfSwitchControllerShow (SelfSwitchController.js:294)
(snip)

$dataSSC.events
(17) [null, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]



◆解決したいこと

処理のタイミングで指定したマップの情報をロードして、イベントの個数を取得したいです。
「起動タイミングやマップ移動タイミングで全マップをロードしておく」ことも可能な気もしますが、
「マップデータが重いから一つずつロードしている」と参考ページに書かれていたため、
処理のタイミングで取得できたらそこまで重くならないのではないか、という予想です。
大変お手数ではございますが、ご教授いただけると幸いです。

もしくは、まったく別の「こんなアプローチもあるよ!」というのもご教授いただけると嬉しいです!
(直接データパスを指定してgrep的に検索する、というのも検討しましたがこちらもさっぱり見当がつきませんでした…)

ただ、イベントコマンドと併用して(一瞬別マップに移動する)みたいな解決も出来ると思いますが、
今回はプラグインの練習ということで、プラグイン内で解決を目指しています!

長くなってしまいました……。
長文読んでいただきありがとうございました!
お手数ではございますが、よろしくお願いします。

動かないプラグインを添付しておきます……
添付ファイル
SelfSwitchController.js
(8.83 KiB) ダウンロード数: 5 回
最後に編集したユーザー たくろう on 2020年8月09日(日) 08:06 [ 編集 1 回目 ]

奏ねこま
記事: 702
登録日時: 2016年1月20日(水) 20:04

Re: 指定したマップのイベントの個数を取得したい

投稿記事by 奏ねこま » 2020年8月06日(木) 20:00

Object.keys($gameSelfSwitches._data)

これでセルフスイッチに保存されているキーの一覧が取得できるので
マップデータをわざわざ読み込む必要はないと思います。
アバター
たくろう
記事: 22
登録日時: 2020年7月01日(水) 18:18
連絡を取る:

Re: 指定したマップのイベントの個数を取得したい

投稿記事by たくろう » 2020年8月07日(金) 06:21

奏ねこま さん、こんにちは!
いつも色々教えていただき大変お世話になっています!
とても勉強になっています!

Object.keys($gameSelfSwitches._data)
これでセルフスイッチに保存されているキーの一覧が取得できる


ありがとうございます!
なるほど! そういう書き方があるのですね!

実際に動作を確認してみて、セルフスイッチがONになったリストが取得できました!!

コード: 全て選択

0:"1,2,A"
1:"1,2,D"
2:"1,2,B"
3:"3,2,A"
4:"3,1,A"
5:"3,4,A"
6:"3,4,C"


ご教示いただいた情報も活用させていただきたいと思うのですが、
ただ、今回プラグインでやりたいことは、セルフスイッチの状態を一覧で取得したく
「セルフスイッチABCD全部が OFF になっているイベントのときも表示させたい」と考えています。

大変お手数ではございますが、
引き続きご教示のほどお願いできればと思います。
アバター
剣崎 宗二
記事: 678
登録日時: 2016年11月12日(土) 20:36
連絡を取る:

Re: 指定したマップのイベントの個数を取得したい

投稿記事by 剣崎 宗二 » 2020年8月07日(金) 12:32

「どうしても他Mapのデータを読み込みたい」と言う前提で話を進めさせていただきます。
(これ自体、ご提示いただいた参考スレにある通り、私としてはあまりやりたくないやり方なのですが…)

ツクールMVのコアスクリプトに於いては、ファイルのローディングは殆どの場合「非同期」で行われております。
これは即ち、そのコマンド行が実行完了した後にファイルのロードが完了されている訳ではなく、「ロードが開始された時点で」もう次の行にコマンドが進んでしまうと言う事です。
なので、
マップ情報をロードする前に参照しようとして、中身が空です、といわれているという風に解釈しました。

この認識は半分正しく、ロード「完了」する前に参照しようとしている、と言う事です。
(余談ですが、画像系のプラグインで結構「一回目に表示する際に画像が表示されず、メニューを開きなおしたりマップを切り替えると正しく表示される」と言った類のバグ報告がございますが、それもほとんどの場合これが関係しております)


解の考え方としましては、そちらも言っている
「起動タイミングやマップ移動タイミングで全マップをロードしておく」ことも可能な気もしますが

が比較的簡単なのですが、この手を取りたくない場合は:

・実行中毎フレーム実行されている処理(一例としてGame_MapやGame_Interpreter等のupdate等。個人的にはGame_Interpreter.prototype.updateWaitModeあたりの調整でいけるかな…と思っておりますが)で、ロードが完了したか否か(=この場合$dataSSCにデータがあるかどうか)をチェックし、ロード完了した場合これを出力して、次のファイルのロードを始める

と言うのが現実的ではないかと思います。



「プラグインの勉強を兼ねて」と言う事なので、説明が長くなった上に解はヒントに留めましたが、一助となれば幸いです。
----
-出先に居る場合回答が未テスト状態である事が多い為、テストは重々にお願いいたします。
-基本自分や友人の問題解決は自分で1からプラグインを書いているので、「こういうプラグインはありますか」に対しては助けになれません。ご了承ください。
アバター
たくろう
記事: 22
登録日時: 2020年7月01日(水) 18:18
連絡を取る:

Re: 指定したマップのイベントの個数を取得したい

投稿記事by たくろう » 2020年8月09日(日) 08:06

剣崎さん、こんにちは!
いつも剣崎さんの投稿に大変お世話になっています!
お勧めではない手法にも付き合っていただき本当にありがとうございます!

*===*
ツクールMVのコアスクリプトに於いては、ファイルのローディングは殆どの場合「非同期」で行われております。

ロード「完了」する前に参照しようとしている、と言う事です。

なるほど!
だからエラーなのにコンソールでは確認できたのですね!

(余談ですが、画像系のプラグインで結構「一回目に表示する際に画像が表示されず、メニューを開きなおしたりマップを切り替えると正しく表示される」と言った類のバグ報告がございますが、それもほとんどの場合これが関係しております)

こちらも参考になります! 今度この状況に出くわしたら今回教えていただいた解決法を試してみたいですね。

・実行中毎フレーム実行されている処理(一例としてGame_MapやGame_Interpreter等のupdate等。個人的にはGame_Interpreter.prototype.updateWaitModeあたりの調整でいけるかな…と思っておりますが)で、ロードが完了したか否か(=この場合$dataSSCにデータがあるかどうか)をチェックし、ロード完了した場合これを出力して、次のファイルのロードを始める

なるほど! 解決法について承知しました!

*===*

本当は「出来ました!」というお返事をしたかったのですが、ご教授いただいた方法で試行錯誤中です!
もう少し時間かかりそうだったので先にお返事させていただきました!
実現できたら是非ご報告させてください!

このトピック自体は手法が分かったため【解決済み】とさせていただきます!
奏ねこまさん、剣崎さん、確認してくれた皆さん、ありがとうございました!
jp_asty
記事: 81
登録日時: 2019年11月12日(火) 15:34

Re: 【解決済み】指定したマップのイベントの個数を取得したい

投稿記事by jp_asty » 2020年8月10日(月) 00:22

たくろうさん

こんばんは。
奏ねこまさんも仰っている通り、セルフスイッチの状態はすべて$gameSelfSwitches._dataに入っています。

状態の一覧を取得したい場合は、マップID 1~999、イベントID 1~999、セルフスイッチA~Dに対して
$gameSelfSwitches.value で問い合わせれば良いのではないかと思うのですが、それでは駄目なのでしょうか。

蛇足とは思いましたが、個人的に気になっていた内容であったため返信させて頂きました。
宜しくお願いします。
---------------------------------------------------------------------------------------------
プラグイン置き場 : https://github.com/ste0/RPG-Maker-MV-Plugins
アバター
たくろう
記事: 22
登録日時: 2020年7月01日(水) 18:18
連絡を取る:

Re: 【解決済み】指定したマップのイベントの個数を取得したい

投稿記事by たくろう » 2020年8月10日(月) 09:32

jp_asty さん こんにちは!
いつも投稿いただいているプラグインを使用させていただいたり、中を見て作成方法など参考にさせていただいたりしています!
本投稿もご確認ありがとうございます!

奏ねこまさんも仰っている通り、セルフスイッチの状態はすべて$gameSelfSwitches._dataに入っています。
状態の一覧を取得したい場合は、マップID 1~999、イベントID 1~999、セルフスイッチA~Dに対して
$gameSelfSwitches.value で問い合わせれば良いのではないかと思うのですが、それでは駄目なのでしょうか。


なるほど! いただいた方法でOFFの状態も含めた一覧は取得できそうでした!

ただ、自分の認識違いだったら勉強不足で申し訳ないのですが、$gameSelfSwitches.value([99,100,'A']) という感じで取得できる値は
true か false のどちらかで、そのマップIDのマップがあるかどうか、そのイベントIDがあるかどうかまでは判断できないという認識です。
(そのマップやイベントが存在しない場合は false になる)

そのため、今回教えていただいた方法の場合、
「そのセルフスイッチがOFFになっている」のか「そもそも存在しないのか」がわからないのではないか、と思っています。
OFF の状態も含めた一覧表示をしようとすると、存在しない分も含め大量のOFF状態の表示が出るという認識です。

※「もしや存在しないマップの存在しないイベントに対して、セルフスイッチはセットできないのでは!?」と思って試したのですが、セットも出来てしまいました…
  セットできなければイベント自体の存在確認ができるなぁと思ったのですが……

*===*

今回の出力の感じは、下記をイメージしています。
例)マップが3つあり、それぞれイベントがマップ1には3つ、マップ2には1つ、マップ3には6つある。

コード: 全て選択

Map ID: 1
 1 (4) ["__", "__", "__", "__"]
 2 (4) ["ON", "ON", "__", "ON"]
 3 (4) ["__", "__", "__", "__"]
 Map ID: 2
 1 (4) ["__", "__", "__", "__"]
 Map ID: 3
 1 (4) ["__", "__", "__", "__"]
 2 (4) ["ON", "__", "__", "__"]
 3 (4) ["__", "__", "__", "__"]
 4 (4) ["__", "__", "__", "__"]
 5 (4) ["__", "ON", "__", "ON"]
 6 (4) ["ON", "ON", "ON", "__"]

これで、任意のマップの各イベントのセルフスイッチの状態を把握できればいいな、と思っています。

(余談:「これ、いります?」ってなりますよね……
 自分のイベントの作り方があまり良くないのかもしれないですが、
 「イベント1が○○まで進行したらイベント2のセルフスイッチA=ONして並列で動き始め、イベント2が▽▽になったら
 イベント3のセルフスイッチA=ONでさらに別のイベントが進行し出す」みたいに
 対象のセルフスイッチをONにすることで、動き出しを指定しています。イベントの進行がどこまで進んだか見れたら便利かもなぁというのがきっかけでした。
 上記の動きを実現するのに通常スイッチや変数を使うこともできるだろうな、と思っていますがプラグインで表示できたら楽しそうだな、
 と思ってしまったので、めちゃめちゃ時間を溶かして色々試行錯誤しています。
 今は教えていただいたロード完了待ちの処理を入れようとして、無限に待ち続けています笑

また長くなってしまいました……。
長文読んでいただきありがとうございました!
また問題解決のご助力ありがとうございました!
引き続き色々挑戦してみます!

(タイトルに【解決済み】を付けていますが、もし何かあれば引き続きご教示いただけると大変嬉しいです!)
jp_asty
記事: 81
登録日時: 2019年11月12日(火) 15:34

Re: 【解決済み】指定したマップのイベントの個数を取得したい

投稿記事by jp_asty » 2020年8月11日(火) 07:18

たくろうさん

こんにちは。

ただ、自分の認識違いだったら勉強不足で申し訳ないのですが、$gameSelfSwitches.value([99,100,'A']) という感じで取得できる値は
true か false のどちらかで、そのマップIDのマップがあるかどうか、そのイベントIDがあるかどうかまでは判断できないという認識です。
(そのマップやイベントが存在しない場合は false になる)

マップIDの存在判定は$dataMapInfosのIdあたりで確認できそうですが、イベントの存在判定はマップデータをロードしなければできないと思われます。

ご希望の要件を満たすにはやはり、全マップのロードなどの処理が必要になってくると思います。
剣崎さんも仰っていますが、私もこの方法はお勧めはできません。

ただ、どうしても試したいということであれば、XMLHttpRequestのonLoadに読み込み完了のコールバックを登録して、そのタイミングでセルフスイッチの中身を出力するようにすれば実装自体は可能ではあると思います。

XMLHttpRequestはデフォルトでは非同期読み込みですが、同期読み込みにするオプションもあるようです。
非同期の場合、読み込み完了のコールバックは読み込みが終了したものから順に処理され、読み込んだデータの中に自分のマップIDが含まれていないため、データの順序関係を保証することができません。

通常、web界隈でデータの同期読み込みは非推奨だと思いますが、今回の例の場合はデータの順序関係を保証する必要があるため同期読み込みにするというのもひとつの手だとは思います。

気になるのはやはりロード時間だと思います。256×256のマップにイベントを150置いて試してみたところ40ms程度かかりました。このイベント数でマップが最大数あった場合 40秒程度かかることになります。
このあたりが私が全マップロードをお勧めできない理由になります。

一応、試したコードを載せておきます。これはたくろうさんが上でアップいているプラグインのコードを部分的に書き換えたもので、対象メソッドを置き換えることで動作確認はとれると思います。エラー処理は一部割愛しています。

コード: 全て選択

function SelfSwitchControllerStatus(mapId){
  const filename = 'Map%1.json'.format(mapId.padZero(3));
  const xhr = new XMLHttpRequest();
  const url = 'data/' + filename;
  xhr.open('GET', url, false);//最後にfalseを指定すると同期読み込みになる。
  xhr.overrideMimeType('application/json');
  xhr.onload = function() {
    if (xhr.status < 400) {//200:ok 403:Forbidden 404:Not Found
      const data = JSON.parse(xhr.responseText);//responseTextに読み込んだデータが入っている。
      for (let i = 1; i < data.events.length; i++) {
        if(data.events[i] == null) continue;//イベントは削除されたりするため必ず存在する訳ではない。
        const eventId = data.events[i].id;
        const selfsws = ["A", "B", "C", "D"];
        const selfswstatusarray = [];
        for (var j = 0; j < selfsws.length; j++) {
          if ($gameSelfSwitches.value([mapId, eventId, selfsws[j]])){
            selfswstatusarray.push("ON")
          } else {
            selfswstatusarray.push("__")
          }
        }
        console.log(eventId,selfswstatusarray)
      }
    }
  };
  xhr.onerror = function() {
      DataManager._errorUrl = DataManager._errorUrl || url;
  };
  xhr.send();
}

追記:データの順序関係に関しては、onLoadのタイミングでファイル名から何番のマップデータかを判定できそうなので読み込みは非同期で問題なさそうでした。処理時間に関しては初回読み込み時にイベントIDのリストをキャッシュすることで2回め以降の呼び出しは高速ですが、以前として初回読み込み時は最大時間かかることになるのは変わりません。

参考(XMLHttpRequest)
https://ja.javascript.info/xmlhttprequest
---------------------------------------------------------------------------------------------
プラグイン置き場 : https://github.com/ste0/RPG-Maker-MV-Plugins
アバター
たくろう
記事: 22
登録日時: 2020年7月01日(水) 18:18
連絡を取る:

Re: 【解決済み】指定したマップのイベントの個数を取得したい

投稿記事by たくろう » 2020年8月13日(木) 08:52

jp_astyさん、こんにちは!
ご返答ありがとうございます!

マップIDの存在判定は$dataMapInfosのIdあたりで確認できそうですが、イベントの存在判定はマップデータをロードしなければできないと思われます。

やはり別マップのイベントはマップデータのロードが必要なのですね。

ご希望の要件を満たすにはやはり、全マップのロードなどの処理が必要になってくると思います。
剣崎さんも仰っていますが、私もこの方法はお勧めはできません。

やはり非推奨なのですね…

ただ、どうしても試したいということであれば、XMLHttpRequestのonLoadに読み込み完了のコールバックを登録して、そのタイミングでセルフスイッチの中身を出力するようにすれば実装自体は可能ではあると思います。
~~
通常、web界隈でデータの同期読み込みは非推奨だと思いますが、今回の例の場合はデータの順序関係を保証する必要があるため同期読み込みにするというのもひとつの手だとは思います。

お勧めではない処理にも付き合っていただき本当にありがとうございます!
解決の考え方について勉強になります!

気になるのはやはりロード時間だと思います。256×256のマップにイベントを150置いて試してみたところ40ms程度かかりました。このイベント数でマップが最大数あった場合 40秒程度かかることになります。
このあたりが私が全マップロードをお勧めできない理由になります。

詳細な検証まで!
確かに40秒も待てないですよね。自分だったらフリーズしたと判断してしまいそうです…!

一応、試したコードを載せておきます。~~

コードありがとうございます!
実際の設定も見させていただくと、実装を具体的にイメージできて勉強になります!

追記:データの順序関係に関しては~~

追記いただいた内容についてもありがとうございます!
やはり読み込みには相当時間がかかるということですね。

参考のXMLHttpRequestページもありがとうございます!
勉強することがたくさんありますね!

*===**===**===**===*

今回教えていただいた「XMLHttpRequestを同期読み込みにするオプション」を指定することで、
元々やりたいと思っていた【指定したマップのイベントの個数を取得したい】は実現することが出来そうでした!!

RPGツクールMV の挙動の勉強になりそうな「Game_MapやGame_Interpreter等のupdateでロード完了をチェックする」方法も、もう少し検証したいと思っています。
皆様のおかげで、今回も新しい発見や納得がたくさんありました!
プラグインの作成が一区切りついたら、是非ご報告させていただけたらと思っています!(有用かどうかはともかく…!)

ツクールもjavascriptも勉強不足で、よくないコードや非推奨な処理を実施してしまいがちですが
引き続き精進していけたらと思います!
改めて、奏ねこまさん、剣崎さん、jp_asty さん、確認してくれた皆さん、本当にありがとうございました!!

(完了感を出していますが、もし何かあれば引き続きご教示いただけると大変嬉しいです!)

“MV:質問” へ戻る