RPGツクールMZのプラグイン開発で、ある独自変数を作成した際にその変数をセーブ・ロードするための基礎知識を解説する。及び、変数にプラグインパラメーターやデータベースのメモ欄から初期値を代入する方法やJSONからの取り込み方法を解説する。なお、今回の記事で扱う変数はツクールエディタで利用する変数ではなくJavaScriptの変数だ。
独自グローバル変数の初期化・セーブ・ロード処理
こちらは独自の変数を作成し、既存のクラスに追加せずにセーブ・ロードに反映する処理だ。変数として好感度を用意。プラグインパラメータで初期値を決め、プラグインコマンドで現在の好感度をメッセージボックスで表示、好感度の変更ができる。
/*:
 * @plugindesc サンプルPlugin
 * @target MZ
 * @help
 * 好感度(1つのみ)を追加するサンプル
 * 
 * @param iniLovePoint
 * @text 初期好感度
 * @desc 一番最初の好感度
 * @default 1
 * @type number
 * 
 * @command outputMessage
 * @text 出力メッセージ
 * @desc メッセージを出力する。
 *
 * @command SetLovePoint
 * @text 好感度セット
 * @desc 好感度をセット
 * 
 * @arg value
 * @text 値
 * @desc 新たな好感度の値
 * @default 0
 * @type number
 */
