Project1

标题: [教程]RMMV脚本教程——菜单美化(一) [打印本页]

作者: xjzsq    时间: 2019-7-2 01:15
标题: [教程]RMMV脚本教程——菜单美化(一)
本帖最后由 xjzsq 于 2020-8-23 02:44 编辑

全系列教程传送门
RMMV脚本教程——菜单美化(二)

RMMV脚本教程——菜单美化(三)(完结)
写在前面
时隔不到一年半,高考完的我终于决定继续研究MV的脚本,然后写教程啦…
之前的教程是发布在Project1(原6R)论坛上的,之前的坑还是会慢慢填完的,现在再开个新坑!
这次来美化一下菜单!
首先放一下先行图:


注意事项

正文
首先,让我们先创建一个新工程!
然后,打开游戏工程文件夹,进入js/plugins文件夹,新建一个js文件。
在里面先输入插件信息:
  1. /*:
  2. @author xjzsq
  3. @plugindesc 菜单美化
  4. @help
  5.          直接打开即可食用~
  6. */
复制代码
@author后面是作者名字,@plugindesc后面是插件的简单描述,而@help后面则是插件怎么用,比如如果有参数的话每个参数的含义等的帮助信息。
之后,在mv的插件管理器中打开插件。
下面,让我们从最简单的显示金钱数的窗口开始吧!
我们的目标是加上好看的图标。
在此之前,我先介绍一下写代码之前需要知道的知识

前置知识——场景类Scene和窗口类Window
  • 场景类Scene
    场景类Scene是负责游戏中各个画面处理的类,RMMV的游戏就是由一个个场景(画面)共同组成的,标题是一个场景(Scene_Title)、地图是一个场景(Scene_Map)、战斗也是一个场景(Scene_Battle),我们今天要改的菜单也是一个场景(Scene_Menu),玩家在不同场景之间不断切换,就组成了一个完整的游戏。感兴趣的同学珂以看下原生脚本中文注释翻译的rpg_scenes文件夹,里面21个文件对应了MV中21个不同的场景,其中有些场景直接在游戏中显示出来,有些场景是其他场景的父类,其中定义了其他几个场景共有方法,比如Scene_Base 是所有场景的父类(关于类和继承相关的知识请自行上网搜索,这里不再赘述),而Scene_MenuBase则作为Scene_Menu和Scene_Options等场景的父类。
    场景类中一般定义了要显示的窗口,并负责不断更新内容。
    如果你想了解更多关于场景类的知识,你珂以打开RMVA的F1到脚本入门解读篇的场景管理部分来查看,虽然MV的代码已经是javaScript,但是他的所有脚本结构基本和VA没有差别,只是为了支持多平台而用JS重写了一遍罢了…
  • 窗口类Window
    窗口类是定义了各个窗口中要显示什么、多大等的类,他与场景类的区别和联系是,窗口类定义窗口长什么样子,而场景类把定义的窗口显示出来。下面将要修改的用来显示金钱的窗口就属于窗口类。


带图标的金钱显示窗口
我们先去RMMV原生脚本那里看看他是如何显示金钱的,因此我们打开原生脚本汉化的Scene_Menu.js,这个是我们今天主要修改和参考的对象——菜单场景,我们就是通过修改菜单场景中的各个窗口来达到美化菜单的目的的。
在里面搜索“金钱”,发现第一处便是:
  1. //创建金钱窗口()
  2. this.createGoldWindow();
复制代码
看不出是什么窗口,于是我们看看这个方法的定义(以createGoldWindow为关键字搜索):
  1. /**创建金钱窗口 */
  2. Scene_Menu.prototype.createGoldWindow = function() {
  3.     //金钱窗口 = 新 窗口金钱(0,0)
  4.     this._goldWindow = new Window_Gold(0, 0);
  5.     //金钱窗口 y = 图形 盒高 - 金钱窗口 高
  6.     this._goldWindow.y = Graphics.boxHeight - this._goldWindow.height;
  7.     //添加窗口(金钱窗口)
  8.     this.addWindow(this._goldWindow);
  9. };
