//=============================================================================
// NRP_DynamicPixiFilter.js
//=============================================================================
/*:
* @target MZ
* @plugindesc v1.00 Pixi effects are called from Dynamic plugins.
* @author Takeshi Sunagawa (http://newrpg.seesaa.net/)
* @base FilterControllerMZ
* @base NRP_DynamicAnimationMZ
* @orderAfter NRP_DynamicAnimationMZ
* @url http://newrpg.seesaa.net/article/487983241.html
*
* @help Call Pixi's filter effect function
* from the DynamicAnimation&Motion plugins.
* ※Pixi is the library used by default in RPG Maler MV/MZ.
*
* This plugin is also required because
* it is via the FilterControllerMZ.js (by Tsukimi) function.
* https://forum.tkool.jp/index.php?threads/4306/
*
* -------------------------------------------------------------------
* [Usage]
* -------------------------------------------------------------------
* Once applied, it can be easily called
* from the DynamicAnimation and Motion plugins.
*
* The easiest effect to handle is "shockwave".
* Or rather, it is difficult to incorporate anything else into combat,
* so the following explanations will be based on that assumption.
*
* ◆DynamicAnimation
* For example, the following will display
* the shockwave effect simultaneously with the animation.
* ※If you do not need the animation, just do not set the image.
* ※By default, the effect is displayed
* at the beginning of the animation.
* -------------------------------------------------------------------
*
* filterType = shockwave
*
* -------------------------------------------------------------------
*
* ◆DynamicMotion
* The same is true for DynamicMotion.
* ※The effect is displayed on the motion performer's side by default.
* -------------------------------------------------------------------
*
* filterType = shockwave
*
* -------------------------------------------------------------------
*
* -------------------------------------------------------------------
* [Parameters]
* -------------------------------------------------------------------
* You can adjust the effect by specifying parameters.
* Most of the parameters follow FilterControllerMZ.js,
* so please refer to the explanation there for details.
*
* Parameters are specified as follows.
* -------------------------------------------------------------------
*
* filterType = shockwave // Type of Effects
* filterTarget = Battlers // Effects Target
* filterX = b.width / 2 // X-coordinate
* filterY = b.height / 2 // Y-coordinate
* // X,Y,Radius,Amplitude,Wavelength,Brightness
* filterParameters = [0,0,-1,30,160,1]
* filterId = 1
*
* -------------------------------------------------------------------
* See below for details.
*
* ◆filterType
* Types of filter effects.
* Basically, you should use "shockwave".
*
* ◆filterTarget
* The target of the effect.
* The standard target is the full screen,
* but the following can also be used.
*
* - Battlers: Only battlers.
* - Battleback: Battlebackgrounds only
* - FullScreenWithWindow: Full screen (including windows)
*
* ※The specification of Battlers and Battlebacks
* is a function added by this plugin.
* ※When Battlers are specified,
* the origin is the upper left corner of the battler.
* Please be careful when changing the coordinates.
*
* ◆filterSpeed
* The speed of the effect.
* For shockwave, it is the speed at which the effect spreads.
* The standard value for shockwave is "0.01", so use that as a reference.
* If you enter "1" by mistake,
* it will be too fast and you will not be able to see it.
*
* Also, if you set it to '0', it will remain in place,
* so You will need to delete it later.
*
* ◆filterX
* ◆filterY
* The X and Y coordinates at which the effect will be displayed.
* May be omitted as it is displayed at the starting point
* of the animation (or motion performer) by default.
*
* ◆filterParameter
* Parameters to be passed to FilterControllerMZ.js and Pixi.
* However, it may be a bit advanced.
*
* For example, in the case of shockwave,
* 6 parameters are passed as follows.
*
* > filterParameters = [0,0,-1,30,160,1]
* ※Values are default settings for FilterControllerMZ.
*
* But you will have to check the meaning of each value against
* the FilterControllerMZ.js implementation and the Pixi documentation.
* https://filters.pixijs.download/main/docs/PIXI.filters.ShockwaveFilter.html
*
* In practice, the following order is supported,
* so adjust to your liking.
*
* ・center(1): X coordinate correction
* ・center(2): Y coordinate correction
* ・radius: maximum radius (unlimited below 0)
* ・amplitude: intensity of fluctuation
* ・wavelength: magnitude of fluctuation
* ・Brightness: brightness of the shock wave
*
* The top two need not be changed basically
* because "filterX" and "filterY" need only be specified.
*
* By the way, since default values are used even if not entered,
* unnecessary items may be left blank as shown below.
* > filterParameters = [,,,,,0]
*
* ◆filterId
* ID to operate the filter effect.
* The ID can be a number or a string,
* but if it is a string, enclose it in "".
*
* Note that this is not necessary if the following deletion
* or other operations are not performed.
* ※For shockwave, it will disappear automatically
* after a period of time, except when the speed is 0.
*
* ◆filterErase
* Delete the effect of the specified "filterId".
* For example, the flow is as follows.
* -------------------------------------------------------------------
*
* filterId = 1
* filterType = godray
*
*
*
* filterErase = 1
*
* -------------------------------------------------------------------
* Also, setting "filterErase = true" will delete all effects.
* Please note that this applies
* to all effects called by FilterControllerMZ.js.
*
* @------------------------------------------------------------------
* @ [Plugin Parameters]
* @------------------------------------------------------------------
*/
/*:ja
* @target MZ
* @plugindesc v1.00 PixiのエフェクトをDynamic系プラグインから呼び出します。
* @author 砂川赳(http://newrpg.seesaa.net/)
* @base FilterControllerMZ
* @base NRP_DynamicAnimationMZ
* @orderAfter NRP_DynamicAnimationMZ
* @url http://newrpg.seesaa.net/article/487983241.html
*
* @help DynamicAnimation&Motionプラグインから、
* Pixiのフィルターエフェクト機能を呼び出します。
* ※PixiとはツクールMV~MZの標準で使用しているライブラリのことです。
*
* FilterControllerMZ.js(Tsukimi様)の機能を経由しているため、
* こちらのプラグインも必須となります。
* https://forum.tkool.jp/index.php?threads/4306/
*
* -------------------------------------------------------------------
* ■使用方法
* -------------------------------------------------------------------
* 適用すれば、DynamicAnimationおよびMotionプラグインから
* 簡単に呼び出せるようになります。
*
* 最も扱いやすいエフェクトは『shockwave(衝撃波)』です。
* ……というか、それ以外を戦闘に組み込むのは難しいので、
* 以降の解説もそれを前提にします。
*
* ◆DynamicAnimation
* 例えば、以下でアニメーションと同時に衝撃波のエフェクトが表示されます。
* ※アニメーションが不要なら画像を設定しなければOKです。
* ※標準ではアニメーションの始点にエフェクトを表示します。
* -------------------------------------------------------------------
*
* filterType = shockwave
*
* -------------------------------------------------------------------
*
* ◆DynamicMotion
* DynamicMotionの場合も同じです。
* ※標準ではモーション実行者側にエフェクトを表示します。
* -------------------------------------------------------------------
*
* filterType = shockwave
*
* -------------------------------------------------------------------
*
* -------------------------------------------------------------------
* ■パラメータ
* -------------------------------------------------------------------
* パラメータを指定することでエフェクトを調整できます。
* 大半のパラメータはFilterControllerMZ.jsに準じますので、
* 詳細はそちらの解説をご確認ください。
*
* パラメータは以下のように指定します。
* -------------------------------------------------------------------
*
* filterType = shockwave // エフェクトの種類
* filterTarget = Battlers // エフェクト対象
* filterX = b.width / 2 // X座標
* filterY = b.height / 2 // Y座標
* filterParameters = [0,0,-1,30,160,1] // X,Y,半径,振幅,波長,明るさ
* filterId = 1 // ID
*
* -------------------------------------------------------------------
* 詳細は下をご覧ください。
*
* ◆filterType
* フィルターエフェクトの種類です。
* 基本的には『shockwave』を使っていけばよいと思います。
*
* ◆filterTarget
* エフェクトをかける対象です。
* 標準では全画面を対象としますが、その他にも以下が使用できます。
*
* ・Battlers:バトラーのみ
* ・Battleback:戦闘背景のみ
* ・FullScreenWithWindow:全画面(ウィンドウ含む)
*
* ※BattlersおよびBattlebackの指定は、当プラグインで追加した機能です。
* ※Battlersを指定した場合は原点が、バトラーの左上になります。
* 座標を変更する場合はご注意ください。
*
* ◆filterSpeed
* エフェクトの速度です。
* shockwaveの場合は衝撃波が広がる速度になります。
* shockwaveの標準値は『0.01』なので、その辺りを基準にしてください。
* うっかり『1』などを入力すると、早すぎて見えなくなります。
*
* また『0』にした場合はその場に残りますので、
* 後で削除を行う必要があります。
*
* ◆filterX
* ◆filterY
* エフェクトを表示するX座標、Y座標です。
* 標準ではアニメーションの始点(もしくはモーション実行者)に
* 表示されるため省略しても構いません。
*
* ◆filterParameter
* FilterControllerMZ.jsおよびPixiに渡すパラメータですが、
* 少し上級者向けかもしれません。
*
* 例えば、shockwaveの場合、以下のように6つのパラメータを渡しています。
*
* > filterParameters = [0,0,-1,30,160,1]
* ※値はFilterControllerMZの標準値
*
* ……が、それぞれの値の意味は、FilterControllerMZ.jsの実装と、
* Pixiのドキュメントを照らし合わせないと分からないと思います。
* https://filters.pixijs.download/main/docs/PIXI.filters.ShockwaveFilter.html
*
* 実際には以下の順番で対応していますので、お好みで調整してください。
*
* ・center(1):X座標補正
* ・center(2): Y座標補正
* ・radius:最大半径(0以下で無制限)
* ・amplitude:振幅(揺らぎの強さ)
* ・wavelength:波長(揺らぎの大きさ)
* ・brightness:明るさ
*
* 上2つは『filterX』『filterY』を指定すればよいので基本は変更不要です。
*
* ちなみに未入力の場合も標準値が使用されるため、
* 不要な項目は以下のように空白にしても構いません。
* > filterParameters = [,,,,,0]
*
* ◆filterId
* フィルターエフェクトを操作するためのIDです。
* IDは数値でも文字列でも構いませんが、文字列の場合は""で囲ってください。
*
* なお、以下の削除などの操作を行わない場合は不要です。
* ※shockwaveについては、速度が0の場合を除いて、
* 時間経過で自動的に消滅します。
*
* ◆filterErase
* 指定した『filterId』のエフェクトを削除します。
* 例えば、以下のような流れになります。
* -------------------------------------------------------------------
*
* filterId = 1
* filterType = godray
*
*
*
* filterErase = 1
*
* -------------------------------------------------------------------
* また『filterErase = true』にすると、全てのエフェクトを削除します。
* FilterControllerMZ.jsで呼び出した全てのエフェクトが
* 対象になるので、ご注意ください。
*
* -------------------------------------------------------------------
* ■利用規約
* -------------------------------------------------------------------
* 特に制約はありません。
* 改変、再配布自由、商用可、権利表示も任意です。
* 作者は責任を負いませんが、不具合については可能な範囲で対応します。
*
* @------------------------------------------------------------------
* @ プラグインパラメータ
* @------------------------------------------------------------------
*/
(function() {
"use strict";
function toBoolean(val, def) {
// 空白なら初期値を返す
if (val === "" || val === undefined) {
return def;
// 既にboolean型なら、そのまま返す
} else if (typeof val === "boolean") {
return val;
}
// 文字列ならboolean型に変換して返す
return val.toLowerCase() == "true";
}
function toNumber(str, def) {
if (str == undefined || str == "") {
return def;
}
return isNaN(str) ? def : +(str || def);
}
function setDefault(str, def) {
if (str == undefined || str == "") {
return def;
}
return str;
}
/**
* ●構造体(二重配列)をJSで扱えるように変換
*/
function parseStruct2(arg) {
var ret = [];
if (arg) {
JSON.parse(arg).forEach(function(str) {
ret.push(JSON.parse(str));
});
}
return ret;
}
const PLUGIN_NAME = "NRP_DynamicPixiFilter";
const parameters = PluginManager.parameters(PLUGIN_NAME);
//-----------------------------------------------------------------------------
// DynamicAnimation(NRP_DynamicAnimationMZ.js)
//-----------------------------------------------------------------------------
/**
* ●評価実行(アニメーションを表示する直前に実行される)
*/
const _DynamicAnimation_evaluate = DynamicAnimation.prototype.evaluate;
DynamicAnimation.prototype.evaluate = function (spriteAnimation) {
_DynamicAnimation_evaluate.apply(this, arguments);
const base = this.baseAnimation;
// フィルタータイプとフィルター削除が未設定の場合は処理しない
if (!base.filterType && !base.filterErase) {
return;
}
// eval参照用
const a = this.referenceSubject;
const b = this.referenceTarget;
const ba = base;
const da = this;
const no = this.no;
const r = this.r;
const targetNo = this.targetNo;
const position = this.position;
const mirroring = this.mirroring;
const screenX = this.screenX;
const screenY = this.screenY;
const defaultX = this.defaultX;
const defaultY = this.defaultY;
const sx = this.sx;
const sy = this.sy;
const ex = this.ex;
const ey = this.ey;
// 座標を取得
let filterX = sx;
let filterY = sy;
//-----------------------------------------------------------
// 以下はDynamicAnimation&Motionで共通
//-----------------------------------------------------------
// 削除する場合
if (base.filterErase) {
const erase = eval(base.filterErase);
// trueなら全削除
if (erase === true) {
$gameMap._filterConArr.forEach(fc => fc.erase());
}
// 指定IDを削除
$gameMap.eraseFilter(erase);
return;
}
// IDを設定(未設定時は実行時刻)
const filterId = eval(setDefault(base.filterId, performance.now()));
const filterType = base.filterType;
const filterTarget = base.filterTarget || "FullScreen";
const filterTargetIds = makeTargesId(base.targets);
const posRefTargetId = null;
// 対象がバトラーの場合は対象中央
// ※バトラーの左上が原点となる。
if (filterTarget == "Battlers") {
filterX = b.width / 2;
filterY = b.height / 2;
}
// 指定があれば取得
filterX = eval(setDefault(base.filterX, filterX));
filterY = eval(setDefault(base.filterY, filterY));
// フィルター生成
$gameMap.createFilter(filterId, filterType, filterTarget, filterTargetIds, posRefTargetId);
// フィルターコントローラを取得
const fc = $gameMap.getFilterController(filterId);
fc.setForcePosition(filterX, filterY);
// フィルター更新速度設定
if (base.filterSpeed != null) {
const filterSpeed = eval(base.filterSpeed);
$gameMap.setFilterAddiTime(filterId, filterSpeed);
}
// フィルターパラメータ設定
if (base.filterParameters != null) {
const filterParams = eval(base.filterParameters);
$gameMap.setFilter(filterId, filterParams);
}
}
//-----------------------------------------------------------------------------
// DynamicMotion(NRP_DynamicMotionMZ.js)
//-----------------------------------------------------------------------------
/**
* 【独自】動的モーションの呼び出し
* ※マップ版と共有するためSpriteに定義する。
*/
const _Sprite_startDynamicMotion = Sprite.prototype.startDynamicMotion;
Sprite.prototype.startDynamicMotion = function(dynamicMotion) {
_Sprite_startDynamicMotion.apply(this, arguments);
const base = dynamicMotion.baseMotion;
// フィルタータイプとフィルター削除が未設定の場合は処理しない
if (!base.filterType && !base.filterErase) {
return;
}
// 実行用のモーション情報
const motion = this._setDynamicMotion;
// eval参照用
const dm = base;
const a = dm.referenceSubject;
const b = motion._referenceTarget;
const repeat = dm.repeat;
const r = dm.r;
const position = dm.position;
const screenX = motion._screenX;
const screenY = motion._screenY;
const defaultX = motion._defaultX;
const defaultY = motion._defaultY;
const performerNo = dm.performerNo;
const targetNo = dm.targetNo;
const mirroring = motion._mirroring;
const sx = motion._sx;
const sy = motion._sy;
const ex = motion._ex;
const ey = motion._ey;
// 座標を取得
let filterX = a.x;
let filterY = a.y - a.height / 2;
//-----------------------------------------------------------
// 以下はDynamicAnimation&Motionで共通
//-----------------------------------------------------------
// 削除する場合
if (base.filterErase) {
const erase = eval(base.filterErase);
// trueなら全削除
if (erase === true) {
$gameMap._filterConArr.forEach(fc => fc.erase());
}
// 指定IDを削除
$gameMap.eraseFilter(erase);
return;
}
// IDを設定(未設定時は実行時刻)
const filterId = eval(setDefault(base.filterId, performance.now()));
const filterType = base.filterType;
const filterTarget = base.filterTarget || "FullScreen";
const filterTargetIds = makeTargesId(base.targets);
const posRefTargetId = null;
// 対象がバトラーの場合は対象中央
// ※バトラーの左上が原点となる。
if (filterTarget == "Battlers") {
filterX = b.width / 2;
filterY = b.height / 2;
}
// 指定があれば取得
filterX = eval(setDefault(base.filterX, filterX));
filterY = eval(setDefault(base.filterY, filterY));
// フィルター生成
$gameMap.createFilter(filterId, filterType, filterTarget, filterTargetIds, posRefTargetId);
// フィルターコントローラを取得
const fc = $gameMap.getFilterController(filterId);
fc.setForcePosition(filterX, filterY);
// フィルター更新速度設定
if (base.filterSpeed != null) {
const filterSpeed = eval(base.filterSpeed);
$gameMap.setFilterAddiTime(filterId, filterSpeed);
}
// フィルターパラメータ設定
if (base.filterParameters != null) {
const filterParams = eval(base.filterParameters);
$gameMap.setFilter(filterId, filterParams);
}
}
//-----------------------------------------------------------------------------
// Filter_Controller(FilterControllerMZ.js)
//-----------------------------------------------------------------------------
/**
* 【独自】フィルターの表示位置を強制的に上書き
*/
Filter_Controller.prototype.setForcePosition = function(x, y) {
this._forceX = x;
this._forceY = y;
};
/**
* 【独自】フィルターの対象を強制的に上書き
*/
Filter_Controller.prototype.setForceTargets = function(targets) {
this._forceTargets = targets;
};
/**
* ●位置取得
*/
const _Filter_Controller_getCharLoc = Filter_Controller.prototype.getCharLoc;
Filter_Controller.prototype.getCharLoc = function() {
// 座標指定があれば優先使用
if (this._forceX != null) {
return [this._forceX, this._forceY];
}
return _Filter_Controller_getCharLoc.apply(this, arguments);
};
// targetTypeにBattlers, Battlebackを追加
Filter_Controller.targetType["Battlers"] = "Battlers";
Filter_Controller.targetType["Battleback"] = "Battleback";
const Type = Filter_Controller.targetType;
const targetGetter = Filter_Controller.targetGetter;
/**
* 【独自】対象にBattlersを追加
*/
targetGetter[Type.Battlers] = function(targetIds) {
// 対象が指定されている場合は取得して終了
if (targetIds) {
const targets = reverseTargesId(targetIds);
return targets.map(target => getBattlerSprite(target));
}
const targets = [];
if (this._spriteset) {
this._spriteset.battlerSprites().forEach(sprite => targets.push(sprite));
}
return targets;
};
/**
* 【独自】対象にBattlebackを追加
*/
targetGetter[Type.Battleback] = function(targetIds) {
const targets = [];
if (this._spriteset) {
targets.push(this._spriteset._back1Sprite);
targets.push(this._spriteset._back2Sprite);
}
return targets;
};
//-----------------------------------------------------------------------------
// 共通関数
//-----------------------------------------------------------------------------
/**
* ●対象を対象IDの配列に変換
*/
function makeTargesId(targets) {
// 戦闘時以外は無視
if (!$gameParty.inBattle()) {
return null;
}
const targetsId = [];
for (const target of targets) {
// 敵の場合はインデックス+1
if (target.isEnemy()) {
targetsId.push(target.index() + 1);
// アクターの場合は*-1
} else {
targetsId.push((target.index() + 1) * -1);
}
}
return targetsId;
}
/**
* ●対象IDを対象の配列に変換
*/
function reverseTargesId(targetsId) {
const targets = [];
for (const targetId of targetsId) {
// アクターの場合
if (targetId < 0) {
targets.push($gameParty.members()[(targetId * -1) - 1]);
// 敵キャラの場合
} else {
targets.push($gameTroop.members()[targetId - 1]);
}
}
return targets;
}
/**
* ●指定したバトラーのスプライトを取得する。
*/
function getBattlerSprite(battler) {
if (!battler) {
return undefined;
}
var sprites;
const spriteset = getSpriteset();
// 戦闘中はバトラースプライトを返す。
if ($gameParty.inBattle()) {
sprites = spriteset.battlerSprites();
// マップ上ではキャラクタースプライトを返す。
} else {
sprites = spriteset._characterSprites;
}
// 一致があれば返す
return sprites.find(s => s._battler == battler || s._character == battler);
}
/**
* ●現在の画面のSpritesetを取得する。
*/
function getSpriteset() {
return SceneManager._scene._spriteset;
}
})();