(() => {
    const pluginName = document.currentScript.src.match(/^.*\/(.*).js$/)[1];
    const param = PluginManager.parameters(pluginName);
    let LovePoint = 0;
    //好感度をメッセージ出力
    PluginManager.registerCommand(pluginName, "outputMessage", () => {
        $gameMessage.add(LovePoint);
    });
    //好感度に新たな値をセット
    PluginManager.registerCommand(pluginName, "SetLovePoint", (args) => {
        LovePoint = args.value;
    });
    //好感度初期化
    const _DataManager_createGameObjects = DataManager.createGameObjects;
    DataManager.createGameObjects = function() {
        _DataManager_createGameObjects.apply(this, arguments);
        //好感度にプラグインパラメータ(初期好感度)をセット
        LovePoint = param.iniLovePoint;
        //今回は単純な変数だが、グローバルに影響するクラスの場合、ここで生成する。
        //例:$GameLovePoint = new Game_LovePoint();
    }
    //セーブデータ保持クラスに好感度クラスを格納
    const _DataManager_makeSaveContents = DataManager.makeSaveContents;
    DataManager.makeSaveContents = function() {
        contents = _DataManager_makeSaveContents.apply(this, arguments);
        
        contents.lovePoint = LovePoint;
        //クラスの場合、コアスクリプトと同じように取得すると上手くいかない。
        //プロパティ1つ1つをセットする必要がある。
        //例:$GameLovePoint._lovePoint = contents.lovePoint._lovePoint
        return contents;
    }
    //ロードデータが格納されているクラスから好感度クラスを取得
    const _DataManager_extractSaveContents = DataManager.extractSaveContents;
    DataManager.extractSaveContents = function(contents) {
         _DataManager_extractSaveContents.apply(this, arguments);
         LovePoint = contents;
    }
})();セーブ・ロードは主にDataManagerクラスに追記することで実現する。DataManagerはJSONの読み込みやグローバルに利用するクラスの生成、管理を行う。その一環でStorageManagerを介してクラスで利用している変数のセーブ・ロードも行っている。今回はそれらグローバルな値を初期化・セーブ・ロードするメソッドを利用する。
DataManager.createGameObjects
ゲーム起動時に呼ばれるメソッド。グローバルに使用したいクラスの生成、変数の初期化などを行う。今回はプラグインパラメータの初期好感度をセットする。ニューゲーム、テストプレイの初期値やタイトル画面時の値になる。
contents、makeSaveContents、extractSaveContents
セーブする時はこのクラスを丸ごと保存し、ロードする時は丸ごとロードする。セーブ直前にmakeSaveContentsメソッドで保存するクラスをcontentsに格納し、ロード直後にextractSaveContentsメソッドでcontentsから各クラスに値を引き渡す。contentsはStrageManagerに引き渡してセーブ&ロード処理を行う。
ゲーム全体で使用するクラスを利用した変数の初期化・セーブ・ロード
RPGツクールMZを起動してから閉じるまで永続的に使用できるグローバルなクラス変数がいくつかある。それぞれ$game~と命名しており、ゲーム内でいつでも使用できる。下記$data~との違いはゲーム内で値が変化すること。セーブに〇がついている項目はセーブ時に内部の変数を全て保存する。保存はクラス内部の変数に対して自動的に行われ、それはプラグインで追加した変数に対しても同様。そのためセーブに〇がついているクラスに変数を追加する場合、セーブ・ロードに関する処理を記述する必要はない。逆にそれ以外のクラスでセーブ・ロード処理が必要な場合は処理の記述が必要だ。セーブ対象のクラスに変数を追加する場合、セーブファイルの容量も増加する。
| 変数名 | 変数のクラス | 内容 | セーブ | 
|---|---|---|---|
| $gameTemp | Game_Temp | 一時的なデータ | |
| $gameSystem | Game_System | システムデータ | 〇 | 
| $gameScreen | Game_Screen | イベントコマンドの画面関連 | 〇 | 
| $gameTimer | Game_Timer | タイマー管理 | 〇 | 
| $gameMessage | Game_Message | メッセージウィンドウ操作 | |
| $gameSwitches | Game_Switches | スイッチ | 〇 | 
| $gameVariables | Game_Variables | 変数 | 〇 | 
| $gameSelfSwitches | Game_SelfSwitches | セルフスイッチ | 〇 | 
| $gameActors | Game_Actors | アクター(Game_Actor)群 | 〇 | 
| $gameParty | Game_Party | パーティー | 〇 | 
| $gameTroop | Game_Troop | 敵グループ | |
| $gameMap | Game_Map | マップ管理 | 〇 | 
| $gamePlayer | Game_Player | プレイヤーや乗り物の管理 | 〇 | 
これらのクラスはゲーム開始時に生成され、セーブ・ロード時に値が切り替わる。その他はゲーム進行に応じて変化していく。どの場面でも自由に使えるクラスだ。
今回の主題は、このクラス変数のうちセーブ可能なクラス変数に追加した変数は、自動的にセーブ・ロード対象になる点だ。例えば今回はGame_Actorクラスに変数を追加し、各アクターごとに好感度を設定できるようにする。Game_Actorは上記表にないため対象外になりそうだが、実はGame_Actorsクラスが全アクター分のGame_Actorを内部変数として所持している。内部変数は全てセーブ・ロード対象のため、Game_Actorがセーブ・ロード対象となり、Game_Actorに追加した変数も保存対象となる。
以下は各アクターに好感度(lovePoint)を設定するプラグインのサンプルだ。好感度はデータベースのアクター画面のメモ欄で<LovePoint>~</LovePoint>と囲まれた箇所を初期値とする。プラグインコマンドで現在の好感度をメッセージボックスで表示、好感度の変更ができる。今回はサンプルなのでアクターIDが1のキャラのみ変更でき、他のアクターIDは対応していない。
/*:
 * @plugindesc サンプルPlugin
 * @target MZ
 * @help
 * Game_Actorに新しい変数を追加するサンプル
 * 
 * @command outputMessage
 * @text 出力メッセージ
 * @desc メッセージを出力する。
 *
 * @command SetLovePoint
 * @text 好感度セット
 * @desc 好感度をセット
 * 
 * @arg value
 * @text 値
 * @desc 新たな好感度の値
 * @default 0
 * @type number
 */
