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

372 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//=============================================================================
// RPG Maker MZ - Sprite_Scrollable
//
// 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 DebugSwitch
* @base Sprite_InputHandle
* @orderAfter DebugSwitch
* @orderAfter Sprite_InputHandle
*
* @param comment
* @text 備考欄
* @desc プラグイン側では使用しません。
* メモ欄としてお使いください。
* @type multiline_string
* @default
*
* @help Sprite_Scrollable.js
*
* Version: 0.0.1
*
* 内部のDisplayObjectの展開領域に関わらず固定の表示領域にクロップするSpriteです。
*/
(() => {
"use strict";
//========================================================================
// プラグイン定義
//========================================================================
const pluginName = "Sprite_Scrollable";
const script = document.currentScript;
const param = PluginManagerEx.createParameter(script);
//========================================================================
// 定数定義
//========================================================================
//========================================================================
// コアスクリプト変更部 (Sprite)
//========================================================================
//========================================================================
// クラス定義 (Sprite_Scrollable)
//========================================================================
class Sprite_Scrollable extends Sprite_InputHandle {
constructor(width, height, mask) {
super();
this.reservedMask = mask;
this.container = new Sprite();
this.container.zIndex = 10;
this.addChildToRoot(this.container);
this.innerRect = null;
this.overallRect = this.container.getBounds();
this.mergin = null;
this.setMergin(0, 0, 0, 0);
this.setFrame(0, 0, width, height);
this._enableInput = true;
this._enableScroll = true;
this._enableScrollX = true;
this._enableScrollY = true;
this._limitInBounds = true;
this._scrollX = 0;
this._scrollY = 0;
this.clearScrollStatus();
}
clearScrollStatus() {
this._scrollTargetX = 0;
this._scrollTargetY = 0;
this._scrollDuration = 0;
this._scrollAccelX = 0;
this._scrollAccelY = 0;
this._scrollTouching = false;
this._scrollLastTouchX = 0;
this._scrollLastTouchY = 0;
}
setFrame(x, y, width, height) {
super.setFrame(x, y, width, height);
this.innerRect = new Rectangle(x, y, width, height);
let mask = this.reservedMask;
if (!mask) {
mask = new Sprite(new Bitmap(width, height));
mask.bitmap.fillAll('#FFFFFF');
}
if (!!this.mask) {
this.removeChild(this.mask);
}
super.addChild(mask);
this.mask = mask;
}
getBounds(skipUpdate, rect) {
// transformの更新のため呼び出し結果は捨てる
this.container.getBounds();
const b = super.getBounds(skipUpdate);
const bounds = !!this.innerRect ? this.innerRect : new Rectangle(this.x, this.y, b.width, b.height);
bounds.x = this.x;
bounds.y = this.y;
if (!!rect) {
rect.x = bounds.x;
rect.y = bounds.y;
rect.width = bounds.width;
rect.height = bounds.height;
return rect;
} else {
return bounds;
}
}
enableInput(enable) {
this._enableInput = enable;
}
enableScroll(enable) {
this._enableScroll = enable;
}
enableScrollX(enable) {
this._enableScrollX = enable;
}
enableScrollY(enable) {
this._enableScrollY = enable;
}
enableLimit(enable) {
this._limitInBounds = enable;
}
setMergin(left, top, right, bottom) {
this.mergin = {
top: top,
bottom: bottom,
left: left,
right: right,
};
}
scrollX() {
return this._scrollX;
}
scrollY() {
return this._scrollY;
}
scrollTo(x, y) {
const scrollX = this._limitInBounds ? x.clamp(-this.mergin.left, this.maxScrollX()) : x;
const scrollY = this._limitInBounds ? y.clamp(-this.mergin.top, this.maxScrollY()) : y;
if (this._scrollX !== scrollX || this._scrollY !== scrollY) {
if (this._enableScrollX) {
this._scrollX = scrollX;
}
if (this._enableScrollY) {
this._scrollY = scrollY;
}
this.updateOrigin();
}
}
scrollBy(x, y) {
this.scrollTo(this._scrollX + x, this._scrollY + y);
}
smoothScrollTo(x, y, duration) {
this._scrollTargetX = this._limitInBounds ? x.clamp(0, this.maxScrollX()) : x;
this._scrollTargetY = this._limitInBounds ? y.clamp(0, this.maxScrollY()) : y;
this._scrollDuration = duration || Input.keyRepeatInterval;
}
smoothScrollBy(x, y, duration) {
if (this._scrollDuration === 0) {
this._scrollTargetX = this.scrollX();
this._scrollTargetY = this.scrollY();
}
this.smoothScrollTo(this._scrollTargetX + x, this._scrollTargetY + y, duration);
}
setScrollAccel(x, y) {
this._scrollAccelX = x;
this._scrollAccelY = y;
}
overallWidth() {
return this.overallRect.width + this.mergin.left + this.mergin.right;
}
overallHeight() {
return this.overallRect.height + this.mergin.top + this.mergin.bottom;
}
maxScrollX() {
return Math.max(0, this.overallWidth() - this.innerRect.width);
}
maxScrollY() {
return Math.max(0, this.overallHeight() - this.innerRect.height);
}
update() {
super.update();
this.overallRect = this.container.getBounds();
if (!this._enableScroll) {
return;
}
if (this._enableInput) {
this.processWheelScroll();
this.processTouchScroll();
}
this.updateSmoothScroll();
this.updateScrollAccel();
this.updateOrigin();
}
processWheelScroll() {
if (this.isWheelScrollEnabled() && this.isTouchedInsideFrame()) {
const threshold = 20;
if (TouchInput.wheelY >= threshold || TouchInput.wheelY <= -threshold) {
this.smoothScrollBy(0, TouchInput.wheelY);
}
}
}
processTouchScroll() {
if (this.isTouchScrollEnabled()) {
if (TouchInput.isTriggered() && this.isTouchedInsideFrame()) {
this.onTouchScrollStart();
}
if (this._scrollTouching) {
if (TouchInput.isReleased()) {
this.onTouchScrollEnd();
} else if (TouchInput.isMoved()) {
this.onTouchScroll();
}
}
}
}
isWheelScrollEnabled() {
return this.isScrollEnabled();
}
isTouchScrollEnabled() {
return this.isScrollEnabled();
}
isScrollEnabled() {
return true;
}
isTouchedInsideFrame() {
// transformの更新結果は捨てる
this.getBounds();
// スクロール量の補正をかける
const touchPos = new Point(TouchInput.x, TouchInput.y + this.container.y);
const localPos = this.worldTransform.applyInverse(touchPos);
const rect = super.getBounds(false);
const start = this.worldTransform.applyInverse(new Point(rect.x, rect.y));
const frame = new Rectangle(start.x, start.y, this.innerRect.width, this.innerRect.height);
return frame.contains(localPos.x, localPos.y);
}
onTouchScrollStart() {
this._scrollTouching = true;
this._scrollLastTouchX = TouchInput.x;
this._scrollLastTouchY = TouchInput.y;
this.setScrollAccel(0, 0);
}
onTouchScroll() {
let accelX = this._scrollLastTouchX - TouchInput.x;
if (this.overallWidth() <= this.width) {
accelX = 0;
}
let accelY = this._scrollLastTouchY - TouchInput.y;
if (this.overallHeight() <= this.height) {
accelY = 0;
}
this.setScrollAccel(-accelX, accelY);
this._scrollLastTouchX = TouchInput.x;
this._scrollLastTouchY = TouchInput.y;
}
onTouchScrollEnd() {
this._scrollTouching = false;
}
updateSmoothScroll() {
if (this._scrollDuration > 0) {
const d = this._scrollDuration;
const deltaX = (this._scrollTargetX - this._scrollX) / d;
const deltaY = (this._scrollTargetY - this._scrollY) / d;
this.scrollBy(deltaX, deltaY);
this._scrollDuration--;
}
}
updateScrollAccel() {
if (this._scrollAccelX !== 0 || this._scrollAccelY !== 0) {
this.scrollBy(this._scrollAccelX, this._scrollAccelY);
this._scrollAccelX *= 0.92;
this._scrollAccelY *= 0.92;
if (Math.abs(this._scrollAccelX) < 1) {
this._scrollAccelX = 0;
}
if (Math.abs(this._scrollAccelY) < 1) {
this._scrollAccelY = 0;
}
}
}
updateOrigin() {
this.container.x = this._scrollX;
this.container.y = -this._scrollY;
}
addChild(child) {
this.container.addChild(child);
}
addChildAt(child, index) {
this.container.addChildAt(child, index);
}
removeChild(child) {
return this.container.removeChild(child);
}
removeChildAt(index) {
return this.container.removeChildAt(index);
}
removeChildren(beginIndex, endIndex) {
return this.container.removeChildren(beginIndex, endIndex);
}
swapChildren(child, child2) {
return this.container.swapChildren(child, child2);
}
calculateBounds() {
super.calculateBounds();
this.overallRect = this.container.getBounds();
}
addChildToRoot(child) {
super.addChild(child);
super.sortChildren();
}
}
window.Sprite_Scrollable = Sprite_Scrollable;
})();