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

Project1

 找回密码
 注册会员
搜索
查看: 12781|回复: 19
打印 上一主题 下一主题

[原创发布] RPGMakerMV的插件学习

[复制链接]

Lv1.梦旅人

梦石
0
星屑
50
在线时间
19 小时
注册时间
2016-3-30
帖子
13
跳转到指定楼层
1
发表于 2016-3-31 17:05:00 | 只看该作者 |只看大图 回帖奖励 |正序浏览 |阅读模式

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

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

x
本人程序员,写过几年js,但是真正用到的东西根本算是皮毛中的皮毛。

本着独立游戏开发者的心态,入了正版RM来想自己做游戏,而且这版的语言也正好是js

就着这个机会一边研究插件一边深入学习js

有能力的同学可以试着去看看Youtube上面Soulpour777的几个视频

对于想学js和想做插件的同学都有挺大的收获

这里就把我对做这插件的学习记录放进来,可能有些乱

首先经过视频和其他大神的插件,了解到这么一个问题,就是很多时候要实现自己的插件,基本上都是去重写官方的原型链中的方法(我不太清楚这样称呼是否明确,请大神给指出错误)

就是你随便打开一个官方的js文件,就会看到里面诸如  xxx.prototype.yyy 这样的东西

这个时候在自己新建的插件里面把这整个方法复制下来, 并且在RPGMaker的插件管理加上自己的插件,启动的时候就会执行重写的那个方法

做个简单的事例(同学们请自己动手喔),我们来实现一个在启动游戏的时候(就是显示新游戏NewGame,继续Continue和选项Options那个页面),加入一个新的选择项目 测试项

下面开始操作:

1,首先在游戏项目下的js/plugins文件夹里创建一个自己的插件文件(我这里命名的是testPlugin.js)

2,然后得找到启动游戏这个东西是在哪儿画出来的,rpg_window.js 这个文件就是控制来画出所有想要的窗口的官方文件,在文件的5747这行里,有个

Window_TitleCommand.prototype.makeCommandList 方法  这个方法里面就是画出初始化游戏的窗口,把这个方法整个复制到自己的js文件里

从这里就能看到,官方是把这里的3个选项依次加进去,addCommand这个方法有4个参数传进去
Window_Command.prototype.addCommand = function(name, symbol, enabled, ext)
第一个参数 类型(string) 代表的是显示的名称
第二个参数 类型(string)代表的是标示(在事件处理的时候会通过标示来确定执行什么事件)
第三个参数 类型(boolean)代表这个选项是否可用,这里的继续游戏continue按钮是灰色,因为他判断了是否游戏里面有存档this.isContinueEnabled(),如果有存档就返回的true,否则false,默认是true
第四个参数 类型(任意)是拓展 用于其他特殊的标示,类似于第二个参数

3,现在我们把一个测试项放进启动游戏的选项里面,只需要在我们的js文件里面,跟着方法后面写上this.addCommand('测试项','testOption');, ,这样

4,将插件加入进来,运行游戏

当当当!就出现了!可是你点击是没有任何效果的,因为这里还没给设置绑定的事件,下次我会继续讲解如何绑定事件.

点评

很棒的教程!不过最好不要直接修改原方法,这样做容易和其他插件不兼容,建议后面的教程都先重定义方法,再修改新定义的方法,以免杯具  发表于 2016-3-31 17:19

评分

参与人数 7星屑 +221 梦石 +2 收起 理由
xjzsq + 30 精品文章,值得精读!加油!
柳岳枫 + 60
CFRoo + 20 精品文章
冷峻逸 + 46 补个111
gonglinyuan + 45 精品文章
dongdongdjh + 20 插眼,养肥了再看。
余烬之中 + 2 加油

查看全部评分

Lv1.梦旅人

梦石
0
星屑
50
在线时间
0 小时
注册时间
2017-9-27
帖子
2
18
发表于 2017-9-27 23:40:54 | 只看该作者
不错不错~~~
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
50
在线时间
45 小时
注册时间
2008-3-2
帖子
118
17
发表于 2017-9-8 14:43:09 | 只看该作者
bulangnisi 发表于 2016-4-11 18:10
有几天没来更新了,在做其它的事儿