(() => {
    const pluginName = document.currentScript.src.match(/^.*\/(.*).js$/)[1];
    //好感度をメッセージ出力
    PluginManager.registerCommand(pluginName, "outputMessage", () => {
        $gameMessage.add($gameActors.actor(1).GetLovePoint());
    });
    //好感度に新たな値をセット
    PluginManager.registerCommand(pluginName, "SetLovePoint", (args) => {
        $gameActors.actor(1).SetLovePoint(args.value);
    });
    //変数初期化
    const _Game_Actor_InitMembers = Game_Actor.prototype.initMembers;
    Game_Actor.prototype.initMembers = function(actorId) {
        _Game_Actor_InitMembers.apply(this, arguments);
        this._lovoPoint = 0;
    }
    //セットアップで初期値を格納
    //初期値はメモ欄の<LovePoint></LovePoint>内
    const _Game_Actor_Setup = Game_Actor.prototype.setup;
    Game_Actor.prototype.setup = function(actorId) {
        _Game_Actor_Setup.apply(this, arguments);
        const actor = $dataActors[actorId];
        this._lovoPoint = Number(extractTagContent(actor.note, 'LovePoint', 0, 0));
    }
    Game_Actor.prototype.GetLovePoint = function()
    {
        return this._lovoPoint;
    }
    Game_Actor.prototype.SetLovePoint = function(value)
    {
        this._lovoPoint = Number(value);
    }
    //タグ内の値を取得する
    //note:文字列
    //tagName:タグ名
    //flg:0:「<タグ名>~</タグ名>」の~の部分を取得。改行にも対応
    //    1:「タグ名:~」の~の部分を取得
    //initial: 値が無かった場合の値
    function extractTagContent(note, tagName, flg, defaultValue) {
        if (flg === 0) {
            const tagPattern = new RegExp(`<${tagName}>([\\s\\S]*?)<\/${tagName}>`);
            const match = tagPattern.exec(note);
            return match ? match[1].trim() : defaultValue;
        } else if (flg === 1) {
            const tagPattern = new RegExp(`${tagName}:(.*)`);
            const match = tagPattern.exec(note);
            return match ? match[1].trim() : defaultValue;
        }
        return null;
    }
})();セーブ・ロードの担当はDataManager及びStrageManagerだが、今回は全くその2つのクラスを触っていない。アクターに変数_lovePointを追加し、initMembers()で初期化、setupでアクターメモ欄から好感度初期値を取得している。setupはクラス生成時に呼ばれるメソッドだ。

