気ままなタンス*プログラミングなどのノートブック

プログラミングやRPGツクール、DTM等について、学んだことや備忘録をアウトプットとして残し、情報を必要としている誰かにとって「かゆいところに手が届く」ブログとなることを願いながら記事を書いています。

【RPGツクールMV】[中級者向け]ゲーム開始~Scene_Title呼び出しまでの流れ(一人輪読会)

スポンサーリンク

ツクールMVで、各種内部処理を理解するため、ソースコードを読み、アウトプットしました。

「ここはどういう意図?あーでもないこうでもない」と意見を思考しながらやっていたため、「一人輪読会」とつけています。

今回の目的は
ゲーム開始~Scene_Title呼び出しまでにどういう処理が動いているのかを理解することです

www.slideshare.net

わかったこと

  • Scene_XXXX.initializeは、SceneManager.goto内で、シーンオブジェクトが生成されたタイミングで呼ばれる
  • Scene_XXXX.createは、SceneManager.changeSceneで、シーンが切り替わる時に呼ばれる
  • Scene_XXXX.startは、SceneManager.updateSceneで、シーンが開始されておらず、準備完了となった時点で呼ばれる
    • 1.initialize, 2.create, 3.start

ゲーム開始~Scene_Titleまでの流れ(ソースコード)

  • js/main.js
// 5行目
PluginManager.setup($plugins);

// 7行目
window.onload = function() {
    SceneManager.run(Scene_Boot);
};
  • js/rgs_managers.js
// 1470行目
SceneManager.run = function(sceneClass) {
    try {
        this.initialize();     // ★A
        this.goto(sceneClass); // ★B
        this.requestUpdate(); // ★C
    } catch (e) {
        this.catchException(e);
    }
};

/*
★A
// 1480行目
SceneManager.initialize = function() {
    this.initGraphics();    
    this.checkFileAccess();
    this.initAudio();
    this.initInput();
    this.initNwjs();
    this.checkPluginErrors();
    this.setupErrorHandlers();
};

// this.initGraphics(): Graphicsの初期化
// this.checkFileAccess(): index.htmlにおける、js/libs/pixi.jsから、js/main.jsまでをgetElementsByTagNameで取得し、XMLHttpRequestで取得確認をする
// this.initAudio(): Web Audio APIがブラウザで使えるかどうか判断
// this.initInput(): 入力関係の初期化(Input、TouchInput)
// this.initNwjs(): Nw.jsの初期化
// this.checkPluginErrors(): プラグインのエラーチェック。PluginManagerでエラーが発生した時点で、_errorUrls配列に対象スクリプトのURLを格納している
// this.setupErrorHandlers(): errorイベントが発生したら、SceneMangaer.onErrorが実行されるように設定
//                            keydownイベントが発生したら、SceneManager.onKeyDownが実行されるように設定
*/

/* ★B
// 1718行目
SceneManager.goto = function(sceneClass) {
    if (sceneClass) {
        this._nextScene = new sceneClass();
    }
    if (this._scene) {
        this._scene.stop();
    }
};

渡されたSceneクラス(Scene_Boot)のオブジェクトを生成

*/
  • js/rgs_scenes.js
// 155行目

Scene_Boot.prototype.initialize = function() {
    Scene_Base.prototype.initialize.call(this);
    this._startDate = Date.now();
};

// Scene_Bootの初期化と開始日付の設定
  • js/rpg_managers.js
/* ★C
// 1566行目
SceneManager.requestUpdate = function() {
    if (!this._stopped) {
        requestAnimationFrame(this.update.bind(this));
    }
};
*/

// SceneManager.updateをコールバックとして、requestAnimationFrameに渡す
// これで定期的にupdateが実行されるようになる
// 1572行目
SceneManager.update = function() {
    try {
        this.tickStart();
        this.updateInputData();
        this.updateMain(); // ★D
        this.tickEnd();
    } catch (e) {
        this.catchException(e);
    }
};

// this.updateMainの呼び出し

/* ★D
// 1639行目
SceneManager.updateMain = function() {
    this.changeScene(); // ★E
    this.updateScene();
    this.renderScene();
    this.requestUpdate();
};
*/