这会有空了,马上来把我的tip插件来完成了

提示cannot read property "filter"of undefined
魔幻大航海II:伟大航路 制作中....
●剧情:■□□□□□□□□□10%
◎美工:■■■■■■■■■□90%
●音效:■■■■■■■■■□90%
◎脚本:■■■■■■■□□□70%
●枫野别墅:http://xiaomu2100.blog.163.com
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
50
在线时间
13 小时
注册时间
2016-3-31
帖子
9
16
发表于 2017-1-2 04:11:07 | 只看该作者
先膜拜一下,回头过来仔细看。
回复 支持 反对

使用道具 举报

Lv5.捕梦者

梦石
0
星屑
31005
在线时间
608 小时
注册时间
2014-7-18
帖子
729

开拓者

15
发表于 2017-1-1 15:40:26 | 只看该作者
给您提供一个有助于您研究的东西吧!
https://rpg.blue/thread-385523-1-1.html
这个帖子不仅汉化了脚本注释,还吧原生脚本给分离开来了,十分符合RMVA的脚本显示方式,可以参考一下。
另外,建议您去看看VA的帮助文档,里面解读篇和实践篇部分介绍了脚本系统RGSS3的结构,尽管是Ruby语言,而且有很多方法MV里面都没有了(比如alias),但是对于理解MV的脚本系统还是很有帮助的,因为MV的脚本思想和VA的非常相似。
希望对您有所帮助!!!加油!!!
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
685
在线时间
0 小时
注册时间
2016-12-27
帖子
1
14
发表于 2016-12-28 22:24:34 | 只看该作者
司机我要加加你,想请教怎么在插件里面选中对象 = =原谅我没看你的源码
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
50
在线时间
19 小时
注册时间
2016-3-30
帖子
13
13
 楼主| 发表于 2016-4-11 18:10:17 | 只看该作者
有几天没来更新了,在做其它的事儿

这会有空了,马上来把我的tip插件来完成了

上次完成一个测试版的之后,发现了一个很大问题,第一,显示出的tip框是直接就出现了,第二,关闭tip的时候没法回车去关闭,而且还强制改写了Scene_Map的update来实现的关闭,相当难看,第三,打开tip的事件角色只转身一下就又转回去了。

说白了,是相当的失败,于是又花了两天时间仔细研究了一下Window_Message的实现,有一些小的收获,这里先大致讲解一下实现的思路

首先我目标中的tip,是在Scene_Map中弹出来,跟对话的消息是一样的,如果新建一个Scene来显示的话,后面是的画面是不会动的,所以这里照着跟Window_Message一样,仅新建一个Window来在Scene_Map中显示

这里提下关于打开tip(Message也是一样)的关键所在,update,刷新帧,Window_Base自带有的一个方法,所以每个继承至Window_Base的都会有这个方法,当创建Scene之后,然后往Scene里添加Window,这些Window都会一直调用这个方法,通过这个方法来检测某些变量或者函数返回值来做出动作

拿Window_Message来举例(Window_Message里面包涵了除了显示消息以外的好几个东西,这里就简单拿显示消息来做例子),Window_Message的update实现是在非打开中和非关闭中的时候,去判断是否要显示消息框,其中当消息(就是我们调用的时候传入的那些字符信息)存在的时候打开了消息框,同时字符会在里面打印的同时并把它们都消费掉,当字符未被消费完,同时达到窗口容纳字符的最大值的时候,先暂停,然后当触发按键的时候打开下一页。看到那几个简单的字眼估计就明白了,比如newLine啊newPage啊什么的。

我们做的这个tip没这么复杂,至少我不想去每个字符慢悠悠的打出来,所以消费字符这一步我这里直接是全部拿出去了

然后再提出几个关键点

