跳到主要内容

从RMMZ开始的 js 入门

原文:『RPGツクールMZ』で始めるJavaScript入門

通过以上两篇文章,我想大家应该已经能够使用脚本事件命令了(下文将以此为前提进行说明)。

但是,也有人虽然能用,却不明白为什么能运行,对 js 的基本部分一知半解而感到不踏实吧。

虽然读了上面推荐的那些网站,但总觉得还是不太明白,甚至无从下手。

或者说,“反正 HTML 什么的怎样都无所谓啊!为什么非得从那里开始学啊!傻了吗!”——我想也有人这么想吧。

这些推荐的网站其实是相对不涉及 HTML、只写 js 部分的那一类,但反过来可能正因为这样反而让人看不懂。

另外,这些网站本身的信息是可靠的,写得也相当通俗易懂,所以在学习 js 时完全可以充分利用。只是没有考虑到 rmmz 的情况而已。

因此,我决定写一篇从 rmmz 入手学习 js 的入门文章。

本文将主要围绕脚本事件命令的使用方法,在 rmmz 编辑器上进行说明。

制作插件时也基本可以使用相同的脚本,所以想制作插件的人也可以参考,但本文不会描述插件中的 js 相关内容。

顺便一提,rmmz 官方的“最速 js 讲座”是作为插件入门的一部分编写的,但作为连接 js 与 rmmz 的部分,内容相对简短易懂,因此推荐阅读。

话说回来,本文的目标是让大家能够读懂下面链接的参考文档。

rmmz 非官方 js 参考文档

所谓“能够使用”,目标仅限于简单的内容。

因为要想全部都能使用,需要直接阅读并理解核心脚本。

而且,我自己也无法全部使用,所以没法说明(笑)。

另外,下文介绍的各网站作者名均省略敬称。

术语

以下内容也在rmmz脚本应用中写过,但最后又补充了几点。遇到不认识的术语时请参考。

数组:给值编号并排列而成的值。示例:[ 10, 4, 6 ](这里排列的是数字作为值,也可以排列其他类型的值)。

索引:从数组(保存数组的变量)中取出值时使用的数字。示例:array[ 0 ](js 数组的索引从 0 开始)。

字符串:字符排列而成的值。在 js 中对应 String 类型。也可以看作是每个元素被固定为一个字符的数组。示例:"这是字符串"

布尔值:取真(正・ON)和假(负・OFF)两种状态的值。在 js 中对应 Boolean 类型,两个值分别表示为 truefalse

逻辑运算:计算结果返回布尔值的运算。包括判断数值大小等的条件表达式。

变量:用于保存值。js 中的变量与 rmmz 中的变量大致相同。定义示例:let variable; 以前定义变量使用 var 而非 let,但由于 var 存在较多问题,现在(2022 年)已不太常用。反过来,如果看到代码中使用 var,即使是初学者也能轻易判断出这是旧代码。另外,在 rmmz 中,核心脚本已经废弃了 var

常量:与变量大致相同,但一旦设定值后便无法更改。乍看似乎不便,但实际上比变量更便利,在实际编程中几乎不需要使用变量。定义示例:const constant = 1;

函数:将处理过程汇总而成的结构。与 rmmz 的公共事件大致相同,但由于具有参数和返回值,使用起来更为方便。另外,脚本事件命令也可以编写多个处理,因此也可以说是一种函数;在变量操作中的脚本选项等地方也存在返回值。js 由于历史原因,函数的定义方式非常多,这一点比较麻烦。定义示例:function addOne( arg ) { return arg + 1; };const addOne = arg => arg + 1;

参数:在执行函数时写在 () 内并传递的值。函数可能没有参数,也可能有多个参数。

返回值:函数返回的值。有的函数有返回值,有的没有。

对象:将相关的值(属性)和功能(方法)汇总而成的结构。js 程序就是由对象组合构建而成的。

