查看: 5755|回复: 4

[原创发布] 滚动窗口

[复制链接]
梦石
0
星屑
755
在线时间
90 小时
注册时间
2017-11-6
回帖
10
发表于 2020-6-13 21:30:34 | 显示全部楼层 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有账号?注册会员

×
本帖最后由 lohengriny 于 2020-6-13 21:33 编辑

纯鼠标操作滚动窗口。包含两个,一个是普通滚动窗口,在窗口区域按住鼠标左键,然后移动鼠标即可滚动内容(仅Y轴)。
另一个是 Selectable 滚动窗口,即普通滚动窗口之外还含有可选择内容(比如物品列表,菜单等)。和普通滚动窗口相比有两个特性:
1. 滚动后不会触发选择。
2. isSelectionMaintained() 该项如果为真,在已经选择一个项时滚动,会保留选择,否者会取消选择。

其他特性:
1.惯性。滚动中松开鼠标,内容会继续滑动一段距离
2.弹性。滚动可以超过上下边界,但是在松开鼠标后回“弹回”边界位置
3.滚动条。 默认显示滚动条,将一个长条图片放到 img/system/window_scroller.png 即可。

代码[pre lang="javascript"]//=============================================================================
// UI_ScrollWindow.js
//=============================================================================
/*:
* @plugindesc Scrollable Window
* @author Hoozuki Araragi
*
* @help This plugin does not provide plugin commands.
*/
class Window_Scroll extends Window_Base {
        /**
         *
         * @param {Number} fX
         * @param {Number} fY
         * @param {Number} fWidth
         * @param {Number} fHeight
         */
    constructor(fX, fY, fWidth, fHeight) {
        super(fX, fY, fWidth, fHeight);
        this._bTouching = false;
        this._bTouched = false;
        this._fScrollX = 0;
        this._fScrollY = 0;
        this._fScrollingX = 0;
        this._fScrollingY = 0;
        this._fScrollOriginX = 0;
        this._fScrollOriginY = 0;
        this._fScrollMaxX = 0;
        this._fScrollMaxY = 0;
        this._fScrollMinX = 0;
        this._fScrollMinY = 0;
        this._fScrollerHeight = 0;
        this._bVertical = true;
        this._bHorizontal = false;
        this._inertia = 0;
        this._lastY = 0;
        this._oHandlers = {};
    }

    static get inertiaAttenuation() {return 0.94;}

    standardPadding() {
        return 2;
    }
    standardPaddingY() {
        return 2;
    }

    move(x, y, w, h) {
        super.move(x, y, w, h);
    }

    /**
     *
     * @param {string} symbol
     * @param {function} method
     */
    setHandler(symbol, method) {
        this._oHandlers[symbol] = method;
    }

    /**
     *
     * @param {string} symbol
     */
    isHandled(symbol) {
        return !!this._oHandlers[symbol];
    }

    /**
     *
     * @param {string} symbol
     */
    callHandler(symbol) {
        if (this.isHandled(symbol)) {
            this._oHandlers[symbol]();
        }
    }

    get scrollBarOffset() {
        return 4;
    }

    get scrollBarWidth() {
        return 4;
    }

    get scrollerHeight() {
        if (this._fScrollerHeight === 0) {
            let l = this._scrollBar.height + this._fScrollMinY / 4;
            this._fScrollerHeight = Math.max(l, 30);
        }
        return this._fScrollerHeight;
    }

    get scrollBarColor() {
        return '#000000';
    }

    get scrollerColor() {
        return '#000000'
    }

    createScrollBar() {
        let bg = new Sprite(new Bitmap(this.scrollBarWidth, this.height - 2 * this.scrollBarOffset));
        bg.bitmap.fillRect(0, 0, this.scrollBarWidth, this.height - 2 * this.scrollBarOffset, this.scrollBarColor);
        this._scrollBar = bg;
        this.addChild(bg);
        bg.move(this.width - this.scrollBarWidth - 4, this.scrollBarOffset);
    }

