设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
查看: 2718|回复: 3

[交流讨论] RPG Maker MV 的源码研究 其九

[复制链接]

Lv3.寻梦者

梦石
0
星屑
1882
在线时间
1552 小时
注册时间
2013-4-13
帖子
917
发表于 2019-8-20 06:47:48 | 显示全部楼层 |阅读模式

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

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

x
本帖最后由 沉滞的剑 于 2019-8-20 18:11 编辑

第八章 Window_Selectable

上回说到Window_Base为Window类提供了基础的绘制功能
那么Window_Selectable则提供了基础的交互功能

  1. function Window_Selectable() {
  2.     this.initialize.apply(this, arguments);
  3. }

  4. Window_Selectable.prototype = Object.create(Window_Base.prototype);
  5. Window_Selectable.prototype.constructor = Window_Selectable;

  6. Window_Selectable.prototype.initialize = function(x, y, width, height) {
  7.     Window_Base.prototype.initialize.call(this, x, y, width, height);
  8.     this._index = -1;
  9.     this._cursorFixed = false;
  10.     this._cursorAll = false;
  11.     this._stayCount = 0;
  12.     this._helpWindow = null;
  13.     this._handlers = {};
  14.     this._touching = false;
  15.     this._scrollX = 0;
  16.     this._scrollY = 0;
  17.     this.deactivate();
  18. };
复制代码
首先this._index指的时当前选择的对象的序号, 如果为-1则代表未选中
  1. Window_Selectable.prototype.index = function() {
  2.     return this._index;
  3. };
  4. Window_Selectable.prototype.select = function(index) {
  5.     this._index = index;
  6.     this._stayCount = 0;
  7.     this.ensureCursorVisible();
  8.     this.updateCursor();
  9.     this.callUpdateHelp();
  10. };

  11. Window_Selectable.prototype.deselect = function() {
  12.     this.select(-1);
  13. };

  14. Window_Selectable.prototype.reselect = function() {
  15.     this.select(this._index);
  16. };
复制代码

this._cursorFixed = false;
this._cursorAll = false;
是光标锁定和选择全体的flag
  1. Window_Selectable.prototype.cursorFixed = function() {
  2.     return this._cursorFixed;
  3. };

  4. Window_Selectable.prototype.setCursorFixed = function(cursorFixed) {
  5.     this._cursorFixed = cursorFixed;
  6. };

  7. Window_Selectable.prototype.cursorAll = function() {
  8.     return this._cursorAll;
  9. };

  10. Window_Selectable.prototype.setCursorAll = function(cursorAll) {
  11.     this._cursorAll = cursorAll;
  12. };
复制代码

this._stayCount 是一个计数器, 判断鼠标或触摸是否在菜单上下内边距内按下超过10帧
如果在上边框悬停超过10帧后按下鼠标则选择上一个item(对触摸也有效)
如果在下边框悬停超过10帧后按下鼠标则选择下一个item(对触摸也有效)
  1. Window_Selectable.prototype.update = function() {
  2.     ...
  3.     this._stayCount++;
  4. };

  5. Window_Selectable.prototype.onTouch = function (triggered) {
  6.    ...
  7.     } else if (this._stayCount >= 10) {
  8.         if (y < this.padding) {
  9.             this.cursorUp();
  10.         } else if (y >= this.height - this.padding) {
  11.             this.cursorDown();
  12.         }
  13.     }
  14.     ...
  15. };
复制代码
很多人都没发现这个功能吧, 可以找标题菜单, 游戏菜单试验一下~
this._helpWindow是说明窗口
这个有专门的类实现这类窗口Window_Helper
我们先简单了解一下在Window_Selectable里的使用

  1. Window_Selectable.prototype.setHelpWindow = function(helpWindow) {
  2.     this._helpWindow = helpWindow;
  3.     this.callUpdateHelp();
  4. };

  5. Window_Selectable.prototype.showHelpWindow = function() {
  6.     if (this._helpWindow) {
  7.         this._helpWindow.show();
  8.     }
  9. };

  10. Window_Selectable.prototype.hideHelpWindow = function() {
  11.     if (this._helpWindow) {
  12.         this._helpWindow.hide();
  13.     }
  14. };

  15. Window_Selectable.prototype.callUpdateHelp = function() {
  16.     if (this.active && this._helpWindow) {
  17.         this.updateHelp();
  18.     }
  19. };

  20. Window_Selectable.prototype.updateHelp = function() {
  21.     this._helpWindow.clear();
  22. };

  23. Window_Selectable.prototype.setHelpWindowItem = function(item) {
  24.     if (this._helpWindow) {
  25.         this._helpWindow.setItem(item);
  26.     }
  27. };