属性:附加在对象上的变量。但与普通变量不同的是,有些属性的值会随对象的状态而改变。反过来,通过设置属性也可能改变对象其他属性等的状态。在对象后加 . 再指定。示例:object.property

只读属性:附加在对象上的只读值。但与常量不同的是,有些只读属性的值会随对象的状态而改变。read only 常简写为 ro 或 r/o。

方法:附加在对象上的函数。通常用于加工属性。在对象后加 . 再指定,并在 () 中指定参数。示例:object.method()

追加术语

:被描述为对象的蓝图或类型,是一个程序模块。

实例:从类通过 new 生成的对象。通常直接称为对象,因此这是一个不太常用的术语。

核心脚本:定义了 rmmz 所制作游戏中所需的类的脚本。实际上,在 rmmz 中使用 js 就是操作这个核心脚本。反过来,一般 js 程序员并不了解它,因此即使去问他们,也很可能被说“那是什么”。

:为制作特定目的的程序而将所需功能汇总而成的程序,是供其他程序调用的程序。通过使用库,无需从头构建程序,可以相对简单地扩展功能。

局部变量:程序通过细分为类、函数等来划分作用域,阻止其他作用域访问变量,从而防止复杂度上升。被封闭在这样作用域内的变量就是局部变量。

全局变量:全局变量是例外,可以从程序的任何作用域中操作。

静态类:无需从类生成对象,直接指定类名即可使用的类。与全局变量一样,可以从程序的任何作用域中操作。

静态属性:附加在静态类上的属性。在参考文档中带有 static 标记。

静态方法:附加在静态类上的方法。在参考文档中带有 static 标记。

コアスクリプトのクラスツリー

さて JavaScript の歴史とかは知りたい人だけ本とかWebで調べてもらうとして、ツクールです。 とりあえず、次のリンク先をざっと見て帰ってきてください。

RPGツクールMZ 非公式JavaScriptリファレンス - クラスツリー

英単語がぐわーーーッと並んでいたと思います。 階層化された様子が木に似ているということでクラスツリー(class tree)なんて言ったりします。 これがコアスクリプトで定義されているクラス(オブジェクト)です。 …え、こんなにたくさんあるの!?って思ったでしょうが、あるんですよ。 ただこれ全部把握するのは大変ですし、なんなら僕も把握してません。

ま、とにかく。これらのオブジェクトを操作するのが『RPGツクールMZ』における JavaScript というわけです。

核心脚本外部的 js

首先,正如 rmmz 可以在像“アツマール”这样的 Web 浏览器上运行一样,它是运行在 Web 浏览器功能之上的。

其次,rmmz 中使用了名为 PixiJS 的绘图库和名为 Effekseer 的特效动画库。

因此,虽然也可以使用 Web 浏览器自带的 js 对象,但基本上可以忽略它们。

PixiJS 官网

Effekseer 官网

另外,在本地运行的情况下(Mac 为 .app 格式,Windows 为 .exe 格式),会使用名为 NW.js 的环境,该环境可在本地运行与浏览器相近的 HTML+js。

虽然有点复杂,但 NW.js 在其环境中拥有一个名为 Node.js 的、可以处理文件等的库。

NW.js 官网 Node.js 官网

执行测试游戏时,是否注意到有一个名为“nwjs”的应用程序启动了?就是那个。

这些库都是通过刚才看到的类树中的对象来使用的,因此没有必要特意直接使用它们。

但是,js 自身所拥有的基础类,在脚本事件命令中也会经常使用。

核心脚本的三个组成部分

刚才看到的类树可以说是材料,要让其运行,必须将它们组装起来。

在 rmmz 中,执行测试游戏等开始游玩的那一刻,这些材料就已经组装完成了。

因此,每个 rmmz 用户都不需要考虑如何组装对象。轻松!

因此,rmmz 用户需要理解的是 rmmz 是如何组装对象的。

其构成要素大致分为数据库、游戏对象和管理器这三个部分。

数据库