    createScroller() {
        let l = this.scrollerHeight;
        let item = new Sprite(new Bitmap(this.scrollBarWidth, l));
        item.bitmap.drawItemBox(0, 0, this.scrollBarWidth, l, 'img/system/', 'window_scroller', 0, 2);
        this._scroller = item;
        this.addChild(item);
        item.move(this.width - this.scrollBarWidth - 4, this.scrollBarOffset);
    }

    processTouch() {
        if (TouchInput.isCancelled()) {
            this.processCancel();
        }
    }

    processCancel() {
        if (this.isHandled('cancel')) {
            SoundManager.playCancel();
            this.callHandler('cancel');
        }
    }

    contentsHeight() {
        return this.height - this.standardPaddingY() * 2 - this._fScrollMinY;
    }

    contentsWidth() {
        return this.width - this.standardPadding() * 2 - this._fScrollMinX;
    }

    /**
     *
     * @param fYmax {number}
     * @param fYmin {number}
     * @param fXmax {number}
     * @param fXmin {number}
     */
    setScrollLimit(fYmax, fYmin, fXmax, fXmin) {
        this._fScrollMaxX = fXmax;
        this._fScrollMaxY = fYmax;
        this._fScrollMinX = fXmin;
        this._fScrollMinY = fYmin;
        this.createContents();
        if (fYmin < 0) {
            this.createScrollBar();
            this.createScroller();
        }
    }

    /**
     *
     * @param horz {boolean}
     * @param vert {boolean}
     */
    setScrollDirection(horz, vert) {
        this._bVertical = vert;
        this._bHorizontal = horz;
    }

    get scrollX() {
        return this._fScrollX + this._fScrollingX;
    }

    get scrollY() {
        return this._fScrollY + this._fScrollingY;
    }

    resetScroll() {
        this._fScrollX = 0;
        this._fScrollY = 0;
    }

    update() {
        super.update();
        this.updateTouching();
        this.processScroll();
        this.updateScroll();
        this.updateContentScroll();
        this.updateScrollBar();
        this.processRelease();
        this.processTouch();
    }

    isMouseOver() {
        var x = this.parent.canvasToLocalX? this.parent.canvasToLocalX(TouchInput.x) : TouchInput.x;
        var y = this.parent.canvasToLocalY? this.parent.canvasToLocalY(TouchInput.y) : TouchInput.y;
        return x >= this.x && x <= this.x + this.width && y >= this.y && y <= this.y + this.height;
    }

    updateTouching() {
        if (this.active) {
            if (TouchInput.isPressed() && this.isMouseOver()) {
                if (!this._bTouching) {
                    this._fScrollOriginX = TouchInput.x;
                    this._fScrollOriginY = TouchInput.y;
                }
                this._bTouching = true;
                this._bTouched = true;
            } else {
                this._bTouching = false;
                if (this._inertia > 1 || this._inertia < -1) {
                    this._fScrollY += this._inertia;
                    this._inertia = this._inertia * Window_Scroll.inertiaAttenuation;
                }
            }
        } else {
            this._bTouching = false;
        }
    }

    processRelease() {
        if (this.active) {
            if (!this._bTouching && this._bTouched) {
                this._fScrollX += this._fScrollingX;
                this._fScrollY += this._fScrollingY;
                this._fScrollingX = 0;
                this._fScrollingY = 0;
                this._bTouched = false;
            }
        } else {
            this._bTouching = false;
        }
    }

    processScroll() {
        if (this.active) {
            if (this._bTouching){
                let x = TouchInput.x;
                let y = TouchInput.y;
                this._bHorizontal? this._fScrollingX = x - this._fScrollOriginX : this._fScrollingX = 0;
                this._bVertical? this._fScrollingY = y - this._fScrollOriginY : this._fScrollingY = 0;
                this._inertia = y - this._lastY;
                this._lastY = y;
            }
        }
    }