复制代码

我们知道了,显示金钱的窗口是Window_Gold,考虑到金钱窗口不仅仅显示在菜单上,还会显示在商店等场景中,因此我们重新写一个窗口Window_NewGold来替代Window_Gold,而在Scene_Menu中只需改动createGoldWindow这个方法即可。
我们打开Window_Gold,看到里面只有50行左右的代码,其中描绘文字是在refresh中(从draw开头的方法名珂以看出来)实现的。那么我们珂以让Window_Gold作为我们新的金钱窗口的父类,我们只需要修改refresh方法即可。
在js插件文件中插入以下内容,来定义Window_NewGold窗口,并将其父类设成Window_Gold:
  1. //********************
  2. //带图标的金钱显示窗口
  3. //********************
  4. function Window_NewGold(){
  5.         this.initialize.apply(this, arguments);
  6. }
  7. Window_NewGold.prototype = Object.create(Window_Gold.prototype);
  8. Window_NewGold.prototype.constructor = Window_NewGold;
复制代码

然后重写refresh方法,这里介绍绘制图标的方法drawIcon,用来绘制图标,定义在Window_Base中,其实当我们不知道某个东西是用哪个函数绘制出来的时候,不妨用中文在Window_Base中搜索一下,大多数方法都定义在这里。搜索到drawIcon的方法定义如下:
  1. /**绘制图标 */
  2. Window_Base.prototype.drawIcon = function(iconIndex, x, y) {
  3.     var bitmap = ImageManager.loadSystem('IconSet');
  4.     var pw = Window_Base._iconWidth;
  5.     var ph = Window_Base._iconHeight;
  6.     var sx = iconIndex % 16 * pw;
  7.     var sy = Math.floor(iconIndex / 16) * ph;
  8.     this.contents.blt(bitmap, sx, sy, pw, ph, x, y);
  9. };
复制代码
我们看到他有3个参数,x和y分别是绘制的坐标,iconIndex则是图标的编号,可以在数据库中可以选择图标的任意一个地方看到,如下图:


我们可以看到我们想显示的图标的iconIndex是313,因此我们在插件中这样写:
  1. Window_NewGold.prototype.refresh = function(){
  2.         Window_Gold.prototype.refresh.call(this);
  3.         this.drawIcon(313, 0, 0);
  4. };
复制代码
这里Window_Gold.prototype.refresh.call(this);是用来调用他的父类的refresh方法中的内容的,相当于VA脚本中的super。
最后,我们将Scene_Menu中的createGoldWindow复制过来,然后将其中的窗口改为Window_NewGold:
  1. Scene_Menu.prototype.createGoldWindow = function() {
  2.     this._goldWindow = new Window_NewGold(0, 0);
  3.     this._goldWindow.y = Graphics.boxHeight - this._goldWindow.height;
  4.     this.addWindow(this._goldWindow);
  5. };
复制代码

然后运行测试一下吧!


我们可以看到,图标显示出来了呢!
下面,我们就将对选项窗口进行调整,加上图标来美化它!

