//============================================================================= // 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; })();