    updateScroll() {
        if (this._fScrollX > this._fScrollMaxX) {
            this._fScrollX -= (this._fScrollX - this._fScrollMaxX) / 3;
            if (this._fScrollX - this._fScrollMaxX < 1) this._fScrollX = this._fScrollMaxX;
        }
        if (this._fScrollY > this._fScrollMaxY) {
            this._fScrollY -= (this._fScrollY - this._fScrollMaxY) / 3;
            if (this._fScrollY - this._fScrollMaxY < 1) this._fScrollY = this._fScrollMaxY;
        }

        if (this._fScrollX < this._fScrollMinX) {
            this._fScrollX -= (this._fScrollX - this._fScrollMinX) / 3;
            if (this._fScrollMinX - this._fScrollX < 1) this._fScrollX = this._fScrollMinX;
        }
        if (this._fScrollY < this._fScrollMinY) {
            this._fScrollY -= (this._fScrollY - this._fScrollMinY) / 3;
            if (this._fScrollMinY - this._fScrollY < 1) this._fScrollY = this._fScrollMinY;
        }
    }

    updateScrollBar() {
        if (!this._scrollBar) return;
        this._scrollBar.move(this.width - this.scrollBarWidth - 4, this.scrollBarOffset);
        if (this._scroller) {
            let y = this.scrollBarOffset + (this._scrollBar.height - this.scrollerHeight) * this.scrollY / this._fScrollMinY;
            this._scroller.move(this.width - this.scrollBarWidth - 4, y);
            if ( y + this.scrollerHeight > this.height - this.scrollBarOffset) {
                this._scroller.setFrame(0, 0, this.scrollBarWidth, this.height - this.scrollBarOffset - y);
            } else if ( y  < this.scrollBarOffset) {
                this._scroller.move(this.width - this.scrollBarWidth - 4, this.scrollBarOffset);
                this._scroller.setFrame(0, this.scrollBarOffset, this.scrollBarWidth, this.scrollerHeight - (this.scrollBarOffset - y));
            } else {
                this._scroller.setFrame(0, 0, this.scrollBarWidth, this.scrollerHeight);
            }
        }
    }

    updateContentScroll() {
        this.origin.x = -this.scrollX;
        this.origin.y = -this.scrollY;
    }
}

class Window_SelectableScroll extends Window_Scroll {
    constructor(x, y, w, h) {
        super(x, y, w, h);
        this._index = -1;
    }

    get index() {
        return this._index;
    }

    get maxCols() {
        return 1;
    }

    get maxItems() {
        return 0;
    };

    get spacing() {
        return 12;
    }

    get itemWidth() {
        return (this.width - this.standardPadding() * 2) / this.maxCols - this.spacing;
    }

    get itemHeight() {
        return this.lineHeight();
    }

    get maxRows() {
        return Math.max(Math.ceil(this.maxItems / this.maxCols), 1);
    }
    get evaluateScrollLimitY() {
        return Math.min(this.height - (this.itemHeight + this.spacing) * this.maxRows - 2 * this.standardPaddingY(), 0);
    }
    get evaluateScrollLimitX() {
        return Math.min(this.width - (this.itemWidth + this.spacing) * this.maxCols - 2 * this.standardPadding(), 0);
    }
    get itemBox() {
        return ['img/system/', 'itembox', 10];
    }
    get selectedBorder() {
        return ['img/system/', 'itemboxframe', 8];
    }

    /**
     * determine if the selection is maintained while scroll;
     * @returns {boolean}
     */
    isSelectionMaintained() {
        return true;
    }
    /**
     * select indicated index
     * @param {number} index
     */
    select(index) {
        let last_index  = this.index;
        this._index = index;
        this.redrawCurrentItem();
        this.redrawItem(last_index);

    }

    deselect() {
        this.select(-1);
    }

    reselect() {
        this.select(-1);
    }

    /**
     *
     * @param {number} index
     * @return {Rectangle}
     */
    itemRect(index) {
        let rect = new Rectangle();
        let maxCols = this.maxCols;
        rect.width = this.itemWidth;
        rect.height = this.itemHeight;
        rect.x = this.standardPadding() + index % maxCols * (rect.width + this.spacing);
        rect.y = this.standardPaddingY() + Math.floor(index / maxCols) * rect.height;
        return rect;
    }

