//============================================================================= // MoviePicture.js // ---------------------------------------------------------------------------- // (C)2017 Triacontane // This software is released under the MIT License. // http://opensource.org/licenses/mit-license.php // ---------------------------------------------------------------------------- // Version // 1.8.0 2024/08/08 読み込みが完了したタイミングでONになるスイッチを追加 // 1.7.4 2022/11/20 動画ピクチャの再生でエラーになる原因不明のケースに対処 // 1.7.3 2022/09/16 動画のロード完了とマップ遷移が同一フレームで起こるとエラーになる不具合を修正 // 1.7.2 2020/09/21 autoplayをtrueに変更 // 1.7.1 2019/08/26 他のプラグインとの組み合わせによりエラーになる可能性のある記述を修正 // 1.7.0 2019/06/30 動画の取得元フォルダと拡張子を変更して動画を難読化できるようにしました。 // 1.6.0 2019/06/29 複数の動画を並行してロードしているときは、すべての動画のロードが完了してから再生するよう変更しました // 一定フレームで動画を中断させるコマンドを追加 // 1.5.1 2019/06/29 画面遷移したとき、動画でないピクチャまで非表示になってしまう問題を修正 // 1.5.0 2019/06/11 動画再生終了後、動画ピクチャを自動削除せず最終フレームで静止したままにする機能を追加 // 1.4.1 2019/05/21 動画を縮小表示したときのジャギを軽減 // ヘルプの記載を本体バージョン1.6を前提に修正 // 1.4.0 2019/01/06 movieフォルダ以外の場所に配置されている動画ファイルを再生できる機能を追加 // 1.3.3 2018/11/08 再生開始直後に停止したとき、特定条件下で正常に停止しない問題を修正 // 1.3.2 2018/06/17 ピクチャの消去によって動画再生を終了した場合に、再生速度と音量が初期化されない問題を修正 // 1.3.1 2017/08/27 二連続で再生したときに動画の音量同期機能が正常に動作しない問題を修正 // 1.3.0 2017/08/26 動画の音量をいずれかのオーディオ音量と同期させる機能を追加 // 1.2.0 2017/08/18 動画の再生速度(倍率)を変更できるプラグインコマンドを追加 // 1.1.0 2017/08/09 アルファチャンネル付き動画の再生に対応(ただし特定の手順を踏む必要あり) // 1.0.3 2017/08/08 エラー処理を追加 // 1.0.2 2017/08/07 環境に関する制約を追加 // 1.0.1 2017/08/07 リファクタリング(仕様の変更はなし) // 1.0.0 2017/08/06 初版 // ---------------------------------------------------------------------------- // [Blog] : https://triacontane.blogspot.jp/ // [Twitter]: https://twitter.com/triacontane/ // [GitHub] : https://github.com/triacontane/ //============================================================================= /*: @url https://triacontane.blogspot.com/ @plugindesc Video picture display plugin @author Triacontane @license MIT License @help English Help Translator: munokura This is an unofficial English translation of the plugin help, created to support global RPG Maker users. Feedback is welcome to improve translation quality (see: https://github.com/munokura/triacontane-MV-plugins ). Original plugin by Triacontane. Please check the latest official version at: https://triacontane.blogspot.com ----- Plays videos using the picture display frame. Picture movement and rotation are supported, and multiple videos can be played in parallel. Videos will also be displayed at the bottom of the window. However, "picture color change" is not supported. This plugin can only be used with the main game version 1.6.0 or later. We have confirmed that videos stop at the first frame when run on a smart device. Therefore, for the time being, only local execution (Game.exe) is supported. Prepare a video file with the plugin command "MP_SET_MOVIE," then execute the event command "Show Picture" with an empty file specification. Plugin Command Details Execute from the event command "Plugin Command." (Parameters are separated by a space.) MP_SET_MOVIE file # Prepares the video file [file]. No extension required. MP_SET_LOOP 1 on # Loops the video with picture number [1]. MP_SET_PAUSE 1 on # Pauses the video in picture number [1]. MP_SET_WAIT 1 # Waits for an event until the video in picture number [1] plays. MP_SET_LIMIT 1 50 # Pauses the video in picture number [1] at 50 frames. MP_SET_VOLUME 1 50 # Sets the volume of the video in picture number [1] to 50%. MP_SET_SPEED 1 150 # Sets the playback speed of the video in picture number [1] to 150%. Prepare a video file located in a path other than the movie folder. The specified [path] can be a full path or a relative path from the path where the save folder is located. An extension is required. MP_SET_OUTER_MOVIE path # Prepare a video file [path]. An extension is required. Sets the video volume type. The settings are the same as the "Video Volume Type" plugin parameter. This overrides the plugin parameter setting. MP_SET_VOLUME_TYPE BGM To use a video with an alpha channel, set the second argument to on when executing the "MP_SET_MOVIE" plugin command. MP_SET_MOVIE file on * Transparency cannot be used in smart device environments (using .mp4). This is a codec (H.264) specification and is not supported by the plugin. Script Details Returns true if the video picture with the specified number has finished playing. Specifying a non-existent picture number will result in an error. This script can only be used if the "Auto-delete on End" parameter is disabled. $gameScreen.picture(2).isVideoEnd(); # Returns true if picture [2] has finished playing. Note: Playing multiple large videos may result in reduced performance. Terms of Use: You may modify and redistribute this plugin without permission from the author, and there are no restrictions on its use (commercial, 18+, etc.). This plugin is now yours. @param 動画音量種別 @text Video volume type @desc If the video contains audio, this is the audio type that refers to the volume. If not specified, it will always play at 100%. @type select @default none @option none @option BGM @option BGS @option ME @option SE @param 終了時自動削除 @text Automatic deletion on exit @desc Automatically delete the video picture when the video finishes playing. If not deleted, the video will freeze at the last frame. @type boolean @default true @param 動画取得フォルダ @text Video acquisition folder @desc The folder from which video files will be retrieved. If not specified, the "movies" folder will be used. No trailing slash is required. @param webm偽装拡張子 @text webm disguised extension @desc This is the disguised extension when playing webm format. Specify this if you want to obfuscate it. This does not increase the number of supported formats. @param mp4偽装拡張子 @text mp4 disguised extension @desc This is the disguised extension when playing mp4 format. Specify this if you want to obfuscate it. This does not increase the number of supported formats. @param 読み込み完了スイッチ @text Loading complete switch @desc This is the switch number that turns ON when the video file has finished loading. @type switch @default 0 */ /*:ja @plugindesc 動画のピクチャ表示プラグイン @author トリアコンタン @param 動画音量種別 @desc 動画再生時に音声が含まれる場合、その音量を参照するオーディオ種別です。指定しない場合、常に100%で再生されます。 @default none @type select @option none @option BGM @option BGS @option ME @option SE @param 終了時自動削除 @desc 動画再生終了時に動画ピクチャを自動で削除します。削除しない場合、動画は最終フレームで静止します。 @default true @type boolean @param 動画取得フォルダ @desc 動画ファイルの取得元フォルダです。指定しない場合は「movies」フォルダが使用されます。末尾のスラッシュは不要です。 @default @param webm偽装拡張子 @desc webm形式を再生するときの偽装拡張子です。難読化したい場合に指定します。対応フォーマットが増えるわけではありません。 @default @param mp4偽装拡張子 @desc mp4形式を再生するときの偽装拡張子です。難読化したい場合に指定します。対応フォーマットが増えるわけではありません。 @default @param 読み込み完了スイッチ @desc 動画ファイルの読み込み完了時にONになるスイッチ番号です。 @default 0 @type switch @help ピクチャの表示枠を使って動画を再生します。 ピクチャの移動や回転による処理の対象になるほか、複数の動画の並行再生が 可能になります。また、動画がウィンドウの下に表示されるようになります。 ただし「ピクチャの色調変更」には対応していません。 このプラグインは本体ver1.6.0以降でのみ使用できます。 現在、スマートデバイスで実行したときに動画が最初のフレームで停止する 現象を確認しています。 よって当面の間はローカル実行(Game.exe)のみをサポート対象とします。 プラグインコマンド「MP_SET_MOVIE」で動画ファイルを準備してから イベントコマンド「ピクチャの表示」をファイル指定を空で実行してください。 プラグインコマンド詳細 イベントコマンド「プラグインコマンド」から実行。 (パラメータの間は半角スペースで区切る) MP_SET_MOVIE file # 動画ファイル[file]を準備します。拡張子不要。 MP_動画設定 file # 同上 MP_SET_LOOP 1 on # ピクチャ番号[1]の動画がループ再生されます。 MP_ループ設定 1 on # 同上(offでループ再生を解除します) MP_SET_PAUSE 1 on # ピクチャ番号[1]の動画が一時停止します。 MP_ポーズ設定 1 on # 同上(offで再生を再開します) MP_SET_WAIT 1 # ピクチャ番号[1]の動画が再生するまでイベントを待機します。 MP_ウェイト設定 1 # 同上 MP_SET_LIMIT 1 50 # ピクチャ番号[1]の動画を50フレームで中断します。 MP_リミット設定 1 50 # 同上 MP_SET_VOLUME 1 50 # ピクチャ番号[1]の動画の音量を50%に設定します。 MP_音量設定 1 50 # 同上 MP_SET_SPEED 1 150 # ピクチャ番号[1]の動画の再生速度を150%に設定します。 MP_速度設定 1 150 # 同上 movieフォルダ以外のパスに存在する動画ファイルを準備します。 指定する[path]は、フルパスもしくはsaveフォルダの存在するパスからの相対パスです。 拡張子が必要です。 MP_SET_OUTER_MOVIE path # 動画ファイル[path]を準備します。拡張子必須 MP_外部動画設定 path # 同上 動画音量種別を設定します。設定する内容はプラグインパラメータ「動画音量種別」と 同じです。プラグインパラメータの設定より優先されます。 MP_音量種別設定 BGM MP_SET_VOLUME_TYPE BGM アルファチャンネル付き動画を使用する場合は、 プラグインコマンド「MP_SET_MOVIE」実行時に二つめの引数をonにしてください。 MP_SET_MOVIE file on ※ スマートデバイス環境(.mp4を使用)では透過を使用できません。 こちらはコーデック(H.264)の仕様なのでプラグイン側では対応できません。 ・スクリプト詳細 指定した番号の動画ピクチャが再生終了している場合にtrueを返します。 存在しないピクチャ番号を指定するとエラーになります。 このスクリプトはパラメータ「終了時自動削除」が無効な場合のみ使えます。 $gameScreen.picture(2).isVideoEnd(); # ピクチャ[2]の再生が終了している場合にtrue 注意: サイズの大きな動画を複数再生すると、パフォーマンスが低下する可能性があります。 利用規約: 作者に無断で改変、再配布が可能で、利用形態(商用、18禁利用等) についても制限はありません。 このプラグインはもうあなたのものです。 */ (function () { 'use strict'; var pluginName = 'MoviePicture'; var metaTagPrefix = 'MP_'; //============================================================================= // ローカル関数 // プラグインパラメータやプラグインコマンドパラメータの整形やチェックをします //============================================================================= var getParamString = function (paramNames) { if (!Array.isArray(paramNames)) paramNames = [paramNames]; for (var i = 0; i < paramNames.length; i++) { var name = PluginManager.parameters(pluginName)[paramNames[i]]; if (name) return name; } return ''; }; var getParamNumber = function (paramNames, min, max) { var value = getParamString(paramNames); if (arguments.length < 2) min = -Infinity; if (arguments.length < 3) max = Infinity; return (parseInt(value) || 0).clamp(min, max); }; var getParamBoolean = function (paramNames) { var value = getParamString(paramNames); return value.toUpperCase() === 'TRUE'; }; var convertEscapeCharacters = function (text) { if (isNotAString(text)) text = ''; var windowLayer = SceneManager._scene._windowLayer; return windowLayer ? windowLayer.children[0].convertEscapeCharacters(text) : text; }; var isNotAString = function (args) { return String(args) !== args; }; var convertAllArguments = function (args) { for (var i = 0; i < args.length; i++) { args[i] = convertEscapeCharacters(args[i]); } return args; }; var getArgNumber = function (arg, min, max) { if (arguments.length < 2) min = -Infinity; if (arguments.length < 3) max = Infinity; return (parseInt(arg) || 0).clamp(min, max); }; var getArgBoolean = function (arg) { return arg && (arg.toUpperCase() === 'ON' || arg.toUpperCase() === 'TRUE'); }; var setPluginCommand = function (commandName, methodName) { pluginCommandMap.set(metaTagPrefix + commandName, methodName); }; //============================================================================= // パラメータの取得と整形 //============================================================================= var param = {}; param.movieVolumeType = getParamString(['MovieVolumeType', '動画音量種別']).toUpperCase(); param.autoEraseOnEnd = getParamBoolean(['AutoEraseOnEnd', '終了時自動削除']); param.movieFolder = getParamString(['MovieFolder', '動画取得フォルダ']); param.webmExt = getParamString(['WebmExt', 'webm偽装拡張子']); param.mp4Ext = getParamString(['Mp4Ext', 'mp4偽装拡張子']); param.onLoadSwitch = getParamNumber(['OnLoadSwitch', '読み込み完了スイッチ'], 0); var pluginCommandMap = new Map(); setPluginCommand('SET_MOVIE', 'execSetVideoPicture'); setPluginCommand('動画設定', 'execSetVideoPicture'); setPluginCommand('SET_LOOP', 'execSetVideoLoop'); setPluginCommand('ループ設定', 'execSetVideoLoop'); setPluginCommand('SET_SPEED', 'execSetVideoSpeed'); setPluginCommand('速度設定', 'execSetVideoSpeed'); setPluginCommand('SET_PAUSE', 'execSetVideoPause'); setPluginCommand('ポーズ設定', 'execSetVideoPause'); setPluginCommand('SET_WAIT', 'execSetVideoWait'); setPluginCommand('ウェイト設定', 'execSetVideoWait'); setPluginCommand('SET_LIMIT', 'execSetVideoLimit'); setPluginCommand('リミット設定', 'execSetVideoLimit'); setPluginCommand('SET_VOLUME', 'execSetVideoVolume'); setPluginCommand('音量設定', 'execSetVideoVolume'); setPluginCommand('SET_VOLUME_TYPE', 'execSetVideoVolumeType'); setPluginCommand('音量種別設定', 'execSetVideoVolumeType'); setPluginCommand('SET_OUTER_MOVIE', 'execSetOuterVideoPicture'); setPluginCommand('外部動画設定', 'execSetOuterVideoPicture'); //============================================================================= // Game_Interpreter // プラグインコマンドを追加定義します。 //============================================================================= var _Game_Interpreter_pluginCommand = Game_Interpreter.prototype.pluginCommand; Game_Interpreter.prototype.pluginCommand = function (command, args) { _Game_Interpreter_pluginCommand.apply(this, arguments); var pluginCommandMethod = pluginCommandMap.get(command.toUpperCase()); if (pluginCommandMethod) { this[pluginCommandMethod](convertAllArguments(args)); } }; Game_Interpreter.prototype.execSetVideoPicture = function (args) { $gameScreen.setVideoPictureName(args[0], getArgBoolean(args[1]), false); }; Game_Interpreter.prototype.execSetOuterVideoPicture = function (args) { $gameScreen.setVideoPictureName(args[0], getArgBoolean(args[1]), true); }; Game_Interpreter.prototype.execSetVideoLoop = function (args) { var picture = $gameScreen.picture(getArgNumber(args[0]), 1); if (picture) { picture.setVideoLoop(getArgBoolean(args[1])); } }; Game_Interpreter.prototype.execSetVideoPause = function (args) { var picture = $gameScreen.picture(getArgNumber(args[0]), 1); if (picture) { picture.setVideoPause(getArgBoolean(args[1])); } }; Game_Interpreter.prototype.execSetVideoVolume = function (args) { var picture = $gameScreen.picture(getArgNumber(args[0]), 1); if (picture) { picture.setVideoVolume(getArgNumber(args[1], 0, 100)); } }; Game_Interpreter.prototype.execSetVideoLimit = function (args) { var picture = $gameScreen.picture(getArgNumber(args[0]), 1); if (picture) { picture.setFrameLimit(getArgNumber(args[1], 0)); } }; Game_Interpreter.prototype.execSetVideoVolumeType = function (args) { var picture = $gameScreen.picture(getArgNumber(args[0]), 1); if (picture) { picture.setVideoVolumeType(args[1]); } }; Game_Interpreter.prototype.execSetVideoWait = function (args) { var picture = $gameScreen.picture(getArgNumber(args[0]), 1); if (picture) { picture.setVideoWait(true); this._waitMode = 'videoPicture'; } }; Game_Interpreter.prototype.execSetVideoSpeed = function (args) { var picture = $gameScreen.picture(getArgNumber(args[0]), 1); if (picture) { picture.setVideoSpeed(getArgNumber(args[1], 10, 500)); } }; var _Game_Interpreter_updateWaitMode = Game_Interpreter.prototype.updateWaitMode; Game_Interpreter.prototype.updateWaitMode = function () { if (this._waitMode === 'videoPicture') { var waiting = $gameScreen.isVideoWaiting(); if (!waiting) { this._waitMode = ''; } return waiting; } else { return _Game_Interpreter_updateWaitMode.apply(this, arguments); } }; //============================================================================= // Utils // 動作環境を判定します。 //============================================================================= Utils.isPcChrome = function () { var agent = navigator.userAgent; return !!(!agent.match(/Android/) && agent.match(/Chrome/)) && !this.isNwjs(); }; //============================================================================= // Game_Screen // 動画ピクチャを準備します。 //============================================================================= Game_Screen.prototype.setVideoPictureName = function (movieName, useAlpha, useOuter) { this._videoUseAlpha = useAlpha; if (useOuter && !movieName.match(/^[A-Z]:/)) { const path = require('path'); this._videoPictureName = path.join(path.dirname(StorageManager.localFileDirectoryPath()), movieName); } else { this._videoPictureName = movieName; } }; Game_Screen.prototype.getVideoPictureName = function () { return this._videoPictureName; }; Game_Screen.prototype.isVideoUseAlpha = function () { return this._videoUseAlpha; }; Game_Screen.prototype.clearVideoPictureName = function () { this._videoPictureName = null; this._videoUseAlpha = null; }; Game_Screen.prototype.isVideoWaiting = function () { return this._pictures.some(function (picture) { return picture && picture.isVideoWait(); }); }; //============================================================================= // Game_Picture // 動画ピクチャに関連するプロパティを追加定義します。 //============================================================================= var _Game_Picture_show = Game_Picture.prototype.show; Game_Picture.prototype.show = function (name, origin, x, y, scaleX, scaleY, opacity, blendMode) { _Game_Picture_show.apply(this, arguments); var videoName = $gameScreen.getVideoPictureName(); if (videoName && !name) { this._name = videoName; this._video = true; this._ended = false; this._videoUseAlpha = $gameScreen.isVideoUseAlpha(); this.setVideoVolume(100); this.setVideoVolumeType(param.movieVolumeType); $gameScreen.clearVideoPictureName(); } else { this._video = false; } }; Game_Picture.prototype.isVideo = function () { return this._video; }; Game_Picture.prototype.isVideoUseAlpha = function () { return this._videoUseAlpha; }; Game_Picture.prototype.setVideoLoop = function (value) { this._loopVideo = this.isVideo() && value; }; Game_Picture.prototype.isVideoLoop = function () { return this._loopVideo; }; Game_Picture.prototype.setVideoPause = function (value) { this._pauseVideo = this.isVideo() && value; }; Game_Picture.prototype.isVideoPause = function () { return this._pauseVideo; }; Game_Picture.prototype.setVideoWait = function (value) { this._waitVideo = this.isVideo() && value; }; Game_Picture.prototype.isVideoWait = function () { return this._waitVideo; }; Game_Picture.prototype.setVideoVolume = function (value) { this._volumeVideo = value; }; Game_Picture.prototype.getVideoRealVolume = function () { return this._volumeVideo * AudioManager.getVideoPictureVolume(this._volumeVideoType); }; Game_Picture.prototype.setVideoVolumeType = function (value) { this._volumeVideoType = value; }; Game_Picture.prototype.setVideoSpeed = function (value) { this._speedVideo = value; }; Game_Picture.prototype.getVideoSpeed = function () { return this._speedVideo || 100; }; Game_Picture.prototype.setVideoPosition = function (value) { this._positionVideo = value; }; Game_Picture.prototype.getVideoPosition = function () { return this._positionVideo || 0; }; // used by user script Game_Picture.prototype.isVideoEnd = function () { return this._ended }; Game_Picture.prototype.setVideoEnd = function () { this._ended = true; }; Game_Picture.prototype.setFrameLimit = function (value) { this._frameLimit = value; }; Game_Picture.prototype.getFrameLimit = function () { return this._frameLimit; }; //============================================================================= // Sprite_Picture // ムービーピクチャを読み込みます。 //============================================================================= var _Sprite_Picture_loadBitmap = Sprite_Picture.prototype.loadBitmap; Sprite_Picture.prototype.loadBitmap = function () { if (this.picture().isVideo()) { this.loadVideo(); } else { _Sprite_Picture_loadBitmap.apply(this, arguments); } }; Sprite_Picture.prototype.loadVideo = function () { if (SceneManager.isBattleStartUnexpectedLoad()) { return; } if (this.isVideoPicture()) { this.bitmap.destroy(); } this.bitmap = ImageManager.loadVideo(this._pictureName, this.picture().isVideoUseAlpha()); this.bitmap.addLoadListener(function () { this.prepareVideo(); }.bind(this)); this._loadingState = 'loading'; }; Sprite_Picture.prototype.prepareVideo = function () { this.refreshForVideo(); this._playStart = true; var picture = this.picture(); if (picture) { this.bitmap.setCurrentTime(picture.getVideoPosition()); this._volume = null; this.updateVideoVolume(); } this._loadingState = 'prepared'; }; Sprite_Picture.prototype.refreshForVideo = function () { this._refresh(); }; var _Sprite_Picture_updateBitmap = Sprite_Picture.prototype.updateBitmap; Sprite_Picture.prototype.updateBitmap = function () { if (!this.picture()) { this.clearVideo(); } _Sprite_Picture_updateBitmap.apply(this, arguments); this.updateVideo(); }; var _Sprite_Picture_setBlendColor = Sprite_Picture.prototype.setBlendColor; Sprite_Picture.prototype.setBlendColor = function (color) { if (this.isVideoPicture()) return; _Sprite_Picture_setBlendColor.apply(this, arguments); }; Sprite_Picture.prototype.updateVideo = function () { if (!this.isVideoPicture()) return; this.bitmap.update(); if (this.bitmap.isEnded()) { this.finishVideo(); return; } if (this.picture() && this._playStart) { this.updateVideoSpeed(); this.updateVideoPause(); this.updateVideoVolume(); this.updateVideoLoop(); this.updateVideoWaiting(); this.updateVideoFrameLimit(); } }; Sprite_Picture.prototype.updateVideoSpeed = function () { var speed = this.picture().getVideoSpeed() / 100; if (speed !== this._speed) { this._speed = speed; this.bitmap.setVideoSpeed(speed); } }; Sprite_Picture.prototype.updateVideoPause = function () { var pause = this.picture().isVideoPause(); if (this._pause && !pause) { this.bitmap.play(); } if (!this._pause && pause) { this.bitmap.pause(); } this._pause = pause; }; Sprite_Picture.prototype.updateVideoLoop = function () { this.bitmap.setVideoLoop(this.picture().isVideoLoop()); }; Sprite_Picture.prototype.updateVideoVolume = function () { var volume = this.picture().getVideoRealVolume(); if (volume !== this._volume) { this._volume = volume; this.bitmap.setVolume(volume / 100); } }; Sprite_Picture.prototype.updateVideoWaiting = function () { var picture = this.picture(); if (picture.isVideoWait() && !this.bitmap.isFirstLap()) { picture.setVideoWait(false); } }; Sprite_Picture.prototype.updateVideoFrameLimit = function () { if (!this._pause) { this._frameCount++; } var limit = this.picture().getFrameLimit(); if (limit > 0 && limit < this._frameCount) { if (this.picture().isVideoLoop()) { this._bitmap.setCurrentTime(0); } else { this.finishVideo(); } this._frameCount = 0; } }; Sprite_Picture.prototype.finishVideo = function () { this._frameCount = 0; if (param.autoEraseOnEnd) { this.eraseVideo(); } else if (this.picture()) { this.picture().setVideoEnd(); } }; Sprite_Picture.prototype.eraseVideo = function () { this.clearVideo(); if (this.picture()) { $gameScreen.erasePicture(this._pictureId); this.visible = false; } }; Sprite_Picture.prototype.clearVideo = function () { if (!this.isVideoPicture()) return; var picture = this.picture(); if (picture) { picture.setVideoPosition(this.bitmap.getCurrentTime()); } this.bitmap.destroy(); this._volume = null; this._speed = null; this._pause = null; this._playStart = false; this.bitmap = null; this._loadingState = null; }; Sprite_Picture.prototype.isVideoPicture = function () { return this.bitmap && this.bitmap.isVideo(); }; Sprite_Picture.prototype.isLoading = function () { return this._loadingState === 'loading'; }; Sprite_Picture.prototype.isPrepared = function () { return this._loadingState === 'prepared'; }; Sprite_Picture.prototype.startVideo = function () { this._loadingState = null; if (!this.isVideoPicture()) { if (this._bitmap) { console.error('ピクチャが消去されたため、動画ピクチャの再生に失敗しました。'); } else { console.error('ピクチャが動画ではなかっため、動画ピクチャの再生に失敗しました。'); } return; } this._bitmap.play(); this._frameCount = 0; }; //============================================================================= // Spriteset_Base // 再生中の動画をすべて破棄します。 //============================================================================= Spriteset_Base.prototype.clearAllVideo = function () { this._pictureContainer.children.forEach(function (picture) { if (picture.clearVideo && picture.isVideoPicture()) { picture.clearVideo(); picture.bitmap = null; } }); }; var _Spriteset_Base_update = Spriteset_Base.prototype.update; Spriteset_Base.prototype.update = function () { _Spriteset_Base_update.apply(this, arguments); this.updateVideoPicture(); }; Spriteset_Base.prototype.updateVideoPicture = function () { var preparedPictures = []; var loading = this._pictureContainer.children.some(function (picture) { if (picture.isPrepared && picture.isPrepared()) { preparedPictures.push(picture); } return picture.isLoading && picture.isLoading(); }); if (!loading) { preparedPictures.forEach(function (picture) { picture.startVideo(); }) } }; //============================================================================= // Scene_Base // シーン遷移時に再生中の動画をすべて破棄します。 //============================================================================= var _Scene_Base_terminate = Scene_Base.prototype.terminate; Scene_Base.prototype.terminate = function () { if (this._spriteset && this._spriteset instanceof Spriteset_Base) { this._spriteset.clearAllVideo(); } _Scene_Base_terminate.apply(this, arguments); }; //============================================================================= // ImageManager // 動画の読み込みを追加定義します。 //============================================================================= ImageManager.loadVideo = function (filename, alpha) { if (filename) { return Bitmap_Video.load(this.getVideoFilePath(filename), true, this.getVideoClass(alpha)); } else { return this.loadEmptyBitmap(); } }; ImageManager.getVideoFilePath = function (filename) { if (!filename.match(/^[A-Z]:/)) { return this.getVideoFileFolder() + encodeURIComponent(filename) + this.getVideoFileExt(); } else { return filename; } }; ImageManager.getVideoFileFolder = function () { return (param.movieFolder || 'movies') + '/' }; ImageManager.getVideoClass = function (alpha) { if ((Utils.isNwjs() || Utils.isPcChrome()) && !alpha) { return Bitmap_Video; } else { return Bitmap_DrawVideo; } }; ImageManager.getVideoFileExt = function () { if (Graphics.canPlayVideoType('video/webm')) { return '.' + (param.webmExt || 'webm'); } else { return '.' + (param.mp4Ext || 'mp4'); } }; //============================================================================= // SceneManager // 戦闘開始時にマップピクチャが一瞬読み込まれてしまう現象を回避します //============================================================================= SceneManager.isBattleStartUnexpectedLoad = function () { return this._scene instanceof Scene_Battle && !$gameParty.inBattle(); }; //============================================================================= // AudioManager // 動画ピクチャの音量を取得します。 //============================================================================= AudioManager._movieVolumePropertyMap = { BGM: 'bgmVolume', BGS: 'bgsVolume', ME: 'meVolume', SE: 'seVolume', VOICE: 'voiceVolume' }; AudioManager.getVideoPictureVolume = function (volumeType) { var property = this._movieVolumePropertyMap[volumeType]; return Graphics.getVideoVolume() * (property ? this[property] : 100) / 100; }; //============================================================================= // Bitmap // 動画かどうかを判定します。 //============================================================================= Bitmap.prototype.isVideo = function () { return false; }; /** * Bitmap_Video * 動画ビットマップクラスです。 * @constructor */ function Bitmap_Video() { this.initialize.apply(this, arguments); } Bitmap_Video.prototype = Object.create(Bitmap.prototype); Bitmap_Video.prototype.constructor = Bitmap_Video; Bitmap_Video.prototype.initialize = function () { Bitmap.prototype.initialize.call(this); }; Bitmap_Video.prototype.isVideo = function () { return !!this._video; }; Bitmap_Video.load = function (url, smooth, loadClass) { var bitmap = Object.create(loadClass.prototype); bitmap._defer = true; bitmap.initialize(); bitmap.smooth = smooth; bitmap._requestVideo(url); return bitmap; }; Bitmap_Video.prototype.update = function () { if (!Utils.isPcChrome()) { this._baseTexture.update(); } }; Bitmap_Video.prototype.setVolume = function (volume) { this._video.volume = volume; }; Bitmap_Video.prototype.pause = function () { this._video.pause(); }; Bitmap_Video.prototype.play = function () { this._video.play(); }; Bitmap_Video.prototype.destroy = function () { if (this.isReady()) { this.pause(); this._video = null; this._baseTexture.destroy(); this.__baseTexture = null; } else { this._loadingDestory = true; } }; Bitmap_Video.prototype._requestVideo = function (url) { if (!this._loader) { this._loader = ResourceHandler.createLoader(url, this._requestVideo.bind(this, url), this._onError.bind(this)); } this._createVideo(url); this._createVideoBaseTexture(); this._loadingState = 'requesting'; }; Bitmap_Video.prototype._createVideo = function (url) { this._video = document.createElement('video'); this._video.src = url; this._video.addEventListener('canplaythrough', this._loadListener = this._onLoad.bind(this)); this._video.addEventListener('ended', this._endedListener = this._onEnded.bind(this)); this._video.addEventListener('error', this._errorListener = this._loader || this._onError.bind(this)); this._video.load(); this._video.autoplay = true; this._loadingState = 'requesting'; }; Bitmap_Video.prototype._createVideoBaseTexture = function () { var scaleMode = this.smooth ? PIXI.SCALE_MODES.LINEAR : PIXI.SCALE_MODES.NEAREST; this.__baseTexture = PIXI.VideoBaseTexture.fromVideo(this._video, scaleMode); this._baseTexture.autoPlay = true; }; Bitmap_Video.prototype._onLoad = function () { if (param.onLoadSwitch) { $gameSwitches.setValue(param.onLoadSwitch, true); } this._loadingState = 'loaded'; if (!this._video) { return; } if (this._loadingDestory) { this.destroy(); return; } var width = this._video.videoWidth; var height = this._video.videoHeight; this.resize(width, height); this._callLoadListeners(); }; Bitmap_Video.prototype._onEnded = function () { this._firstLapEnded = true; if (this._video && !this._video.loop) { this._ended = true; } }; Bitmap_Video.prototype._onError = function () { this._video.removeEventListener('load', this._loadListener); this._video.removeEventListener('ended', this._endedListener); this._video.removeEventListener('error', this._errorListener); this._loadingState = 'error'; }; Bitmap_Video.prototype.isFirstLap = function () { return !this._firstLapEnded; }; Bitmap_Video.prototype.isEnded = function () { return this._ended; }; Bitmap_Video.prototype.setVideoLoop = function (loop) { this._video.loop = loop; }; Bitmap_Video.prototype.setCurrentTime = function (value) { this._video.currentTime = value; }; Bitmap_Video.prototype.getCurrentTime = function () { return this._video.currentTime; }; Bitmap_Video.prototype.setVideoSpeed = function (value) { this._video.playbackRate = value; }; /** * Bitmap_DrawVideo * drawImageで実装する動画ビットマップクラスです。 * @constructor */ function Bitmap_DrawVideo() { this.initialize.apply(this, arguments); } Bitmap_DrawVideo.prototype = Object.create(Bitmap_Video.prototype); Bitmap_DrawVideo.prototype.constructor = Bitmap_DrawVideo; Bitmap_DrawVideo.prototype._createVideoBaseTexture = function () { // do nothing }; Bitmap_DrawVideo.prototype.update = function () { if (this.isHalfRefreshRateSize() && Graphics.frameCount % 2 !== 0) { return; } if (this.getCurrentTime() > 0) { this.clear(); } this._context.drawImage(this._video, 0, 0, this.width, this.height); this._baseTexture.update(); }; Bitmap_DrawVideo.prototype.isHalfRefreshRateSize = function () { return this.width * this.height > 1000000; }; //============================================================================= // Graphics // 動画の音量を取得します。 //============================================================================= Graphics.getVideoVolume = function () { return this._videoVolume; }; })();