Project1
标题:
RPG Maker MV 的源码研究 其九
[打印本页]
作者:
沉滞的剑
时间:
2019-8-20 06:47
标题:
RPG Maker MV 的源码研究 其九
本帖最后由 沉滞的剑 于 2019-8-20 18:11 编辑
第八章 Window_Selectable
上回说到Window_Base为Window类提供了基础的绘制功能
那么Window_Selectable则提供了基础的交互功能
function Window_Selectable() {
this.initialize.apply(this, arguments);
}
Window_Selectable.prototype = Object.create(Window_Base.prototype);
Window_Selectable.prototype.constructor = Window_Selectable;
Window_Selectable.prototype.initialize = function(x, y, width, height) {
Window_Base.prototype.initialize.call(this, x, y, width, height);
this._index = -1;
this._cursorFixed = false;
this._cursorAll = false;
this._stayCount = 0;
this._helpWindow = null;
this._handlers = {};
this._touching = false;
this._scrollX = 0;
this._scrollY = 0;
this.deactivate();
};
复制代码
首先this._index指的时当前选择的对象的序号, 如果为-1则代表未选中
Window_Selectable.prototype.index = function() {
return this._index;
};
Window_Selectable.prototype.select = function(index) {
this._index = index;
this._stayCount = 0;
this.ensureCursorVisible();
this.updateCursor();
this.callUpdateHelp();
};
Window_Selectable.prototype.deselect = function() {
this.select(-1);
};
Window_Selectable.prototype.reselect = function() {
this.select(this._index);
};
复制代码
this._cursorFixed = false;
this._cursorAll = false;
是光标锁定和选择全体的flag
Window_Selectable.prototype.cursorFixed = function() {
return this._cursorFixed;
};
Window_Selectable.prototype.setCursorFixed = function(cursorFixed) {
this._cursorFixed = cursorFixed;
};
Window_Selectable.prototype.cursorAll = function() {
return this._cursorAll;
};
Window_Selectable.prototype.setCursorAll = function(cursorAll) {
this._cursorAll = cursorAll;
};
复制代码
this._stayCount 是一个计数器, 判断鼠标或触摸是否在菜单上下内边距内按下超过10帧
如果在上边框悬停超过10帧后按下鼠标则选择上一个item(对触摸也有效)
如果在下边框悬停超过10帧后按下鼠标则选择下一个item(对触摸也有效)
Window_Selectable.prototype.update = function() {
...
this._stayCount++;
};
Window_Selectable.prototype.onTouch = function (triggered) {
...
} else if (this._stayCount >= 10) {
if (y < this.padding) {
this.cursorUp();
} else if (y >= this.height - this.padding) {
this.cursorDown();
}
}
...
};
复制代码
很多人都没发现这个功能吧, 可以找标题菜单, 游戏菜单试验一下~
this._helpWindow是说明窗口
这个有专门的类实现这类窗口Window_Helper
我们先简单了解一下在Window_Selectable里的使用
Window_Selectable.prototype.setHelpWindow = function(helpWindow) {
this._helpWindow = helpWindow;
this.callUpdateHelp();
};
Window_Selectable.prototype.showHelpWindow = function() {
if (this._helpWindow) {
this._helpWindow.show();
}
};
Window_Selectable.prototype.hideHelpWindow = function() {
if (this._helpWindow) {
this._helpWindow.hide();
}
};
Window_Selectable.prototype.callUpdateHelp = function() {
if (this.active && this._helpWindow) {
this.updateHelp();
}
};
Window_Selectable.prototype.updateHelp = function() {
this._helpWindow.clear();
};
Window_Selectable.prototype.setHelpWindowItem = function(item) {
if (this._helpWindow) {
this._helpWindow.setItem(item);
}
};
复制代码
这些方法只是helpWindow方法的包装而已
作为一基础类Window_Selectable并没有实际上的helpWindow, 所以这部分等到以后遇到HelpWindow再细讲
this._handlers 是回调函数, 也就是玩家选择后的反馈
Window_Selectable.prototype.setHandler = function(symbol, method) {
this._handlers[symbol] = method;
};
Window_Selectable.prototype.isHandled = function(symbol) {
return !!this._handlers[symbol];
};
Window_Selectable.prototype.callHandler = function(symbol) {
if (this.isHandled(symbol)) {
this._handlers[symbol]();
}
};
复制代码
其实非常简单: 以字典格式存储, 按照key来呼叫方法就好
有一些默认的handler
Window_Selectable.prototype.callOkHandler = function() {
this.callHandler('ok');
};
Window_Selectable.prototype.processCancel = function() {
SoundManager.playCancel();
this.updateInputData();
this.deactivate();
this.callCancelHandler();
};
Window_Selectable.prototype.callCancelHandler = function() {
this.callHandler('cancel');
};
Window_Selectable.prototype.processPageup = function() {
SoundManager.playCursor();
this.updateInputData();
this.deactivate();
this.callHandler('pageup');
};
Window_Selectable.prototype.processPagedown = function() {
SoundManager.playCursor();
this.updateInputData();
this.deactivate();
this.callHandler('pagedown');
};
复制代码
这些为子类提供了一些基础框架
this._touching是触摸状态, 下面是一个子update方法
Window_Selectable.prototype.processTouch = function () {
if (this.isOpenAndActive()) { // 如果窗口可用
if (TouchInput.isTriggered() && this.isTouchedInsideFrame()) { //如果在窗口区域按下鼠标
this._touching = true;
this.onTouch(true); // 触发按下handler
} else if (TouchInput.isCancelled()) { // 如果按下右键/取消键
if (this.isCancelEnabled()) { // 如果有取消handler
this.processCancel(); // 执行取消handler
}
}
if (this._touching) {
if (TouchInput.isPressed()) { // 在按住状态滑过窗口(非触摸双击或左键选择已选择的item)
this.onTouch(false); // 仅触发重新选择而不会出发handler
} else {
this._touching = false;
}
}
} else {
this._touching = false;
}
};
复制代码
this._scrollX 和 this._scrollY指的是菜单卷动的位置
这些纯计算位置的方法就不多说了, 数量太多不过内容只是纯数值计算, 我们以后遇到了再说
说完了初始化, 我们再看看update
Window_Selectable.prototype.update = function () {
Window_Base.prototype.update.call(this);
this.updateArrows(); // 如果菜单高度显示不下, 显示箭头指示玩家下面/上面还有item
this.processCursorMove(); // 键盘事件
this.processHandling(); // 以后再说
this.processWheel(); // 看名字似乎是滚轮, 但是貌似无用
this.processTouch(); // 鼠标/触摸事件
this._stayCount++;
};
复制代码
键盘事件, 支持上下左右和上下翻页
Window_Selectable.prototype.processCursorMove = function () {
if (this.isCursorMovable()) {
var lastIndex = this.index();
if (Input.isRepeated('down')) {
this.cursorDown(Input.isTriggered('down'));
}
if (Input.isRepeated('up')) {
this.cursorUp(Input.isTriggered('up'));
}
if (Input.isRepeated('right')) {
this.cursorRight(Input.isTriggered('right'));
}
if (Input.isRepeated('left')) {
this.cursorLeft(Input.isTriggered('left'));
}
if (!this.isHandled('pagedown') && Input.isTriggered('pagedown')) {
this.cursorPagedown();
}
if (!this.isHandled('pageup') && Input.isTriggered('pageup')) {
this.cursorPageup();
}
if (this.index() !== lastIndex) {
SoundManager.playCursor();
}
}
};
复制代码
Window_Selectable还有一些对item的绘制方法
Window_Selectable.prototype.drawItem = function (index) {
};
Window_Selectable.prototype.clearItem = function (index) {
var rect = this.itemRect(index);
this.contents.clearRect(rect.x, rect.y, rect.width, rect.height);
};
Window_Selectable.prototype.redrawItem = function (index) {
if (index >= 0) {
this.clearItem(index);
this.drawItem(index);
}
};
Window_Selectable.prototype.redrawCurrentItem = function () {
this.redrawItem(this.index());
};
Window_Selectable.prototype.refresh = function () {
if (this.contents) {
this.contents.clear();
this.drawAllItems();
}
};
复制代码
不过可以看出drawItem只有一个架子, 需要子类对其进行填充
Window_Selectable的方法还是有一大堆的, 涉及到了用户交互后新增了很多状态
而且当然也需要TouchInput, Input类来提供用户行为的判断
具体实践我们留到下一回讲Window_Command的时候继续
(讲一个Scene_Title的createCommandWindow方法可以水3个类, 继承真棒!
作者:
walf_man
时间:
2019-8-21 20:17
辛苦大佬无私分享
欢迎光临 Project1 (https://rpg.blue/)
Powered by Discuz! X3.1