    itemRectForText(index) {
        let rect = this.itemRect(index);
        rect.x += this.textPadding();
        rect.y += this.textPadding();
        rect.width -= this.textPadding() * 2;
        return rect;
    }

   
    isOpenAndActive() {
        return this.isOpen() && this.active;
    }

    update() {
        super.update();
        this.processHandling();
    }

    processHandling() {
        if (this.isOpenAndActive()) {
            if (this.isOkEnabled() && this.isOkTriggered()) {
                this.processOk();
            } else if (this.isCancelEnabled() && this.isCancelTriggered()) {
                this.processCancel();
            }
        }
    }

    updateTouching() {
        if (this.active) {
            if (TouchInput.isPressed() && this.isMouseOver()) {
                if (!this._bTouching) {
                    this._lastIndex = this.index;
                    this._fScrollOriginX = TouchInput.x;
                    this._fScrollOriginY = TouchInput.y;
                }
                if (this._fScrollingY > 1 || this._fScrollingX > 1) {
                    if (!this.isSelectionMaintained()) this.select(-1);
                } else {
                    let x = this.canvasToLocalX(TouchInput.x);
                    let y = this.canvasToLocalY(TouchInput.y);
                    let index = this.hitTest(x,y);
                    if (index > -1) {
                        this.select(index);
                    }
                }
                this._bTouching = true;
                this._bTouched = true;
            } else {
                this._bTouching = false;
                if (this._inertia > 1 || this._inertia < -1) {
                    this._fScrollY += this._inertia;
                    this._inertia = this._inertia * Window_Scroll.inertiaAttenuation;
                }
            }
        } else {
            this._bTouching = false;
        }
    }

    processRelease() {
        if (this.active) {
            if (!this._bTouching && this._bTouched) {
                this._fScrollX += this._fScrollingX;
                this._fScrollY += this._fScrollingY;
                if (this._fScrollingY === 0 && this._fScrollingX === 0) {
                    this.processClick();
                } else {
                    this.select(-1);
                }
                this._fScrollingX = 0;
                this._fScrollingY = 0;
                this._bTouched = false;

            }
        } else {
            this._bTouching = false;
        }
    }

    processClick() {
        let lastIndex = this.index;
        let x = this.canvasToLocalX(TouchInput.x);
        let y = this.canvasToLocalY(TouchInput.y);
        let hitIndex = this.hitTest(x, y);
        if (hitIndex >= 0) {
            this.select(hitIndex);
            if (hitIndex === this.index) {
                if (this.isOkEnabled()) {
                    this.processOk();
                }
            } else {
                this.select(hitIndex);
            }
        }
    }

    /**
     *
     * @param {number} x
     * @param {number} y
     */
    hitTest(x, y) {
        if (this.isContentsArea(x, y)) {
            let cx = x - this.scrollX - this.standardPadding();
            let cy = y - this.scrollY - this.standardPaddingY();
            for(let i = 0; i < this.maxItems; i++) {
                let rect = this.itemRect(i);
                let right = rect.x + rect.width;
                let bottom = rect.y + rect.height;
                if(cx >= rect.x && cy >= rect.y && cx < right && cy < bottom) {
                    return i;
                }
            }
        }
        return -1;
    }

    /**
     *
     * @param {number} x
     * @param {number} y
     */
    isContentsArea(x, y) {
        let left = this.standardPadding();
        let top = this.standardPaddingY();
        let right = this.width - this.standardPadding();
        let bottom = this.height - this.standardPaddingY();
        return (x >= left && y >= top && x < right && y < bottom);
    }

    isOkEnabled() {
        return this.isHandled('ok');
    }

    isCancelEnabled() {
        return this.isHandled('cancel');
    }
   
    isOkTriggered() {
        return Input.isRepeated('ok');
    }

    isCancelTriggered() {
        return Input.isRepeated('cancel');
    }