是以 $data 开头的全局变量。由于它就是编辑器中设置的数据库内容本身,因此可以认为您已经有所了解。

数据库保存在 data/文件名.json 文件中,因此有时也被称为 JSON 数据。在参考文档 Global#数据库 中也可以确认,这里将其整理为表格。

说明变量名数组
角色$dataActors⚪︎
动画$dataAnimations⚪︎
防具$dataArmors⚪︎
职业$dataClasses⚪︎
公共事件$dataCommonEvents⚪︎
敌人$dataEnemies⚪︎
物品$dataItems⚪︎
当前地图$dataMap-
地图列表$dataMapInfos⚪︎
技能$dataSkills⚪︎
状态$dataStates⚪︎
系统$dataSystem-
图块组$dataTilesets⚪︎
敌群$dataTroops⚪︎
武器$dataWeapons⚪︎
信息

由于几乎原样保留了 JSON 文件的结构,因此在游戏中其值不会发生变化。 但是仅限 $dataMap,每次移动地图时会重新加载,因此会随地图变化。

当数组列为 ⚪︎ 时,例如查看 $dataActors参考文档 Global#数据库 开头的部分,会有如下描述。

$dataActors :Array.<[RPG.Actor](https://github.com/tonbijp/RPGMakerMZ/blob/master/Reference/RPG.Actor.md)>

角色用 JSON(Actors.json)。

Array 是指数组,表示名为 RPG.Actor 的数据被按顺序编号记录。

因此,在变量后面写 [索引] 来指定,就会返回与索引编号对应的数据。

$dataActors[ 1 ]

这种情况下,是编辑器中数据库 -> 角色 里角色 ID 为 1 的数据。

点击写有 <RPG.Actor> 的部分的链接查看详细页面,会在属性一栏看到排列的英文单词,并写有与数据库窗口中看到的标签之间的对应关系。

在变量后面继续写 . 再加这些属性名,就可以获取各个值。

例如,如下写法即可获取角色 ID 1 的“名字”。

在测试游戏时,复制到按 F8(或 F12)打开的“控制台”中,就会显示该值。

尝试改变数字、删除 .name 部分、或者改写成其他属性试试看。

总结来说,rmmz 中准备了全局变量 $dataActors,它是一个数组,因此写 [ 1 ] 就能得到角色 ID 1 的 RPG.Actor 信息,接着写 .name 就能得到角色 ID 1 的“名字”信息。

角色以外的数据库项目也可以用同样的指定方法获取。

属性有时本身是数组,有时还进一步拥有其他属性。

这种情况下,如果是数组就继续写 [索引],如果是属性就继续写 .属性,这样连接下去即可。

$dataActors[ 1 ].equips[ 2 ]
$dataActors[ 1 ].traits[ 3 ].code

另外,$dataMap$dataSystem 不是数组,因此不需要索引。

例如,如下写法即可获取“显示名称”。

$dataMap.displayName

具体的写法,可以搜索トリアコンタン编写的 rmmz 脚本参考文档#数据库,按值的名称查找并确认“获取脚本”中的脚本内容。

备注(元数据)

能够处理数据库中包含的备注(元数据)后,就可以实现标准功能难以完成的处理。

详细内容请参考rmmz 脚本应用#元数据

游戏数据

$game 开头的全局变量是在游戏中使用的对象。

可以控制游戏的各种行为。而且其中大部分也兼作存档数据,会保存在存档文件中。

参考文档 Global#游戏数据 中也可以确认,这里将其整理为表格。

说明变量名存档
角色$gameActors⚪︎
地图$gameMap⚪︎
消息$gameMessage-
队伍$gameParty⚪︎
玩家$gamePlayer⚪︎
画面管理$gameScreen⚪︎
独立开关$gameSelfSwitches⚪︎
开关$gameSwitches⚪︎
系统$gameSystem⚪︎
临时数据$gameTemp-
计时器$gameTimer⚪︎
敌群$gameTroop-
变量$gameVariables⚪︎

关于游戏数据的获取示例,查看トリアコンタン编写的 rmmz 脚本参考文档#游戏数据,就能明白这里的描述方法。

属性的指定方法与数据库相同,因此省略。

游戏数据与数据库的一大区别在于,游戏数据拥有方法。

另一个区别是,属性不仅仅是获取值,更多的是对值进行赋值。

管理器

带有 Manager 的静态类用于管理游戏中使用的数据等。

参考文档:类树#管理器

管理器的功能大体上从名称就能看出,但有时也会缺少预期中的功能。

类树

说起来,之前还没有解释过为什么类树会像树木一样分支。

类通过一种称为“继承”的机制,可以以一个类为基础创建多个不同的类。

在 rmmz 中,例如以 window 类为基础,创建了大量的相关类。

参考文档:类树#窗口(Window)

在 rmmz 制作的游戏中有各种各样的窗口,但所有窗口在“有框且能写字”这一基本部分都是相同的,因此创建一个通用化的类,然后在继承它的子类中只定义不同的部分,从而省去重复劳动。

被继承的类称为超类,继承后的类称为子类。你可能在参考文档的说明中见过这些词。

正如前面所述,由于复用了被继承类的功能,因此在超类中可用的属性和方法也都能直接使用。

在参考文档中,“从超类继承的方法”会列出清单,但属性则没有列表化。

但实际上超类的属性也是可用的。参考文档中,带有 _ 的属性建议尽量不使用,而且也不太想让它们太显眼,再加上也很麻烦(笑),所以就没有把从超类继承的属性列表化。

当你觉得“怎么没有像表示坐标的 xy 这样的标准属性”时,向上追溯到超类,就会发现在某处有定义。

顺便一提,核心脚本中也有很多类是从前面提到的 PixiJS 对象继承而来的,主要的部分已经转录到了参考文档中。

通过继承使功能通用化,整体上变得更易于理解,但当你只想调查某一个类时,却必须去追溯其继承来源的超类,因此在这方面反而变得难以把握。

如果你打算深入使用到制作插件的程度,那么建议先浏览类树,掌握大致的框架。

对象的生成

在脚本中编写 js 时,通常使用的是已经生成好的对象。

$data$game 系列的全局变量就是如此。

或者直接使用 Manager 系列的静态类,或者使用存放了静态类对象的属性。

因此,大部分对象都已经生成好了,所以需要重新生成对象来使用的情况应该很少,但还是在此说明一下。

new 类名()

在类的说明中,有时会写有 new 类名()

那是在生成实例时的写法以及参数的说明。

像下面这样生成一个新的对象,并将其存入常量中使用。

const rect = new Rectangle( 360, 8, 100, 400 );

Rectangle 参数的详细内容请参考以下参考文档。

参考文档:Rectangle

也可以不存入常量而直接写在方法的参数中,但这样会降低可读性,因此不推荐。

关于 RPG 和 MV

看参考文档时,可能会时不时看到带有 RPG.MV. 前缀的类。

这些在下面的链接中也有说明,是笔者在非官方参考文档中自行命名的。

因为在参考文档中,如果没有名字的话会非常难以处理。

参考文档:命名空间:RPG

参考文档:命名空间:MV

RPG. 是为了数据库而创建的东西。从这个意义上说,查看 JSON 文件就能找到其格式定义。它被记录在 $data 系列的全局变量中。

MV. 是因为各种方法的参数和返回值存在一定的格式,而对那种格式进行说明的东西。硬要说的话,方法的代码(程序)就是定义。

这些在 js 中只是 Object 这种数据类型的一种。可以说是“伪对象”。

这里,伪对象的类名是 Object 这一点非常令人困惑……我认为这是导致 js 难以说明的首要规格。

话虽如此,由于是伪对象,创建时不用 new,例如对于 MV.Size 就像下面这样写。

const size = { width: 10, height: 8 };

想必一看就懂,但用语言描述的话,就是用 {} 将整体括起来,属性和值之间用 : 分隔,每个属性之间用 , 分隔。

MV.Size 这个名字只是为了方便而起的,实际上并不存在叫这个名字的类,只是像这样用符号分隔并排列数据而已。

属性的详细内容请参考参考文档。

参考文档:MV.Size

这种用属性名汇总起来的值,有时被称为“Object 类型的值”。有时也简称为“对象”,真是麻烦。

另外,在这个例子中我们赋值给了常量,但有时也会直接写在参数中。

此外,方法的返回值有时也是这些格式的值。

以上就是对象以及伪对象(即 Object 类型的值)的生成方法。

小知识

追溯 js 的类继承,最终都会到达 Object 类。

虽然我前面写了“伪对象”之类的说法,但实际上它同时也是“所有对象的父类”。

不过,由于它经常被用作数据类型,所以真希望类名不是 Object,而是叫 Record 之类的。

我想所有 js 程序员都这么觉得(笑)。

另外,从被称为 ES6 的 js 版本开始,提供了一种名为 Map 的数据类型,它解决了把 Object 类型当作数据类型使用时的问题。

Map 类型在 rmmz 中也可以使用,不过因为游戏中本身就有地图显示,所以会有点容易混淆。

关于 this

在看脚本事件命令的示例脚本时,我想你应该频繁地看到 this 这个单词。

粗略地说,this 中存放的是包含当前脚本的对象。

在脚本事件命令的情况下,这个对象是 Game_Interpreter

因此,在 this 后面可以接着写以下参考文档中的属性和方法。

参考文档:Game_Interpreter

例如像下面这样。

this.setWaitMode( "message" );

在脚本移动命令的情况下,this 中存放的是移动路线的执行对象,即事件或玩家。

因此,在 this 后面可以接着写以下参考文档中的属性和方法。

参考文档:Game_Event

参考文档:Game_Player

例如像下面这样。

this.setDirection( 8 );

到了这个程度,如果不掌握核心脚本的内容,我想很难方便地使用它。

当你要复制的脚本中含有 this 时,你只需要想着“原来如此,就是之前读过的那个东西啊”大概就可以了。

最后

希望通过以上内容,大家能够勉强读懂 rmmz 非官方 js 参考文档

正如开头所写,我认为要能够使用全部核心脚本是很困难的。

不过,通过本文,我认为至少可以达到这样的程度:“当有想实现的处理时,能在参考文档中搜索,运气好的话就能发现知道如何使用的属性或方法”。

或者,“在复制了脚本之后,通过参考文档查阅方法的参数,然后改写参数”等等。

毕竟使用 rmmz 的目的是制作作品,因此过度深入 js 反而本末倒置。

比如我自己,就是因为过于深入,结果完全没做出作品来(笑)。

不过,以此为契机彻底沉迷于 js,那也是一种乐趣。

以下讲解了在变量中放入数值以外内容的使用方法。 在 rmmz 中使用字符串和数组

以上でRPGツクールMZ 非公式JavaScriptリファレンスがなんとか読めるようになってもらえれば幸いです。

最初に書いたように、コアスクリプト全部を使えるようになるのは難しいと思います。 とはいえこれで「やりたい処理があった場合にリファレンス内を探して、うまくいけば使い方のわかるプロパティやメソッドを発見できる」というぐらいにはなれるとは思います。 あるいは「スクリプトをコピーしてきた後に、メソッドの引数をリファレンスで調べて引数を書き換える」とか。

そもそも『RPGツクールMZ』で作品を作るのが目的なのですから、あまり JavaScript に深入りするのは本末転倒だと思います。 僕なんか、深入りしすぎて全然作品が作れてません(笑)

ただ、これを機会に JavaScript にズッポリハマってしまうのも、それはそれで楽しいかもしれません。

レッツエンジョイ ツクールライフ!

変数に数値以外を入れる使い方を解説しました。 『RPGツクールMZ』で文字列・配列を使う