给菜单选项加上图标
那么绘制选项窗口的窗口类是哪个呢?
我们同样在Scene_Menu里面搜索“选项”,却发现只能搜到“option”,也就是对应选项窗口里面的那个“设置”,但是翻了下,第二个搜索结果中发现了以下内容,非常像绘制菜单中选项的窗口类:
  1. /**创建命令窗口 */
  2. Scene_Menu.prototype.createCommandWindow = function() {
  3.     //命令窗口 = 新 命令窗口(0,0)
  4.     this._commandWindow = new Window_MenuCommand(0, 0);
  5.     //命令窗口 设置处理("item"//物品 , 命令物品 绑定(this))
  6.     this._commandWindow.setHandler('item',      this.commandItem.bind(this));
  7.     //命令窗口 设置处理("skill"//技能 , 命令个人 绑定(this))
  8.     this._commandWindow.setHandler('skill',     this.commandPersonal.bind(this));
  9.     //命令窗口 设置处理("equip"//装备 , 命令个人 绑定(this))
  10.     this._commandWindow.setHandler('equip',     this.commandPersonal.bind(this));
  11.     //命令窗口 设置处理("status"//状态 , 命令个人 绑定(this))
  12.     this._commandWindow.setHandler('status',    this.commandPersonal.bind(this));
  13.     //命令窗口 设置处理("formation"//编队 , 命令编队 绑定(this))
  14.     this._commandWindow.setHandler('formation', this.commandFormation.bind(this));
  15.     //命令窗口 设置处理("options"//选项 , 命令选项 绑定(this))
  16.     this._commandWindow.setHandler('options',   this.commandOptions.bind(this));
  17.     //命令窗口 设置处理("save"//保存 , 命令保存 绑定(this))
  18.     this._commandWindow.setHandler('save',      this.commandSave.bind(this));
  19.     //命令窗口 设置处理("gameEnd"//游戏结束 , 命令结束游戏 绑定(this))
  20.     this._commandWindow.setHandler('gameEnd',   this.commandGameEnd.bind(this));
  21.     //命令窗口 设置处理("cancel"//取消 , 删除场景 绑定(this))
  22.     this._commandWindow.setHandler('cancel',    this.popScene.bind(this));
  23.     //添加窗口(命令窗口)
  24.     this.addWindow(this._commandWindow);
  25. };
复制代码

也就是Window_MenuCommand,这个窗口类确实是定义了菜单选项的。
那么我们打开这个类的js文件,但很不幸的是,即使你把整个文件读一遍,都不会找到什么有价值的东西…
原因是,绘制菜单选项的drawItem方法是定义在他的父类Window_Command里面…
他的定义是这样的:(感兴趣的同学可以去Window_Command里面搜搜看)
  1. /**绘制项目 */
  2. Window_Command.prototype.drawItem = function(index) {
  3.     var rect = this.itemRectForText(index);
  4.     var align = this.itemTextAlign();
  5.     this.resetTextColor();
  6.     this.changePaintOpacity(this.isCommandEnabled(index));
  7.     this.drawText(this.commandName(index), rect.x, rect.y, rect.width, align);
  8. };
复制代码
那我们修改Window_MenuCommand中的drawItem方法就好了。
既然是绘制图标,那么我们还是要用刚才提到的drawIcon,而且我已经给你们找好了图标的index,分别是:[208, 64, 137, 84, 75, 242, 229, 82],但是我们发现,drawItem方法有一个参数index,这和图标的index不同,对应的是菜单中的第几个选项,这里要注意的是,index是从0开始的,因此drawItem函数每次只描绘一个选项。这样的话,我们可以把图标的编号放到一个数组iconIndex内,这样就可以通过iconIndex快速访问第i个选项的图标的index是多少
这样我们就可以开始写了!首先将Window_Command内的drawItem函数的内容复制过来,然后加入图标,大家可以先尝试自己写一写,然后再看我的代码,这里要给大家补充的是,MV中图标的大小是36*36,因此文字的x值应该向右也就是加上36。
  1. //******************
  2. //给菜单选项加上图标
  3. //******************
  4. var iconIndex = [208, 64, 137, 84, 75, 242, 229, 82];
  5. Window_MenuCommand.prototype.drawItem = function(index){
  6.         var rect = this.itemRectForText(index);
  7.     var align = this.itemTextAlign();
  8.     this.resetTextColor();
  9.     this.changePaintOpacity(this.isCommandEnabled(index));
  10.         this.drawIcon(iconIndex[index],rect.x,rect.y);
  11.     this.drawText(this.commandName(index), rect.x + 36, rect.y, rect.width - 36, align);
  12. }
复制代码
然后运行结果如下:


作业
反正没人做,那就留一个比较有挑战性的作业吧…
在菜单显示金钱的窗口上面加一个显示玩家已经走过步数的窗口吧!
Tips1. 可以参照显示金钱的窗口来改。
Tips2. 获取玩家已经走过的步数的方法是$gameParty.steps()

后记
啊啊,教程看起来好短...是不是有点水的嫌疑?
吐槽一下,p1论坛的编辑器实在是太难用了...
直接复制粘贴过来排版全部乱掉了...
下一篇教程,我们将改造右边的人物绘制的方式,并且改变菜单的背景,像先行图上一样,感谢大家的支持啦~
最后,附上这篇教程最终的代码:
xjzsqMenu.zip (782 Bytes, 下载次数: 23, 售价: 100 星屑)




作者: xjzsq    时间: 2019-7-2 01:27
本帖最后由 xjzsq 于 2019-7-2 13:08 编辑

授人以渔!

这部分内容就决定叫做授人以渔了,具体内容大概就是写一写我自己的一些关于写脚本的心得或者经验,以及研究MV原生脚本并从中获得有用信息的方法。
之后嘛... 待填坑...


作者: zfjlove123    时间: 2019-7-2 08:57
支持楼主,希望楼主能常常更新哟
作者: 黑舞嗜    时间: 2019-7-12 11:00
求加背景教程...
作者: xjzsq    时间: 2019-7-12 12:35
黑舞嗜 发表于 2019-7-12 11:00
求加背景教程...


这个在下下期(第二期已经写好了,第三期估计后天就能完工)
作者: 黑舞嗜    时间: 2019-7-12 14:18
xjzsq 发表于 2019-7-12 12:35
这个在下下期(第二期已经写好了,第三期估计后天就能完工)

这样啊,好吧,反正我游戏还够没有,我等
作者: wuwei001    时间: 2019-11-1 16:21
感谢大佬 努力学习中~~~~
作者: 织梦行云    时间: 2019-11-2 00:58
很棒的教程啊!!
作者: 织梦行云    时间: 2019-11-7 08:46
每天早上支持一波
作者: 759782518    时间: 2019-11-8 09:40
大佬,那个原生汉化脚本如何使用?
直接放js里?
作者: xjzsq    时间: 2019-11-16 03:31
759782518 发表于 2019-11-8 09:40
大佬,那个原生汉化脚本如何使用?
直接放js里?

