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

362 lines
11 KiB
JavaScript

//=============================================================================
// RPG Maker MZ - Sprite_InputHandle
//
// 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 AsyncLoadImage
* @base SmartAnimation
* @orderAfter DebugSwitch
* @orderAfter AsyncLoadImage
* @orderAfter SmartAnimation
*
* @param comment
* @text 備考欄
* @desc プラグイン側では使用しません。
* メモ欄としてお使いください。
* @type multiline_string
* @default
*
* @help Sprite_InputHandle.js
*
* Version: 0.0.1
*
* 内部のDisplayObjectの展開領域に関わらず固定の表示領域にクロップするSpriteです。
*/
(() => {
"use strict";
//========================================================================
// プラグイン定義
//========================================================================
const pluginName = "Sprite_InputHandle";
const script = document.currentScript;
const param = PluginManagerEx.createParameter(script);
//========================================================================
// 定数定義
//========================================================================
//========================================================================
// クラス定義 (Sprite_InputHandle)
//========================================================================
class Sprite_InputHandle extends Sprite {
constructor(bitmap) {
super(bitmap);
this._enterListeners = [];
this._hoverListeners = [];
this._pressed = false;
this._hovered = false;
this._isTouchEnabled = true;
this._isKeepEntryUntilDragging = false;
this._excludeTransparentPixel = false;
this._lastSnappedChildren = 0;
this._snap = null;
}
onHandleEnter() {
if (this.isTouchEnabled()) {
this._fireEnter(this._name);
}
}
onPressed(pressed) {
}
onPointerEntry(entry) {
if (this.isTouchEnabled()) {
this._fireHover(this._name, entry);
}
}
addEnterListener(listener) {
if (!!listener && typeof listener === 'function') {
this._enterListeners.push(listener);
}
}
removeEnterListener(listener) {
this._enterListeners = this._enterListeners.filter(l => l !== listener);
}
addHoverListener(listener) {
if (!!listener && typeof listener === 'function') {
this._hoverListeners.push(listener);
}
}
removeHoverListener(listener) {
this._hoverListeners = this._hoverListeners.filter(l => l !== listener);
}
update() {
super.update();
this.updateSnap();
this.processTouch();
}
isTouchEnabled() {
return this.worldVisible && this.isTouchEnable();
}
enableTouch(value) {
this._isTouchEnabled = value;
}
isTouchEnable() {
return this._isTouchEnabled;
}
isKeepEntryUntilDragging() {
return this._isKeepEntryUntilDragging;
}
isPressed() {
return this._pressed;
}
isHovered() {
return this._hovered;
}
isBeingTouched() {
const touchPos = new Point(TouchInput.x, TouchInput.y);
const localPos = this.worldTransform.applyInverse(touchPos);
return this.hitTest(localPos.x, localPos.y);
}
createSnap() {
const width = this.width;
const height = this.height;
const bitmap = new Bitmap(width, height);
const renderTexture = PIXI.RenderTexture.create(width, height);
const renderer = Graphics.app.renderer;
renderer.render(this, renderTexture);
this.worldTransform.identity();
const canvas = renderer.extract.canvas(renderTexture);
bitmap.context.drawImage(canvas, 0, 0);
canvas.width = 0;
canvas.height = 0;
renderTexture.destroy({ destroyBase: true });
bitmap.baseTexture.update();
this._lastSnappedChildren = this.children.length;
return bitmap;
}
getSnap() {
if (!this._snap || (this.children.length !== this._lastSnappedChildren)) {
this._snap = this.createSnap();
}
return this._snap;
}
updateSnap() {
if (this._excludeTransparentPixel) {
const childrenSize = this.children.length;
if (childrenSize !== this._lastSnappedChildren) {
this._snap = this.createSnap();
}
}
}
hitTest(x, y) {
const rect = new Rectangle(
-this.anchor.x * this.width,
-this.anchor.y * this.height,
this.width,
this.height
);
if (this._excludeTransparentPixel === true) {
if (rect.contains(x, y)) {
const snap = this.getSnap();
const alpha = snap.getAlphaPixel(x, y);
snap.destroy();
return alpha > 0;
} else {
return false;
}
} else {
return rect.contains(x, y);
}
}
isIncludeOnParentFrame() {
if (this.worldVisible === false) {
return false;
}
let item = this.parent;
while (!!item) {
if (item instanceof Sprite_Scrollable) {
if (!item.isTouchedInsideFrame()) {
return false;
}
}
item = item.parent;
}
return true;
}
processTouch() {
if (this.isTouchEnabled()) {
if (this.isBeingTouched() || (this.isKeepEntryUntilDragging() && this.isPressed())) {
if (!this._hovered && TouchInput.isHovered()) {
this._hovered = true;
this.onPointerEntry(true);
}
if (TouchInput.isTriggered()) {
this.onPressed(true);
this._pressed = true;
}
} else {
if (this._hovered) {
this.onPointerEntry(false);
}
this._pressed = false;
this._hovered = false;
}
if (this._pressed && TouchInput.isReleased() && this.isIncludeOnParentFrame()) {
this.onHandleEnter();
this.onPressed(false);
this._pressed = false;
}
} else {
if (this._pressed) {
this.onPressed(false);
this._pressed = false;
}
if (this._hovered) {
this.onPointerEntry(false);
this._hovered = false;
}
}
}
_checkTouchInput() {
const point = this.toLocal(new Point(TouchInput.x, TouchInput.y));
const bounds = this.getLocalBounds();
return bounds.contains(point.x, point.y);
}
_fireEnter() {
this._enterListeners.forEach(listener => {
listener(this);
})
}
_fireHover(inEntry) {
this._hoverListeners.forEach(listener => {
listener(this, inEntry);
})
}
enableTransparent(value) {
this._excludeTransparentPixel = !value;
}
canTouchTransparent() {
return !this._excludeTransparentPixel;
}
};
window.Sprite_InputHandle = Sprite_InputHandle;
//========================================================================
// クラス定義 (Sprite_SimpleButton)
//========================================================================
class Sprite_SimpleButton extends Sprite_InputHandle {
constructor(baseBitmap, option) {
super();
this.option = option;
this.setFrame(0, 0, baseBitmap.width, baseBitmap.height);
this.base = new Sprite(baseBitmap);
this.addChild(this.base);
const normalColor = this.getNormalColor();
if (!!normalColor) {
this.base.tint = normalColor;
}
this.content = new Sprite(new Bitmap(baseBitmap.width, baseBitmap.height));
this.content.zIndex = 1;
this.paintContent(this.content.bitmap);
this.addChild(this.content);
this._pressedMask = this.createPressedMask(baseBitmap);
this._pressedMask.zIndex = 2;
this.addChild(this._pressedMask);
this._pressedMask.hide();
this.focused = false;
this.interactive = true;
this.buttonMode = true;
}
paintContent(content) {
// for sub-class override
}
getNormalColor() {
// for sub-class override
return undefined;
}
getFocusColor() {
// for sub-class override
return undefined;
}
createPressedMask(baseBitmap) {
const bitmap = new Bitmap(baseBitmap.width, baseBitmap.height);
const sprite = new Sprite(bitmap);
const mask = new Sprite(baseBitmap);
sprite.addChild(mask);
sprite.mask = mask;
bitmap.paintOpacity = PluginUtils.percent(255, 40);
bitmap.fillAll('#000000');
bitmap.paintOpacity = 255;
return sprite;
}
setFocus(focus) {
if (this.focused !== focus) {
const tint = focus ? this.getFocusColor() : this.getNormalColor();
if (!!tint) {
this.base.tint = tint;
}
}
this.focused = focus;
}
isFocused() {
return this.focused;
}
onPointerEntry(entry) {
super.onPointerEntry(entry);
this.setFocus(entry);
}
onPressed(pressed) {
super.onPressed(pressed);
Logger.d(`onPressed: pressed = ${pressed}`);
this._pressedMask.visible = pressed;
}
}
window.Sprite_SimpleButton = Sprite_SimpleButton;
})();