RMMV脚本教程——菜单美化(一)

RMMV脚本教程——菜单美化(一)

写在前面

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

注意事项

  1. 本教程的灵感来自于【渣作品】RGSS3教程(二) 菜单的美化【2013.8.2-16:40完结】,不如说是该教程直接翻译成的MV版本。
  2. 因为作者特别的菜,所以教程中难免会有一些小(致命)的错误,请大家原谅,另外请大家不吝赐教。
  3. 教程中会用到的参考资料:
  4. 本教程同步发布于Project1论坛,我的博客xjzsq.xyz(未更新…)和ConanKaito论坛的RMMV板块:RMMV脚本教程——菜单美化(一)

    正文

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

    前置知识——场景类Scene和窗口类Window

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

    带图标的金钱显示窗口

    我们先去RMMV原生脚本那里看看他是如何显示金钱的,因此我们打开原生脚本汉化的Scene_Menu.js,这个是我们今天主要修改和参考的对象——菜单场景,我们就是通过修改菜单场景中的各个窗口来达到美化菜单的目的的。
    在里面搜索“金钱”,发现第一处便是:
    //创建金钱窗口()
    this.createGoldWindow();
    
    看不出是什么窗口,于是我们看看这个方法的定义(以createGoldWindow为关键字搜索):
    /**创建金钱窗口 */
    Scene_Menu.prototype.createGoldWindow = function() {
     //金钱窗口 = 新 窗口金钱(0,0)
     this._goldWindow = new Window_Gold(0, 0);
     //金钱窗口 y = 图形 盒高 - 金钱窗口 高
     this._goldWindow.y = Graphics.boxHeight - this._goldWindow.height;
     //添加窗口(金钱窗口)
     this.addWindow(this._goldWindow);
    };
    
    我们知道了,显示金钱的窗口是Window_Gold,考虑到金钱窗口不仅仅显示在菜单上,还会显示在商店等场景中,因此我们重新写一个窗口Window_NewGold来替代Window_Gold,而在Scene_Menu中只需改动createGoldWindow这个方法即可。
    我们打开Window_Gold,看到里面只有50行左右的代码,其中描绘文字是在refresh中(从draw开头的方法名珂以看出来)实现的。那么我们珂以让Window_Gold作为我们新的金钱窗口的父类,我们只需要修改refresh方法即可。
    在js插件文件中插入以下内容,来定义Window_NewGold窗口,并将其父类设成Window_Gold
    //********************
    //带图标的金钱显示窗口
    //********************
    function Window_NewGold(){
     this.initialize.apply(this, arguments);
    }
    Window_NewGold.prototype = Object.create(Window_Gold.prototype);
    Window_NewGold.prototype.constructor = Window_NewGold;
    
    然后重写refresh方法,这里介绍绘制图标的方法drawIcon,用来绘制图标,定义在Window_Base中,其实当我们不知道某个东西是用哪个函数绘制出来的时候,不妨用中文在Window_Base中搜索一下,大多数方法都定义在这里。搜索到drawIcon的方法定义如下:
    /**绘制图标 */
    Window_Base.prototype.drawIcon = function(iconIndex, x, y) {
     var bitmap = ImageManager.loadSystem('IconSet');
     var pw = Window_Base._iconWidth;
     var ph = Window_Base._iconHeight;
     var sx = iconIndex % 16 * pw;
     var sy = Math.floor(iconIndex / 16) * ph;
     this.contents.blt(bitmap, sx, sy, pw, ph, x, y);
    };
    
    我们看到他有3个参数,xy分别是绘制的坐标,iconIndex则是图标的编号,可以在数据库中可以选择图标的任意一个地方看到,如下图:
    icon
    我们可以看到我们想显示的图标的iconIndex是313,因此我们在插件中这样写:
    Window_NewGold.prototype.refresh = function(){
     Window_Gold.prototype.refresh.call(this);
     this.drawIcon(313, 0, 0);
    };
    
    这里Window_Gold.prototype.refresh.call(this);是用来调用他的父类的refresh方法中的内容的,相当于VA脚本中的super。
    最后,我们将Scene_Menu中的createGoldWindow复制过来,然后将其中的窗口改为Window_NewGold:
    Scene_Menu.prototype.createGoldWindow = function() {
     this._goldWindow = new Window_NewGold(0, 0);
     this._goldWindow.y = Graphics.boxHeight - this._goldWindow.height;
     this.addWindow(this._goldWindow);
    };
    
    然后运行测试一下吧!
    coin
    我们可以看到,图标显示出来了呢!
    下面,我们就将对选项窗口进行调整,加上图标来美化它!

    给菜单选项加上图标

    那么绘制选项窗口的窗口类是哪个呢?
    我们同样在Scene_Menu里面搜索“选项”,却发现只能搜到“option”,也就是对应选项窗口里面的那个“设置”,但是翻了下,第二个搜索结果中发现了以下内容,非常像绘制菜单中选项的窗口类:
    /**创建命令窗口 */
    Scene_Menu.prototype.createCommandWindow = function() {
     //命令窗口 = 新 命令窗口(0,0)
     this._commandWindow = new Window_MenuCommand(0, 0);
     //命令窗口 设置处理("item"//物品 , 命令物品 绑定(this))
     this._commandWindow.setHandler('item',      this.commandItem.bind(this));
     //命令窗口 设置处理("skill"//技能 , 命令个人 绑定(this))
     this._commandWindow.setHandler('skill',     this.commandPersonal.bind(this));
     //命令窗口 设置处理("equip"//装备 , 命令个人 绑定(this))
     this._commandWindow.setHandler('equip',     this.commandPersonal.bind(this));
     //命令窗口 设置处理("status"//状态 , 命令个人 绑定(this))
     this._commandWindow.setHandler('status',    this.commandPersonal.bind(this));
     //命令窗口 设置处理("formation"//编队 , 命令编队 绑定(this))
     this._commandWindow.setHandler('formation', this.commandFormation.bind(this));
     //命令窗口 设置处理("options"//选项 , 命令选项 绑定(this))
     this._commandWindow.setHandler('options',   this.commandOptions.bind(this));
     //命令窗口 设置处理("save"//保存 , 命令保存 绑定(this))
     this._commandWindow.setHandler('save',      this.commandSave.bind(this));
     //命令窗口 设置处理("gameEnd"//游戏结束 , 命令结束游戏 绑定(this))
     this._commandWindow.setHandler('gameEnd',   this.commandGameEnd.bind(this));
     //命令窗口 设置处理("cancel"//取消 , 删除场景 绑定(this))
     this._commandWindow.setHandler('cancel',    this.popScene.bind(this));
     //添加窗口(命令窗口)
     this.addWindow(this._commandWindow);
    };
    
    也就是Window_MenuCommand,这个窗口类确实是定义了菜单选项的。
    那么我们打开这个类的js文件,但很不幸的是,即使你把整个文件读一遍,都不会找到什么有价值的东西…
    原因是,绘制菜单选项的drawItem方法是定义在他的父类Window_Command里面…
    他的定义是这样的:(感兴趣的同学可以去Window_Command里面搜搜看)
    /**绘制项目 */
    Window_Command.prototype.drawItem = function(index) {
     var rect = this.itemRectForText(index);
     var align = this.itemTextAlign();
     this.resetTextColor();
     this.changePaintOpacity(this.isCommandEnabled(index));
     this.drawText(this.commandName(index), rect.x, rect.y, rect.width, align);
    };
    
    那我们修改Window_MenuCommand中的drawItem方法就好了。
    既然是绘制图标,那么我们还是要用刚才提到的drawIcon,而且我已经给你们找好了图标的index,分别是:[208, 64, 137, 84, 75, 242, 229, 82],但是我们发现,drawItem方法有一个参数index,这和图标的index不同,对应的是菜单中的第几个选项,这里要注意的是,index是从0开始的,因此drawItem函数每次只描绘一个选项。这样的话,我们可以把图标的编号放到一个数组iconIndex内,这样就可以通过iconIndex[i]快速访问第i个选项的图标的index是多少。
    这样我们就可以开始写了!首先将Window_Command内的drawItem函数的内容复制过来,然后加入图标,大家可以先尝试自己写一写,然后再看我的代码,这里要给大家补充的是,MV中图标的大小是36*36,因此文字的x值应该向右也就是加上36。
    //******************
    //给菜单选项加上图标
    //******************
    var iconIndex = [208, 64, 137, 84, 75, 242, 229, 82];
    Window_MenuCommand.prototype.drawItem = function(index){
     var rect = this.itemRectForText(index);
     var align = this.itemTextAlign();
     this.resetTextColor();
     this.changePaintOpacity(this.isCommandEnabled(index));
     this.drawIcon(iconIndex[index],rect.x,rect.y);
     this.drawText(this.commandName(index), rect.x + 36, rect.y, rect.width - 36, align);
    }
    
    然后运行结果如下:
    command
    好,这篇教程就写到这里。

    作业

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

    后记

    下一篇教程,我们将改造右边的人物绘制的方式,并且改变菜单的背景,像先行图上一样,感谢大家的支持啦~