复制代码
这些方法只是helpWindow方法的包装而已
作为一基础类Window_Selectable并没有实际上的helpWindow, 所以这部分等到以后遇到HelpWindow再细讲
this._handlers 是回调函数, 也就是玩家选择后的反馈
  1. Window_Selectable.prototype.setHandler = function(symbol, method) {
  2.     this._handlers[symbol] = method;
  3. };

  4. Window_Selectable.prototype.isHandled = function(symbol) {
  5.     return !!this._handlers[symbol];
  6. };

  7. Window_Selectable.prototype.callHandler = function(symbol) {
  8.     if (this.isHandled(symbol)) {
  9.         this._handlers[symbol]();
  10.     }
  11. };
复制代码

其实非常简单: 以字典格式存储, 按照key来呼叫方法就好
有一些默认的handler
  1. Window_Selectable.prototype.callOkHandler = function() {
  2.     this.callHandler('ok');
  3. };

  4. Window_Selectable.prototype.processCancel = function() {
  5.     SoundManager.playCancel();
  6.     this.updateInputData();
  7.     this.deactivate();
  8.     this.callCancelHandler();
  9. };

  10. Window_Selectable.prototype.callCancelHandler = function() {
  11.     this.callHandler('cancel');
  12. };

  13. Window_Selectable.prototype.processPageup = function() {
  14.     SoundManager.playCursor();
  15.     this.updateInputData();
  16.     this.deactivate();
  17.     this.callHandler('pageup');
  18. };

  19. Window_Selectable.prototype.processPagedown = function() {
  20.     SoundManager.playCursor();
  21.     this.updateInputData();
  22.     this.deactivate();
  23.     this.callHandler('pagedown');
  24. };
复制代码
这些为子类提供了一些基础框架
this._touching是触摸状态, 下面是一个子update方法

  1. Window_Selectable.prototype.processTouch = function () {
  2.     if (this.isOpenAndActive()) { // 如果窗口可用
  3.         if (TouchInput.isTriggered() && this.isTouchedInsideFrame()) { //如果在窗口区域按下鼠标
  4.             this._touching = true;
  5.             this.onTouch(true); // 触发按下handler
  6.         } else if (TouchInput.isCancelled()) { // 如果按下右键/取消键
  7.             if (this.isCancelEnabled()) {  // 如果有取消handler
  8.                 this.processCancel(); // 执行取消handler
  9.             }
  10.         }
  11.         if (this._touching) {
  12.             if (TouchInput.isPressed()) {   // 在按住状态滑过窗口(非触摸双击或左键选择已选择的item)
  13.                 this.onTouch(false); // 仅触发重新选择而不会出发handler
  14.             } else {
  15.                 this._touching = false;
  16.             }
  17.         }
  18.     } else {
  19.         this._touching = false;
  20.     }
  21. };
复制代码
   this._scrollX 和 this._scrollY指的是菜单卷动的位置
这些纯计算位置的方法就不多说了, 数量太多不过内容只是纯数值计算, 我们以后遇到了再说
说完了初始化, 我们再看看update

  1. Window_Selectable.prototype.update = function () {
  2.     Window_Base.prototype.update.call(this);
  3.     this.updateArrows(); // 如果菜单高度显示不下, 显示箭头指示玩家下面/上面还有item
  4.     this.processCursorMove(); // 键盘事件
  5.     this.processHandling(); // 以后再说
  6.     this.processWheel(); // 看名字似乎是滚轮, 但是貌似无用
  7.     this.processTouch(); // 鼠标/触摸事件
  8.     this._stayCount++;
  9. };
