prison-brave/js/plugins/SmartAnimation.js
2025-08-28 10:38:20 -05:00

371 lines
12 KiB
JavaScript

//=============================================================================
// RPG Maker MZ - SmartAnimation
//
// Copyright 2024 Panzer-IV. All rights reserved.
// This source code or any portion thereof must not be
// reproduced or used without licensed in any manner whatsoever.
//=============================================================================
/*:
* @target MZ
* @plugindesc スマートアニメーション
* @author 四号戦車
* @base PluginCommonBase
* @base DebugSwitch
* @base TextResource
* @base PluginUtils
* @orderAfter PluginCommonBase
* @orderAfter DebugSwitch
* @orderAfter TextResource
* @orderAfter PluginUtils
*
* @help SmartAnimation.js
*
* Version: 0.0.33
*
* スマートアニメーションを実装するユーティリティプラグインです。
* フレームに合わせて複数の値を変更できます。
* 他のプラグインで使用する前提です。
*
*/
(() => {
"use strict";
//========================================================================
// プラグイン定義
//========================================================================
const pluginName = "SmartAnimation";
const script = document.currentScript;
const param = PluginManagerEx.createParameter(script);
//========================================================================
// 定数定義 (EasingType)
//========================================================================
const EasingType = {
LINEAR: 'linear',
EASE_IN: 'ease_in',
EASE_OUT: 'ease_out',
EASE_INOUT: 'ease_inout',
};
window.EasingType = Object.freeze(EasingType);
//========================================================================
// クラス定義 (SmartAnimation)
//========================================================================
class SmartAnimation {
constructor(name, object, property, repeat, start, end, callback, easing) {
this.name = name;
this.object = object;
this.startValue = start;
this.endValue = end;
this.targetProperty = property;
this.state = 'ready';
this.repeat = repeat;
if (!!easing) {
this.easing = easing;
} else {
this.easing = EasingType.LINEAR;
}
if (!!callback && typeof callback === 'function') {
this.listener = callback;
} else {
this.listener = null;
}
this.directionReverse = (end < start);
this.currentFrame = 0;
this.currentValue = start;
this.throttle = 0;
this.duration = 0;
this.inSkip = false;
}
setDuration(duration) {
this.duration = duration;
let amount = this.endValue - this.startValue;
if (this.directionReverse) {
amount = this.startValue - this.endValue;
}
this.throttle = Math.abs(amount / duration);
// Logger.d(`setDuration: throttle = ${this.throttle}, duration = ${duration}, amount = ${amount}`);
this.reset();
return this;
}
setThrottle(throttle) {
this.throttle = throttle;
let amount = this.endValue - this.startValue;
if (this.directionReverse) {
amount = this.startValue - this.endValue;
}
this.duration = amount / Math.abs(throttle);
// Logger.d(`setThrottle: throttle = ${throttle}, duration = ${this.duration}, amount = ${amount}`);
this.reset();
return this;
}
getDuration() {
return this.duration;
}
getThrottle() {
return this.throttle;
}
getState() {
return this.state;
}
start() {
this._setState('running');
}
setSkip(skip) {
this.inSkip = skip;
}
stop() {
if (this.state !== 'complete') {
this._setState('stopped');
this._callbackListener(true);
}
}
completeForce() {
if (this.state !== 'complete') {
this.currentFrame = this.duration;
this.update();
}
}
// Game_Picture.prototype.applyEasing = function(current, target) {
// const d = this._duration;
// const wd = this._wholeDuration;
// const lt = this.calcEasing((wd - d) / wd);
// const t = this.calcEasing((wd - d + 1) / wd);
// const start = (current - target * lt) / (1 - lt);
// return start + (target - start) * t;
// };
calcTarget() {
if (this.easing === EasingType.LINEAR) {
return (this.throttle * this.currentFrame);
} else {
const current = this.duration - this.currentFrame;
const lt = this.calcEasing(this.currentFrame / this.duration);
const t = this.calcEasing((this.currentFrame + 1) / this.duration);
}
}
calcEasing(t) {
const exponent = 2;
switch (this.easing) {
case EasingType.EASE_IN:
return Math.pow(t, exponent);
case EasingType.EASE_OUT:
return 1 - Math.pow(1 - t, exponent);
case EasingType.EASE_INOUT:
if (t < 0.5) {
return Math.pow((t * 2), exponent) / 2;
} else {
return (1 - Math.pow(1 - (t * 2 - 1), exponent)) / 2 + 0.5;
}
} // switch
return t;
}
update() {
if (this.state !== 'running') {
return;
}
let target = 0;
if (this.directionReverse) {
const currentValue = this.startValue - (this.throttle * this.currentFrame);
target = Math.max(currentValue, this.endValue);
} else {
const currentValue = this.startValue + (this.throttle * this.currentFrame);
target = Math.min(currentValue, this.endValue);
}
if (!!this.object && !!this.targetProperty) {
this.object[this.targetProperty] = target;
}
this.currentFrame++;
if (this.currentFrame >= this.duration || this.inSkip) {
if (!!this.listener) {
this.listener(this.name);
}
if (!!this.object && !!this.targetProperty) {
this.object[this.targetProperty] = this.endValue;
}
this._setState('complete');
if (this.repeat) {
this.reset();
}
}
}
reset() {
this.currentFrame = 0;
this.state = 'ready';
if (!!this.object && !!this.targetProperty && !!this.object[this.targetProperty]) {
this.object[this.targetProperty] = this.startValue;
}
}
inRunning() {
return this.state === 'running';
}
isComplete() {
return this.state === 'complete';
}
isRepeat() {
return this.repeat;
}
_callbackListener(byAbort) {
if (!!this.listener && typeof this.listener === 'function') {
this.listener(byAbort);
}
}
_setState(newState) {
this.state = newState;
}
}
window.SmartAnimation = SmartAnimation;
//========================================================================
// クラス定義 (SmartAnimationWait)
//========================================================================
class SmartAnimationWait extends SmartAnimation {
constructor(name, duration, callback) {
super(name, null, null, false, 0, 0, callback);
this.setDuration(duration);
}
}
window.SmartAnimationWait = SmartAnimationWait;
//========================================================================
// クラス定義 (SmartAnimationSequencial)
//========================================================================
class SmartAnimationSequencial extends SmartAnimation {
constructor(name, repeat, callback, ...values) {
super(name, null, null, repeat, 0, 0, callback, ...values);
this.values = !!values ? values : [];
this.targetFrame = values.reduce((accum, value) => {
return accum + value.getDuration();
}, 0);
this.currentIndex = 0;
}
update() {
if (this.state !== 'running') {
return;
}
const current = this.values[this.currentIndex];
if (!!current) {
if (current.isComplete()) {
this.currentIndex++;
if (this.currentIndex >= this.values.length) {
this._setState('complete');
this._callbackListener(false);
if (this.repeat) {
this.reset();
this.start();
}
} else {
this.currentValueFrame = 0;
this.values[this.currentIndex].update();
}
} else {
current.update();
}
}
}
reset() {
super.reset();
this.values.forEach(value => value.reset());
this.currentIndex = 0;
}
start() {
super.start();
this.values.forEach(value => value.start());
}
stop() {
super.stop();
this.values.forEach(value => value.stop());
}
}
window.SmartAnimationSequencial = SmartAnimationSequencial;
//========================================================================
// クラス定義 (SmartAnimationParallel)
//========================================================================
class SmartAnimationParallel extends SmartAnimation {
constructor(name, repeat, callback, ...values) {
super(name, null, null, repeat, 0, 0, callback, ...values);
this.values = !!values ? values : [];
this.targetFrame = values.reduce((accum, value) => {
const duration = value.getDuration();
if (accum < duration) {
return duration;
} else {
return accum;
}
}, 0);
this.currentFrame = 0;
}
update() {
if (this.state !== 'running') {
return;
}
this.values
.filter(value => value.isComplete() === false)
.forEach(value => value.update());
this.currentFrame++;
if (this.currentFrame >= this.targetFrame) {
this._setState('complete');
this._callbackListener(false);
if (this.repeat) {
this.reset();
}
}
}
reset() {
super.reset();
this.values.forEach(value => value.reset());
}
start() {
super.start();
this.values.forEach(value => value.start());
}
stop() {
super.stop();
this.values.forEach(value => value.stop());
}
}
window.SmartAnimationParallel = SmartAnimationParallel;
})();