こんにちは!
RPGツクールMVで、マップが切り替わった時にそのマップの名前を表示するウィンドウがありますよね(下記イメージの赤枠)。
このウィンドウはマップに入った時にフェードイン・アウトしながら表示されます。 RPGツクールMVでは、マップの「表示名」に入れるだけで、このマップ名称を表示するウィンドウが有効になるんです!*1
フェードイン・アウトしながらウィンドウを表示する機能は、マップ以外にも、ミニゲーム等のいろんな部分に使えそうです。
そこで、どのようなソースコードでこの仕組みを実現しているのかを調べてみることにしました。
参考とする関数オブジェクト
マップ上で呼び出される
ことと、マップ名を表示する
ことから、
下記のファイル・関数オブジェクトに当たりをつけて調べました。
- rpg_scenes.js - Scene_Map
- rpg_windows.js - Window_MapName
ざっくりとした流れ
- マップオブジェクトの作成
- マップ準備完了
- マップロードイベント発火
マップに必要なウィンドウの準備(Scene_Map.prototype.createDisplayObjects)
まず、マップ用のシーンで定義されたcreateDisplayObjectsで、 ウィンドウレイヤやスプライトセット、さらに今回の対象であるMapNameWindowを作成するメソッドを呼び出します
Scene_Map.prototype.createDisplayObjects = function() { this.createSpriteset(); this.createMapNameWindow(); this.createWindowLayer(); this.createAllWindows(); };
マップ表示名のウィンドウ作成(Scene_Map.prototype.createMapNameWindow)
- createMapNameWindowを呼び出すことによって、this._mapNameWindowにオブジェクトが作成されます
- また、作成したオブジェクトをシーンの子オブジェクトとして追加します
Scene_Map.prototype.createMapNameWindow = function() { this._mapNameWindow = new Window_MapName(); this.addChild(this._mapNameWindow); };
マップ名を表示するウィンドウの初期化(Window_MapName.prototype.initialize)
上記createMapNameWindowの中で、Window_MapName()
がnewされた時点でinitializeが呼び出されます
Window_MapName.prototype.initialize = function() { var width = this.windowWidth(); var height = this.windowHeight(); Window_Base.prototype.initialize.call(this, 0, 0, width, height); this.opacity = 0; this.contentsOpacity = 0; this._showCount = 0; this.refresh(); };
initializeでは、下記のような初期化を行っているようです。
- width, heightの設定
- ウィンドウ自体の透明度の設定
- コンテンツの透明度の設定
- フェードインにかける時間の指定
- ウィンドウ内容のリフレッシュ
マップ名を表示するウィンドウ内容の表示(Window_MapName.prototype.refresh)
Window_MapName.prototype.refresh = function() { this.contents.clear(); if ($gameMap.displayName()) { var width = this.contentsWidth(); this.drawBackground(0, 0, width, this.lineHeight()); this.drawText($gameMap.displayName(), 0, 0, width, 'center'); } };
次に、リフレッシュが呼び出され、 一度コンテンツ(描画領域等)をクリアするようです。
その後、もし表示名$gameMap.displayName
が指定されている場合は、背景やマップ名の表示をしています。
ウィンドウの背景を設定(Window_MapName.prototype.drawBackground)
Window_MapName.prototype.drawBackground = function(x, y, width, height) { var color1 = this.dimColor1(); var color2 = this.dimColor2(); this.contents.gradientFillRect(x, y, width / 2, height, color2, color1); this.contents.gradientFillRect(x + width / 2, y, width / 2, height, color1, color2); };
マップ名表示の領域のグラデーションは、gradientFillRect
で表現されているようです。
マップ名表示ウィンドウをオープン(Scene_Map.prototype.start)
さらに処理を追うと、
マップのシーンが開始する際に、this._mapNameWindow.open()
でマップ名表示ウィンドウを開く処理が呼び出されることがわかります。
Scene_Map.prototype.start = function() { Scene_Base.prototype.start.call(this); SceneManager.clearStack(); if (this._transfer) { this.fadeInForTransfer(); this._mapNameWindow.open(); $gameMap.autoplay(); } else if (this.needsFadeIn()) { this.startFadeIn(this.fadeSpeed(), false); } this.menuCalling = false; };
ウィンドウオープンをフェードインで表現するための準備(Window_MapName.prototype.open)
Window_MapName.prototype.open = function() { this.refresh(); this._showCount = 150; };
リフレッシュ処理を呼び出し、showCountに150という値をセットしています。 この値がフェードイン・アウトを行う際に増減されるようです。
共通のupdateイベントによる、Windowのアップデート
Window_MapName.prototype.update = function() { Window_Base.prototype.update.call(this); if (this._showCount > 0 && $gameMap.isNameDisplayEnabled()) { this.updateFadeIn(); this._showCount--; } else { this.updateFadeOut(); } };
Window_MapName.prototype.updateFadeIn = function() { this.contentsOpacity += 16; }; Window_MapName.prototype.updateFadeOut = function() { this.contentsOpacity -= 16; };
- contentOpacityというのは、名前から察するに透明度のことのようです
- updateFadeIn()では、contentsOpacity の値を16増やしています
- updateFadeOutでは、contentsOpacity の値を16減らしています
- updateは、1フレームごとに呼び出されるので、フレーム毎に不透明度を16増減しているようです。
- showCountが0より大きい場合はフェードイン、それ以外の場合はフェードアウトを呼び出します。
- 60フレーム = 1秒 がツクールMVの基本なので、150フレーム=2.5秒でフェードイン・アウトを実行しているようです。
- ただし、不透明度255が最大であると考えると、150フレーム丁度で表示されるわけではなく、だいたい16フレーム(255/16)くらいで完全に表示され、残り134フレーム+αを表示した後、16フレームで完全に非表示となってしまうことが考えられます。
まとめ
コードリーディングを行うことによって、下記のようなことがわかりました。
- showCount = フレーム数(1/60秒)で表示時間を制御している
- フェードイン・フェードアウトは不透明度を増減することによって実現している
*1:RPGツクールVXから実装された素敵な機能です