复制代码
键盘事件, 支持上下左右和上下翻页
  1. Window_Selectable.prototype.processCursorMove = function () {
  2.     if (this.isCursorMovable()) {
  3.         var lastIndex = this.index();
  4.         if (Input.isRepeated('down')) {
  5.             this.cursorDown(Input.isTriggered('down'));
  6.         }
  7.         if (Input.isRepeated('up')) {
  8.             this.cursorUp(Input.isTriggered('up'));
  9.         }
  10.         if (Input.isRepeated('right')) {
  11.             this.cursorRight(Input.isTriggered('right'));
  12.         }
  13.         if (Input.isRepeated('left')) {
  14.             this.cursorLeft(Input.isTriggered('left'));
  15.         }
  16.         if (!this.isHandled('pagedown') && Input.isTriggered('pagedown')) {
  17.             this.cursorPagedown();
  18.         }
  19.         if (!this.isHandled('pageup') && Input.isTriggered('pageup')) {
  20.             this.cursorPageup();
  21.         }
  22.         if (this.index() !== lastIndex) {
  23.             SoundManager.playCursor();
  24.         }
  25.     }
  26. };
复制代码
Window_Selectable还有一些对item的绘制方法

  1. Window_Selectable.prototype.drawItem = function (index) {
  2. };

  3. Window_Selectable.prototype.clearItem = function (index) {
  4.     var rect = this.itemRect(index);
  5.     this.contents.clearRect(rect.x, rect.y, rect.width, rect.height);
  6. };

  7. Window_Selectable.prototype.redrawItem = function (index) {
  8.     if (index >= 0) {
  9.         this.clearItem(index);
  10.         this.drawItem(index);
  11.     }
  12. };

  13. Window_Selectable.prototype.redrawCurrentItem = function () {
  14.     this.redrawItem(this.index());
  15. };

  16. Window_Selectable.prototype.refresh = function () {
  17.     if (this.contents) {
  18.         this.contents.clear();
  19.         this.drawAllItems();
  20.     }
  21. };
复制代码

不过可以看出drawItem只有一个架子, 需要子类对其进行填充
Window_Selectable的方法还是有一大堆的, 涉及到了用户交互后新增了很多状态
而且当然也需要TouchInput, Input类来提供用户行为的判断

具体实践我们留到下一回讲Window_Command的时候继续
(讲一个Scene_Title的createCommandWindow方法可以水3个类, 继承真棒!


点评

代码块会被吞, 已修复, TAT  发表于 2019-8-20 18:12

评分

参与人数 2+2 收起 理由
玄羽 + 1 塞糖
康姆图帕帕 + 1 塞糖

查看全部评分

夏普的道具店

塞露提亚-道具屋的经营妙方同人作品
发布帖:点击这里

Lv4.逐梦者

梦石
0
星屑
14205
在线时间
718 小时
注册时间
2011-7-16
帖子
1428

开拓者

发表于 2019-8-21 20:17:42 | 显示全部楼层
辛苦大佬无私分享

点评

别刷屏...  发表于 2019-8-21 20:19
RMMV网络插件,开源免费,内含服务器端,无需强制登录,云数据,弹幕,云存档,排名,兑换码,版本检测,可自由上架下架删除。q群399090587
免打包运行MV游戏,云游戏,安卓App雷神游戏厅,在线玩游戏,上传下载游戏
开源游戏:重装机兵之重装归来【RMMV制作】全球首款按照美剧分季分集的方式发布的游戏
体素画 -- MV画3D像素图的画板
RMMV显示3D模型和场景的插件
RMMV显示spine骨骼动画的插件
RMMV秘密通道插件
突破敌群数量上限8个的插件
在rmmv中显示gif动态图片的插件
一款可以在mv游戏界面的任意位置显示任意文字的插件
RMMV Toast 插件 带物品得失提示,可以设置开启关闭 兼容yep itemcore
制作一个改名卡道具插件、调整标题页面菜单的插件、在标题页面之前显示大段文字的插件、标题页面显示版本号的插件
物品得失自动提示自动上色自动换行插件
我的Q群 663889472
另外,我的插件、范例、游戏都在这里
回复 支持 反对

使用道具 举报

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

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2024-4-18 20:53

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表