/* ★E
SceneManager.changeScene = function() {
    if (this.isSceneChanging() && !this.isCurrentSceneBusy()) {
        if (this._scene) {
            this._scene.terminate();
            this._previousClass = this._scene.constructor;
        }
        this._scene = this._nextScene;
        if (this._scene) {
            this._scene.create();
            this._nextScene = null;
            this._sceneStarted = false;
            this.onSceneCreate();
        }
        if (this._exiting) {
            this.terminate();
        }
    }
};

// this._sceneには何も入っていない。Sceneも変更中ではないので、if文はスルー
// this._nextSceneにはScene_Baseのオブジェクトが入っている
// ここでようやく、Scene_Baseのcreateメソッドが呼ばれる
*/
  • js/rgs_scenes.js
// 160行目

Scene_Boot.prototype.create = function() {
    Scene_Base.prototype.create.call(this);
    DataManager.loadDatabase(); // ★F
    ConfigManager.load(); // ★G
    this.loadSystemImages(); // ★H
};
  • js/rgs_managers.js
/*
★F
// 65行目
DataManager.loadDatabase = function() {
    var test = this.isBattleTest() || this.isEventTest();
    var prefix = test ? 'Test_' : '';
    for (var i = 0; i < this._databaseFiles.length; i++) {
        var name = this._databaseFiles[i].name;
        var src = this._databaseFiles[i].src;
        this.loadDataFile(name, prefix + src);
    }
    if (this.isEventTest()) {
        this.loadDataFile('$testEvent', prefix + 'Event.json');
    }
};

// 78行目
DataManager.loadDataFile = function(name, src) {
    var xhr = new XMLHttpRequest();
    var url = 'data/' + src;
    xhr.open('GET', url);
    xhr.overrideMimeType('application/json');
    xhr.onload = function() {
        if (xhr.status < 400) {
            window[name] = JSON.parse(xhr.responseText);
            DataManager.onLoad(window[name]);
        }
    };
    xhr.onerror = function() {
        DataManager._errorUrl = DataManager._errorUrl || url;
    };
    window[name] = null;
    xhr.send();
};

// jsonファイルの読み込み、Gameオブジェクトを作成
// 例によって、エラーが発生したjsonは、_errorUrls配列に格納される
*/


/*
★G
// 503行目
ConfigManager.load = function() {
    var json;
    var config = {};
    try {
        json = StorageManager.load(-1);
    } catch (e) {
        console.error(e);
    }
    if (json) {
        config = JSON.parse(json);
    }
    this.applyData(config);
};

// config.rpgsaveの存在確認
// ローカルファイルか、Webストレージかによってパラメーターが異なる

*/

/*
// ★H
//  167行目
Scene_Boot.prototype.loadSystemImages = function() {
    ImageManager.loadSystem('Window');
    ImageManager.loadSystem('IconSet');
    ImageManager.loadSystem('Balloon');
    ImageManager.loadSystem('Shadow1');
    ImageManager.loadSystem('Shadow2');
    ImageManager.loadSystem('Damage');
    ImageManager.loadSystem('States');
    ImageManager.loadSystem('Weapons1');
    ImageManager.loadSystem('Weapons2');
    ImageManager.loadSystem('Weapons3');
    ImageManager.loadSystem('ButtonSet');
};

// 各アイコンファイルを取得

*/
  • js/rpg_managers.js
// 1665行目
SceneManager.updateScene = function() {
    if (this._scene) {
        if (!this._sceneStarted && this._scene.isReady()) {
            this._scene.start();
            this._sceneStarted = true;
            this.onSceneStart();
        }
        if (this.isCurrentSceneStarted()) {
            this._scene.update();
        }
    }
};

// this._sceneがnullではなく、まだ開始されていないので、startする(Scene_Boot)
  • js/rgs_scenes.js
// 200行目
Scene_Boot.prototype.start = function() {
    Scene_Base.prototype.start.call(this);
    SoundManager.preloadImportantSounds();
    if (DataManager.isBattleTest()) {
        DataManager.setupBattleTest();
        SceneManager.goto(Scene_Battle);
    } else if (DataManager.isEventTest()) {
        DataManager.setupEventTest();
        SceneManager.goto(Scene_Map);
    } else {
        this.checkPlayerLocation();
        DataManager.setupNewGame();
        SceneManager.goto(Scene_Title);
        Window_TitleCommand.initCommandPosition();
    }
    this.updateDocumentTitle();
};

// バトルテスト、イベントテストではないので、
// プレイヤーの初期位置を確認し、Scene_Titleを呼び出す

シーン系のソースコードを読み込んでだいぶ勉強になりました。

それでは、皆様も楽しいツクールライフを