那个原生汉化脚本是用来辅助我们理解mv中原生js代码的,并不是放到游戏里的插件。
作者: legendxi    时间: 2019-11-26 23:12
谢谢楼主,希望还能发布更多的教程~~
作者: 博丽内奥拉    时间: 2019-12-30 01:30
交作业,真的就是照抄Window_Gold:
JAVASCRIPT 代码复制
  1. Window_Gold.prototype.refresh = function() {
  2.     var x = this.textPadding();
  3.     var width = this.contents.width - this.textPadding() * 2;
  4.     this.contents.clear();
  5.     this.drawIcon(313, 0, 0);
  6.     this.drawCurrencyValue(this.value(), this.currencyUnit(), x, 0, width);
  7. };
  8.  
  9.  
  10. var iconIndex = [208, 64, 137, 84, 75, 242, 229, 82];
  11. Window_MenuCommand.prototype.drawItem = function(index) {
  12.     var rect = this.itemRectForText(index);
  13.     var align = this.itemTextAlign();
  14.     this.resetTextColor();
  15.     this.changePaintOpacity(this.isCommandEnabled(index));
  16.     this.drawIcon(iconIndex[index],rect.x,rect.y);
  17.     this.drawText(this.commandName(index), rect.x+36, rect.y, rect.width, align);
  18. };
  19.  
  20.  
  21. Scene_Menu.prototype.create = function() {
  22.     //场景菜单基础 创建 呼叫(this)
  23.     Scene_MenuBase.prototype.create.call(this);
  24.     //创建命令窗口()
  25.     this.createCommandWindow();
  26.     //创建金钱窗口()
  27.     this.createGoldWindow();
  28.     //创建状态窗口()
  29.     this.createStatusWindow();
  30.  
  31.     this.createStepWindow();
  32. };
  33. Scene_Menu.prototype.createStepWindow = function() {
  34.     //金钱窗口 = 新 窗口金钱(0,0)
  35.     this._StepWindow = new Window_Step(0, 0);
  36.     //金钱窗口 y = 图形 盒高 - 金钱窗口 高
  37.     this._StepWindow.y = Graphics.boxHeight - this._StepWindow.height*2;
  38.     //添加窗口(金钱窗口)
  39.     this.addWindow(this._StepWindow);
  40. }
  41.  
  42.  
  43. function Window_Step() {
  44.     this.initialize.apply(this, arguments);
  45. }
  46.  
  47.  
  48. Window_Step.prototype = Object.create(Window_Base.prototype);
  49.  
  50. Window_Step.prototype.constructor = Window_Step;
  51.  
  52.  
  53. Window_Step.prototype.initialize = function(x, y) {
  54.     var width = this.windowWidth();
  55.     var height = this.windowHeight();
  56.     Window_Base.prototype.initialize.call(this, x, y, width, height);
  57.     this.refresh();
  58. };
  59.  
  60. Window_Step.prototype.windowWidth = function() {
  61.     return 240;
  62. };
  63.  
  64. Window_Step.prototype.windowHeight = function() {
  65.     return this.fittingHeight(1);
  66. };
  67.  
  68. Window_Step.prototype.refresh = function() {
  69.     var x = this.textPadding();
  70.     var width = this.contents.width - this.textPadding() * 2;
  71.     this.contents.clear();
  72.     this.drawIcon(176, 0, 0);
  73.     this.drawCurrencyValue(this.value(), this.currencyUnit(), x, 0, width);
  74. };
  75.  
  76. Window_Step.prototype.value = function() {
  77.     return $gameParty.steps();
  78. };
  79.  
  80. Window_Step.prototype.currencyUnit = function() {
  81.     return 's';
  82. };

作者: pihongwei456    时间: 2020-8-10 09:55
盖楼
作者: enderweater    时间: 2020-10-25 21:41
萌新表示学废了
作者: enderweater    时间: 2020-10-25 21:47
博丽内奥拉 发表于 2019-12-30 01:30
交作业,真的就是照抄Window_Gold:

大大写的程序是有bug吗,技能和装备界面打不开
作者: 张嘉仔    时间: 2021-9-4 05:36
66666666666666
作者: Lucky321    时间: 2021-9-4 09:33
感谢大佬分享

作者: archfalcon    时间: 2021-9-17 17:38
收藏了,感谢大佬分享
作者: whitesnake    时间: 2021-10-9 12:40
很不错,感谢楼主

作者: pohuai456    时间: 2021-10-11 18:04
支持一下
作者: haiyin    时间: 2021-11-14 18:14
作业那个怎么总是覆盖金钱的窗口啊...
作者: haiyin    时间: 2021-11-14 18:42
本帖最后由 haiyin 于 2021-11-14 19:02 编辑