    processOk() {
        if (this.isCurrentItemEnabled()) {
            this.playOkSound();
            this.updateInputData();
            this.callOkHandler();
        } else {
            this.playBuzzerSound();
        }
    }

    playBuzzerSound() {
        SoundManager.playBuzzer();
    }

    playOkSound() {
        SoundManager.playOk();
    }

    callOkHandler() {
        this.callHandler('ok');
    }

    processCancel() {
        if(this.isHandled('cancel')) {
            SoundManager.playCancel();
            this.updateInputData();
            this.callCancelHandler();
        }
    }

    callCancelHandler() {
        this.callHandler('cancel');
    }

    updateInputData() {
        Input.update();
        TouchInput.update();
    }

    isCurrentItemEnabled() {
        return true;
    }

    drawAllItems() {
        for (let i = 0; i < this.maxItems; i++) {
            this.drawItem(i);
        }
    }

    /**
     *
     * @param {number} index
     */
    clearItem(index) {
        let rect = this.itemRect(index);
        this.contents.clearRect(rect.x, rect.y, rect.width, rect.height);
    }

    /**
     *
     * @param {number} index
     */
    drawItem(index) {
    }

    /**
     *
     * @param {number} index
     */
    redrawItem(index) {
        if (index >= 0) {
            this.clearItem(index);
            this.drawItem(index);
        }
    }

    redrawCurrentItem() {
        this.redrawItem(this.index);
    }

    updateScrollLimit() {

    }

    refresh() {
        this.updateScrollLimit();
        this.drawAllItems();
    }
}[/pre]

评分

参与人数 6赞 +6 收起 理由
moonyoulove + 1 精品文章
hanyilun + 1 塞糖
白嫩白嫩的 + 1 精品文章
if216 + 1 塞糖
wabcmcc + 1 塞糖
沉滞的剑 + 1 我很赞同

查看全部评分

梦石
0
星屑
7735
在线时间
1227 小时
注册时间
2008-12-14
回帖
504
发表于 2020-6-13 23:14:19 | 显示全部楼层
很丝滑很丝滑很丝滑很丝滑
需要购买本人MV插件必须先加wx好友。加不上wx就是本人忙,没时间卖。原则上太久以前的插件也不想卖,因为我也忘了,维护上会不给力。wx名:alskyif    本人插件地址:
   LCK_SRPG梦幻模拟战、火焰纹章类系统
   究极立绘ADV系统

   究极换装统合系统
   究极! 回想与CG系统
   消息文字的距离调整  
   自动返回上一张地图
回复 0 1

使用道具 举报

梦石
0
星屑
3291
在线时间
350 小时
注册时间
2018-3-28
回帖
189
发表于 2021-1-18 12:46:34 | 显示全部楼层
能问下 这个是怎么使用的么
我用这个创建了新的窗口 但是显示不出什么东西
用mv做了两款游戏,有兴趣的可以瞧一瞧:
《有毛病》--- 休闲、探索、策略、剧情、恐怖 都有那么一些,就是没有战斗。挺骚挺有意思的一个游戏。
steam链接:点击这里


《留离》--- 探索、高自由度、ARPG、战斗,就是没有啥剧情。
steam链接:点击这里
回复

使用道具 举报

梦石
0
星屑
228
在线时间
86 小时
注册时间
2021-10-23
回帖
34
发表于 2021-12-30 14:01:55 | 显示全部楼层
有没有使用教程。不会用呀
回复

使用道具 举报

梦石
0
星屑
228
在线时间
86 小时
注册时间
2021-10-23
回帖
34
发表于 2021-12-30 16:53:05 | 显示全部楼层
本帖最后由 babystudio 于 2021-12-30 16:55 编辑

你的代码里有好多的函数调用没有加(),还有item.bitmap.drawItemBox(0, 0, this.scrollBarWidth, l, 'img/system/', 'window_scroller', 0, 2)是无法在mv中调用的,没有drawItemBox方法
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.

在本版发帖返回顶部