ツクール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を呼び出す
シーン系のソースコードを読み込んでだいぶ勉強になりました。
それでは、皆様も楽しいツクールライフを