找到问题了,我之前所做的都只是新增了窗口,但是并没有在scenes中显示出来...好像还没有人交作业,我就交下作业吧 有点乱..



  1. /*:
  2. *@author 作者
  3. *@plugindesc 插件描述
  4. *@help 帮助文档
  5. *
  6. *
  7. */

  8. (function() {
  9.         //金钱窗口
  10.         function Window_DIY_Gold() {
  11.                 this.initialize.apply(this, arguments);
  12.         }
  13.         //继承Window_Gold.prototype
  14.         Window_DIY_Gold.prototype = Object.create(Window_Gold.prototype);
  15.         Window_DIY_Gold.prototype.constructor = Window_DIY_Gold;
  16.         //刷新
  17.         Window_DIY_Gold.prototype.refresh = function() {
  18.                 Window_Gold.prototype.refresh.call(this);
  19.                 this.drawIcon(313, 0, 0);
  20.         };
  21.         //创建窗口
  22.         Scene_Menu.prototype.createGoldWindow = function() {
  23.                 this._goldWindow = new Window_DIY_Gold(0, 0);
  24.                 this._goldWindow.y = Graphics.boxHeight - this._goldWindow.height;
  25.                 this.addWindow(this._goldWindow);
  26.         };
  27.         //添加菜单图标 iconIndex对应的是菜单中从0开始的菜单选项索引值对应的图标索引值
  28.         var iconIndex = [208, 64, 137, 84, 75, 242, 229, 82];
  29.         Window_MenuCommand.prototype.drawItem = function(index) {
  30.                 //选项
  31.                 var rect = this.itemRectForText(index);
  32.                 //排列方式
  33.                 var align = this.itemTextAlign();
  34.                 //文字颜色
  35.                 this.resetTextColor();
  36.                 //透明状态
  37.                 this.changePaintOpacity(this.isCommandEnabled(index));
  38.                 //图标
  39.                 this.drawIcon(iconIndex[index], rect.x, rect.y);
  40.                 //MV中图标的大小是36*36,因此文字的x值应该向右也就是加上36 参数:名称 x y 宽 排列方式
  41.                 this.drawText(this.commandName(index), rect.x + 36, rect.y, rect.width - 36, align);
  42.         }
  43.         //创建步数窗口
  44.         function Window_DIY_Step() {
  45.                 this.initialize.apply(this, arguments);
  46.         }

  47.         Window_DIY_Step.prototype = Object.create(Window_Base.prototype);
  48.         //创建构造函数
  49.         Window_DIY_Step.prototype.constructor = Window_DIY_Step;

  50.         Window_DIY_Step.prototype.initialize = function(x, y) {
  51.                 var width = this.windowWidth();
  52.                 var height = this.windowHeight();
  53.                 Window_Base.prototype.initialize.call(this, x, y, width, height);
  54.                 this.refresh();
  55.         };

  56.         Window_DIY_Step.prototype.windowWidth = function() {
  57.                 return 240;
  58.         };

  59.         Window_DIY_Step.prototype.windowHeight = function() {
  60.                 return this.fittingHeight(1);
  61.         };

  62.         Window_DIY_Step.prototype.refresh = function() {
  63.                 var x = this.textPadding();
  64.                 var width = this.contents.width - this.textPadding() * 2;
  65.                 this.contents.clear();
  66.                 this.drawIcon(82, 0, 0);
  67.                 this.drawCurrencyValue(this.value(), this.currencyUnit(), x, 0, width);
  68.         };

  69.         Window_DIY_Step.prototype.value = function() {
  70.                 return $gameParty.steps();
  71.         };

  72.         Window_DIY_Step.prototype.currencyUnit = function() {
  73.                 return "S";
  74.         };

  75.         Window_DIY_Step.prototype.open = function() {
  76.                 this.refresh();
  77.                 Window_Base.prototype.open.call(this);
  78.         };
  79.         //新增步数窗口
  80.         Scene_Menu.prototype.createWindowDIYStep = function() {
  81.                 this._stepWindow = new Window_DIY_Step(0, 0);
  82.                 //设置上边距
  83.                 this._stepWindow.y = Graphics.boxHeight - this._stepWindow.height*2 - 5;
  84.                 this.addWindow(this._stepWindow);

  85.         }
  86.         //显示菜单窗口
  87.         Scene_Menu.prototype.create = function() {
  88.                 Scene_MenuBase.prototype.create.call(this);
  89.                 this.createCommandWindow();
  90.                 this.createGoldWindow();
  91.                 this.createStatusWindow();
  92.                 this.createWindowDIYStep();
  93.         };
  94. })();
复制代码

zy.PNG (780.04 KB, 下载次数: 45)

展示

展示

作者: 师太    时间: 2021-11-25 15:34
66666666666666666666




欢迎光临 Project1 (https://rpg.blue/) Powered by Discuz! X3.1