extractTagContentは今回用に作ったメソッドで値から<タグ名>~</タグ名>の~を取得、又はタグ名:~の~を取得する。メモ欄やメッセージの拡張などでよく使うので、自分専用でこの種のメソッドを作っておくことをお勧めする。
今回はアクターを例にしたが、保存したい変数やクラス変数が何かに紐づかない単一の要素の場合、Game_Player、Game_Partyあたりに作成した変数を追加すると今回のようにセーブ処理を書かなくてもよいので楽だ。
JSONデータベースの読み込み
RPGツクールの開発者がデータベースやイベントエディタで入力した値は「プロジェクトトップ\data\」にjsonファイルとして出力する。各種jsonファイルの読み込みはゲームexe実行直後、スプラッシュ画面表示前、一番初期に呼ばれるシーン(Scene_Boot)にてDataManager.loadDatabase()を実行することでjsonファイルをメモリに格納している。
DataManager._databaseFiles()には、格納するクラス名(Data_)とjsonファイル名が記述されており、以下の通りだ。
| データベースのタイトル | jsonファイル名 | クラス名 | 
|---|---|---|
| アクター | actors.json | $dataActors | 
| 職業 | Classes.json | $dataClasses | 
| スキル | Skills.json | $dataSkills | 
| アイテム | Items.json | $dataItems | 
| 武器 | Weapons.json | $dataWeapons | 
| 防具 | Armors.json | $dataArmors | 
| 敵キャラ | Enemies.json | $dataEnemies | 
| 敵グループ | Troops.json | $dataTroops | 
| ステート | States.json | $dataStates | 
| アニメーション | Animations.json | $dataAnimations | 
| タイルセット | Tilesets.json | $dataTilesets | 
| コモンイベント | CommonEvents.json | $dataCommonEvents | 
| システム1,2,タイプ,用語 | System.json | $dataSystem | 
| マップ情報(全体) | MapInfos.json | $dataMapInfos | 
| 各種マップ | Map000~999.json | $dataMap | 
具体的にデータベースのどの項目がどのプロパティに対応しているかはトリアコンタン氏作成のデータベース一覧を参照するとよい。
以下のように取得する。
$data~[id].プロパティ例えばデータベースのアクターのID = 0003のアクター名を取得したい場合、$dataActors[3].nameとなる。なお、$data~はあくまでデータベースの順番に並んでいるため、パーティーの2番目みたいに動的に値が変化する項目の取得はできない。こちらは$game~で取得する。
独自にデータベースを追加したい場合はDataManager.loadDatabase()に追記する。以下はdataフォルダ以下にalbum.jsonを作成してそれを読み込み、プラグインコマンドでメッセージ出力するプラグインのサンプルだ。
dataフォルダ以下のjsonファイルの読み込み、及びクラス格納はDataManager.loadDataFile(クラス名、jsonファイル名)で行える。
albums.json(dataフォルダ直下に作成)
[
  {
    "album": "白い羽根",
    "year": 1998,
    "chart": "-"
  },
  {
    "album": "ステラ",
    "year": 2000,
    "chart": "-"
  },
  {
    "album": "白い血",
    "year": 2003,
    "chart": 71
  },
  {
    "album": "エレファント",
    "year": 2003,
    "chart": 3
  }
]/*:
 * @plugindesc サンプルPlugin
 * @target MZ
 * @help
 * albums.jsonを読み込む
 * 
 * @command outputMessage
 * @text 出力メッセージ
 * @desc メッセージを出力する。
 *
 */
(() => {
    const pluginName = document.currentScript.src.match(/^.*\/(.*).js$/)[1];
    $dataAlbum = null;
    PluginManager.registerCommand(pluginName, "outputMessage", () => {
        $gameMessage.add($dataAlbum[0].album + ' ' + $dataAlbum[0].year + ' ' + $dataAlbum[0].chart);
        $gameMessage.add($dataAlbum[1].album + ' ' + $dataAlbum[1].year + ' ' + $dataAlbum[1].chart);
        $gameMessage.add($dataAlbum[2].album + ' ' + $dataAlbum[2].year + ' ' + $dataAlbum[2].chart);
        $gameMessage.add($dataAlbum[3].album + ' ' + $dataAlbum[3].year + ' ' + $dataAlbum[3].chart);
    });
    const _DataManager_loadDatabase = DataManager.loadDatabase;
    DataManager.loadDatabase = function() {
        _DataManager_loadDatabase.apply(this, arguments);
        this.loadDataFile("$dataAlbum", "Albums.json");
    }
})();
単純なプロパティに文字列や数値が入るだけの単純なJSONの場合、ExcelやGoogle SpreadSheetなどからcsv出力したファイルをCSV to JSONなどの変換ツールを用いて変換する方法が一番楽だ。以下は参考にjsonファイルを作る際のスプレッドシート。

Excelでは作成できない複雑なtree構造を持つjsonファイル作成の際はJSON Editor Onlineなどのツールが便利だ。
JSONファイルを用いた扱い方を説明したが、loadDatabase()は外部のファイルをメモリに格納する処理を一手に引き受けている。手間をかけてもよいならloadDatabase()でcsvファイルを読み込んでdata~に格納みたいな処理を作ることもできる。
関連リンク
当サイトのRPGツクールMZプラグイン開発のトップページ。他の記事へのリンクをまとめている。