第一,就是当打开消息框的时候,按esc,不会打开菜单,而是关闭掉消息框,同样我们的tip也需要这一个操作,但是这个动作我之前是用了一个比较笨的方法,就是菜单监听esc的事件里先判断是否打开tip,如果是,则先关闭tip,其实官方的方式是,设置菜单的可用性,于是这次我也沿用官方的做法,打开tip的时候,先设置菜单不可用,然后后面的esc就不会触发打开菜单

第二,打开的tip怎么出现的,之前也是用的错误的办法,直接设置tip窗口的visible,效果嘛,就一闪,直接打开了```感觉很突兀,而标题页和消息框的那些菜单都是展开的形式打开的,方法我也想过,无非刷新帧的时候去做个动画而已嘛,实际不用这么麻烦,直接调用本体的open函数就行了,他会每一帧增加一个opacity的值,每次增加32,8次就能达到大于255的极值了,在这个加值的过程,window的isOpening属性会是true,所以就不用担心他在原本的update函数里面捣乱(update函数里面实现的时候是要去判断非打开中和非关闭中的状态),用样close也是类似的动作,所以这一动作就作出了让我们看到的展开的形式(ps:其实这里我还是有点疑问,就是opacity该叫做透明度的,怎么动画效果会是展开呢。。。),这里注意一点,初始化tip窗口的时候,记得把this.openness = 0;,这是open函数操作的关键之一。

第三,事件触发的目标是人物的话,他不会朝向主角,这里是由于有一个等待模式的介入,大家在rpg_object里面找到command101看函数最后就明白了,他设置了一个消息的等待模式,除了消息,其它好几个需要等待的,都是这样处理的,当等待模式启动之后,触发事件的目标就会朝向主角,并且如果带动作效果的,他的动作也不会停,因为等待模式也是一种update刷新着呢

上代码
JAVASCRIPT 代码复制
  1. /*:
  2.  * @plugindesc 主场景小提示插件
  3.  * @author BenJ
  4.  *
  5.  *
  6.  *
  7.  * @param tipIconPadding
  8.  * @desc 如果带icon图标的话,文字与图标的间距
  9.  * @default 36
  10.  *
  11.  *
  12.  * @help
  13.  *
  14.  * Plugin Command:
  15.  *
  16.  * myTipWindow showTip msg  #添加一条消息
  17.  * myTipWindow showTip msg iconId  #添加一条带icon的消息
  18.  *
  19.  *
  20.  */
  21. var parameters = PluginManager.parameters('myTipWindow');
  22. var tipIconPadding = Number(parameters['tipIconPadding'] || 36);
  23.  
  24. var _myGame_Interpreter_pluginCommand = Game_Interpreter.prototype.pluginCommand;
  25.  
  26. Game_Interpreter.prototype.pluginCommand = function(command,args){
  27.   _myGame_Interpreter_pluginCommand.call(this);
  28.   if(command == 'myTipWindow'){
  29.     $gameMap._showTip = true;//是否需要打开tip窗口
  30.     $gameMap._isShownTip = true;//tip窗口是否被打开
  31.     $gameMap._tip = {
  32.       msg : args[0] ,//tip的文本
  33.       icon : args[1]  //tip的图标
  34.       //showed : false //是否已经显示过该信息  防止一直刷新
  35.     };
  36.     this.setWaitMode('tipMessage');
  37.   }
  38. };
  39.  
  40. //修改Game_Map初始化,增加tip相关属性
  41. var _jGame_Map_setup = Game_Map.prototype.setup;
  42. Game_Map.prototype.setup = function(mapId) {
  43.   _jGame_Map_setup.call(this,mapId);
  44.   this._showTip = false;
  45.   this._isShownTip = false;
  46.   this._tip = {};
  47. };
  48.  
  49. //重写Scene_Map初始化部分窗口函数
  50. var _jScene_Map_createAllWindows = Scene_Map.prototype.createAllWindows;
  51. Scene_Map.prototype.createAllWindows = function() {
  52.   _jScene_Map_createAllWindows.call(this);
  53.   this.createTipWindow();
  54. };
  55.  
  56. //创建tipWindow加入到Scene_Map
  57. Scene_Map.prototype.createTipWindow = function() {
  58.   this._tipWindow = new Window_JTip();
  59.   this.addWindow(this._tipWindow);
  60. };
  61.  
  62. //todo 自定义提示窗体
  63. function Window_JTip() {
  64.   this.initialize.apply(this, arguments);
  65. }
  66.  
  67. Window_JTip.prototype = Object.create(Window_Base.prototype);
  68. Window_JTip.prototype.constructor = Window_JTip;
  69.  
  70. Window_JTip.prototype.initialize = function() {
  71.   var width = this.windowWidth();
  72.   var height = this.windowHeight();
  73.   Window_Base.prototype.initialize.call(this, (Graphics.width - width)/2, 200, width, height);
  74.   this.openness = 0;//尝试了好多次,原来这就是关键点所在,初始化的时候,把openness设置为0的时候,调用open函数的时候,才会去刷新
  75. };
  76.  
  77. //窗口宽度
  78. Window_JTip.prototype.windowWidth = function() {
  79.   return Number(this.width || 240);
  80. };
  81.  
  82. //窗口高度
  83. Window_JTip.prototype.windowHeight = function() {
  84.   return this.fittingHeight(1);
  85. };
  86.  
  87. //刷新tip窗口
  88. Window_JTip.prototype.refresh = function(_tipArgs) {
  89.   this.contents.clear();
  90.   //this.visible = $gameMap.isTipWindowShow();
  91.   if(_tipArgs){
  92.     //this.resetTipWindow(_tipArgs);//这个函数里面执行过显示窗口函数核心Bitmap的resize,如果在后面resize,会清空内容栏,具体我也没看到哪里在清空,但是事实如此
  93.     //todo 绘制消息板
  94.     var _cnTest =  /[\u4E00-\u9FA5]/;
  95.     var _msg = _tipArgs.msg.toString();
  96.     var _width = 0;
  97.     //通过文字计算窗口大小
  98.     for(var i=0 ; i<_msg.length ; i++){
  99.       //判断是否为中文,不是中文,只用字体大小的一半
  100.       if(_cnTest.test(_msg[i])){
  101.         _width += this.standardFontSize() ;
  102.       }else{
  103.         _width += this.standardFontSize() / 2 ;
  104.       }
  105.     }
  106.     //添加默认内容左右padding
  107.     _width += this.standardPadding() * 2;
  108.  
  109.     //是否包含icon
  110.     if(_tipArgs.icon != undefined && _tipArgs.icon != 0){
  111.       _width += tipIconPadding;
  112.     }
  113.  
  114.     this.width = _width;
  115.     this.x = (Graphics.width - _width)/2;
  116.     this.contents.resize(this.contentsWidth(),this.contentsHeight());//这里设置的内容的宽度,如果照官方的算法,这个宽度可能会显示不完我们的内容
  117.  
  118.     //todo 绘制内容
  119.     //_tipArgs.showed = true; //显示过的信息改变此标示
  120.     if(_tipArgs.icon){
  121.       //显示带icon的信息
  122.       this.drawIcon(_tipArgs.icon,0,0);
  123.       this.drawText(_tipArgs.msg.toString(),tipIconPadding,0);
  124.     }else{
  125.       //显示普通信息
  126.       this.drawText(_tipArgs.msg.toString(),0,0);
  127.     }
  128.   }
  129. };
  130.  
  131. Window_JTip.prototype.update = function(){
  132.   Window_Base.prototype.update.call(this);
  133.   //根据window_message的实现来看,弹出样式是打开和关闭的时候调用的updateOpen和updateClose
  134.   while(!this.isOpening() && !this.isClosing()){
  135.     //在非打开中和非关闭中,调用一遍所有需要执行的东西
  136.     //message处理的方式是检测文本信息是否已经消费完来启动
  137.     if(this.updateInput()){
  138.       return;
  139.     }else if(this.needShow()){
  140.       this.startTip();
  141.     }else{
  142.       return;
  143.     }
  144.   }
  145. };
  146.  
  147. //启动tip窗口
  148. Window_JTip.prototype.startTip = function() {
  149.   this.refresh($gameMap._tip);
  150.   this.open();
  151.   $gameSystem.disableMenu();
  152.   $gameMap._showTip = false;//启动了窗口就把是否启动tip关掉,否则update一直刷新启动造成死循环了
  153.   this.pause = true;//启动了窗口,并且刷新了窗口之后,设置暂停
  154. };
  155.  
  156. Window_JTip.prototype.needShow = function() {
  157.   return $gameMap._showTip;
  158. };
  159.  
  160. Window_JTip.prototype.isTriggered = function() {
  161.   return (Input.isRepeated('ok') || Input.isRepeated('cancel') || TouchInput.isRepeated());
  162. };
  163.  
  164. //当窗口暂停,并且有按键触发,我们就关闭窗口
  165. Window_JTip.prototype.updateInput = function() {
  166.   if(this.pause){
  167.     if(this.isTriggered()){
  168.       $gameSystem.enableMenu();
  169.       this.pause = false;
  170.       $gameMap._isShownTip = false;
  171.       this.close();
  172.     }
  173.     return true;
  174.   }else{
  175.     return false;
  176.   }
  177. };
  178.  
  179. //这里由于官方内定了好几种等待模式,而且写得比较死,我就直接在官方的函数里拓展了,增加了tipMessage的标示
  180. Game_Interpreter.prototype.updateWaitMode = function() {
  181.   var waiting = false;
  182.   switch (this._waitMode) {
  183.     case 'message':
  184.       waiting = $gameMessage.isBusy();
  185.       break;
  186.     case 'transfer':
  187.       waiting = $gamePlayer.isTransferring();
  188.       break;
  189.     case 'scroll':
  190.       waiting = $gameMap.isScrolling();
  191.       break;
  192.     case 'route':
  193.       waiting = this._character.isMoveRouteForcing();
  194.       break;
  195.     case 'animation':
  196.       waiting = this._character.isAnimationPlaying();
  197.       break;
  198.     case 'balloon':
  199.       waiting = this._character.isBalloonPlaying();
  200.       break;
  201.     case 'gather':
  202.       waiting = $gamePlayer.areFollowersGathering();
  203.       break;
  204.     case 'action':
  205.       waiting = BattleManager.isActionForced();
  206.       break;
  207.     case 'video':
  208.       waiting = Graphics.isVideoPlaying();
  209.       break;
  210.     case 'image':
  211.       waiting = !ImageManager.isReady();
  212.       break;
  213.     case 'tipMessage':
  214.       waiting = $gameMap._isShownTip;
  215.       break;
  216.   }
  217.   if (!waiting) {
  218.     this._waitMode = '';
  219.   }
  220.   return waiting;
  221. };


关于插件的调用和设置就不多说了,下面看成果图
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
234
在线时间
124 小时
注册时间
2015-2-18
帖子
11
12
发表于 2016-4-9 22:28:48 | 只看该作者
加油!!。。。
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
50
在线时间
48 小时
注册时间
2010-10-26
帖子
17
11
发表于 2016-4-7 14:27:21 | 只看该作者
专业的就是不一样,几天就顶我几个月的研究
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
50
在线时间
19 小时
注册时间
2015-12-15
帖子
6
10
发表于 2016-4-5 03:49:43 | 只看该作者
bulangnisi 发表于 2016-4-4 22:18
呼~~~

看到你的回复之后,搞了我好几个小时,毕竟是第一个向我提问的人啊,我这不就全力以赴的帮你研 ...

天哪……………………简直太感谢了!!!!!!!原来每次scene_map都要清空栈…………总之太感谢了!!!!
回复 支持 反对

使用道具 举报

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

本版积分规则

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

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

GMT+8, 2024-12-3 00:50

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

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