JavaScript 列车相关
NTE 支持通过 JavaScript 控制列车的渲染全过程。既可以完全用 JavaScript 控制所有部件的渲染,也可以在现有的一个列车类型的显示模型的基础上叠加用 JavaScript 控制的显示内容。
添加车型
在 mtr_custom_resources.json
里使用这样写法即可添加使用 JavaScript 控制渲染的车型。
{ "custom_trains": { "s_train_suspend": { "name": "JS Test Train", "base_type": "train_9_2", "color": "2AF0AD", "script_files": [ "mtr:js_train/main.js" ], "bve_sound_base_id": "optonix1500" } } }
可包含的内容和 MTR 原版添加车型时的相同,相当于写一个标准的 MTR 自定义列车,然后再添加 script_files
属性。
如果不含有 base_type
这个参数,将首先原样显示由其余内容设定的列车外观,然后把 JavaScript 控制的渲染内容叠加在上面。如果含有 base_type
这个参数,则会纯粹用 JavaScript 来显示它的外观。
属性 | 说明 |
---|---|
basetype | 列车的交通类型、长度和宽度。如 train_19_2 。如果有这个属性,会纯粹用 JavaScript 来显示它的外观,即忽略 base_train_type 、model 等参数;否则会按照base_train_type 、model 等显示一个外观再把 JavaScript 控制的内容叠加在上面。 |
| scriptfiles | 一个数组,包含要使用的 JS 文件的资源位置。可以使用多个 JS 文件。 |
scripttexts | 可选,一个数组,包含要运行的一些 JS 纯文本内容(会在 scriptfiles 之前运行)。可以用于需要给多个列车使用同一脚本,而又想设定一些各个列车之间不相同的设定的情况。 | |
hasgangwayconnection | 是否可以通过贯通道走到其他车厢。没有这项时采取 basetraintype 的设置。 |
isjacobsbogie | 是否是铰接转向架。只影响 BVE 列车音效的轮轨声音播放。 |
bogie_position | 非铰接的转向架距离车中点的距离。只影响 BVE 列车音效的轮轨声音播放。 |
全局环境
同一车型的所有列车共享同一个运行环境(即全局变量等)。
写在函数以外的顶层空间内的代码会在资源包加载时运行,可用于加载模型、贴图等资源。推荐将不需要每列车都不同的资源(如模型等)存储在全局变量,避免相同内容每列车都加载一份带来过多内存占用。
您要定义的函数
您的脚本中应包含以下函数,NTE 会按需调用它们:
function create(ctx, state, train) { ... } function render(ctx, state, train) { ... } function dispose(ctx, state, train) { ... }
函数 | 说明 |
---|---|
create | 在列车最开始被加载时调用,可用于进行一些初始化的操作,例如创建动态贴图。 |
render | 大致每帧调用一次。用于主要的显示逻辑。代码在单独线程上运行以便不拖低 FPS。如果代码耗时太长,就可能实际上好几帧才运行一次。 |
dispose | 在列车驶出可视范围时调用。可用于释放动态贴图之类的操作。 |
NTE 调用这几个函数时会使用三个参数,稍后介绍其各自的内容。
参数 (本文中称呼) | 说明 |
---|---|
第一个 (ctx ) | 用于向 NTE 输出要如何渲染列车的相关操作。类型是 TrainScriptContext。 |
第二个 (state ) | 一个和某列车关联的 JavaScript 对象。初始值是 {} ,可随意设置其上的成员,用来存储一些需要每列车都不同的内容。 |
第三个 (train ) | 用于获取列车的状态。类型是 Train。 |
接下来列出您可以进行的所有渲染控制操作,和可以获取到的所有关于列车的信息。
TrainScriptContext
调用以下函数可以控制渲染。每次 render
时都需要为想绘制的模型调用相应的函数,
TrainScriptContext.drawCarModel(model: ModelCluster, carIndex: int, poseStack: Matrices): void
TrainScriptContext.drawCarModel(model: DynamicModelHolder, carIndex: int, poseStack: Matrices: void
要求 NTE 在一节车厢处绘制模型。carIndex
:模型放置位置相对于哪节车厢的中心(0
为相对于出库方向的第一节,train.trainCars() - 1
为最后一节)。原点位置是列车的中心,离地高 1m 处。poseStack
:模型放置位置的变换,传入null
表示就放在中心不变换。TrainScriptContext.drawConnModel(model: ModelCluster, carIndex: int, poseStack: Matrices): void
要求 NTE 在车厢连接处绘制模型。carIndex
:模型放置位置相对于第几个连接处(0
为相对于出库方向的第 1 和 2 节之间,train.trainCars() - 2
为最后一个)原点位置是连接处的中心,离地高 1m 处。poseStack
:同上。TrainScriptContext.drawConnStretchTexture(location: ResourceLocation, carIndex: int): void
要求 NTE 在车厢连接处绘制与 MTR 原版相同的可拉伸折蓬。为节省性能,要输入的图片是 MTR 原版的四张图片合并成一张。其中左上四分之一是外侧,右上四分之一是内部侧面,左下四分之一是内部顶面,右下四分之一是内部底面。
调用以下函数可以播放声音。只在需要开始播放时调用,重复调用会使多个声音叠加。TrainScriptContext.playCarSound(sound: ResourceLocation, carIndex: int, x: float, y: float, z: float, volume: float, pitch: float): void
播放声音。可设定声源位置,能被所有附近玩家听到。TrainScriptContext.playAnnSound(sound: ResourceLocation, volume: float, pitch: float): void
播放广播声音。只能被当前在车上的玩家听到。
此外,还有一组函数以 辅助开发调试。TrainScriptContext.setDebugInfo(key: String, value: Object)
在屏幕左上角输出调试信息。需在设置中开启 “显示JS调试信息” 才会显示。key
为值的名称,value
为内容(GraphicsTexture
类型的会被显示出来,其他的会被转为字符串显示)。
Train
属性 说明 train.shouldRender(): boolean
现在是否应该显示这列车。在打开 “隐藏正在乘坐的列车” 时,JS 脚本仍然会照常运行,以保证如广播的功能还可以照常运作。此时这个函数会返回 false
以便关闭如粒子效果的功能。注意不需要用这个来判断停止drawCarModel
,NTE 会自动让它调用也没有效果。train.shouldRenderDetail(): boolean
列车是否在细节显示范围(32 格)以内。推荐在它为 false
的时候停止处理如广播、显示屏、细节模型等来节省性能。train.trainTypeId(): String
车型 ID。 train.baseTrainType(): String
基于的车型 ID。 train.id(): long
这辆车在 MTR 内部的唯一编号,是一个随机的 64 位整数。
在 JavaScript 里可能因为有效数字位数不够,末尾的几位变成 0?train.transportMode(): TransportMode
交通方式种类。 train.spacing(): int
每节车的长度 + 1。 train.width(): int
宽度。由于玩家也有宽度,3 格宽的车的这一属性是 2。 train.trainCars(): int
车厢数。 train.accelerationConstant(): float
加速度。单位是 m/tick/tick,即 *1/400 m/s。 train.manualAllowed(): boolean
是否可以人工控制。 train.maxManualSpeed(): int
人工控制时的最大速度。是和轨道类型从低到高的顺序对应的。 train.manualToAutomaticTime(): int
无人驾驶后转回自动控制的时间。 train.path(): List<PathData>
行驶路径,即要经过的每段轨道的列表。每一项是一个 PathData
。train.railProgress(): double
从车库开出的距离。 train.speed(): float
速度。单位是 m/tick,即 *1/20 m/s。 train.doorValue(): float
车门开度。关门为 0,全开为 1,开门时增加关门时减少。 train.doorValue(): float
车门开度。关门为 0,全开为 1,开门时增加关门时减少。 train.isDoorOpening(): boolean
是否正在开门。 train.doorLeftOpen[carIndex: int]: boolean
某一车厢的左侧车门是否可以打开。 train.doorRightOpen[carIndex: int]: boolean
某一车厢的右侧车门是否可以打开。 train.isCurrentlyManual(): boolean
是否正在被人工控制。 train.isReversed(): boolean
是否已折返,即现在 1 号车是车尾。 train.isOnRoute(): boolean
是否已出库。 *
train.getRailProgress(car: int): double
相对于当前行驶方向的车头,从 0 开始计第car
车前方的从车库开出的距离。如getRailProgress(1)
是 1/2 车连接处的位置。train.getRailIndex(railProgress: double, roundDown: boolean): int
计算某个railProgress
是位于在path()
中的第几项的这条轨道上的。如果这个位置正位于两条轨道交界,roundDown
为true
时返回更靠车尾方向的一条,否则返回更靠车头方向的一条。train.getRailSpeed(railIndex: int): float
path()
中的第railIndex
项的这条轨道可通行的最高速度。它能正确处理这段轨道是站台时列车不应该进站还加速的情况。单位是 m/tick,即 *1/20 m/s。train.getAllPlatforms(): List<PlatformInfo>
列车指令里所有线路行经的所有站台的列表。每一项是一个PlatformInfo
。在站台上折返时只算作一项。train.getAllPlatformsNextIndex(): int
列车下一站(这个值在列车出站时更新,所以停在站台时则是这一站)要停靠的站台是在getAllPlatforms()
的列表里的第几项。 0 代表刚刚出库正前往第一个站台,等于getAllPlatforms().size()
代表正在回库。注意因此它并不一定在getAllPlatforms()
的索引范围内,需要判断。train.getThisRoutePlatforms(): List<PlatformInfo>
列车现在行驶的线路行经的所有站台的列表。每一项是一个PlatformInfo
。train.getThisRoutePlatformsNextIndex(): int
列车下一站要停靠的站台是在getThisRoutePlatforms()
的列表里的第几项。 0 正前往第一个站台,等于getThisRoutePlatforms().size()
代表正在前往下一条线路起点或回库。注意因此它并不一定在getThisRoutePlatforms()
的索引范围内,需要判断。
PathData
属性 说明 PathData.rail: Rail
这段轨道;详情见 MTR 源码 Rail.java
。PathData.rail.railType: RailType
这段轨道的轨道类型(木、铁……);详情见 MTR 源码 RailType.java
。PathData.rail.getModelKey(): String
这段轨道所使用的 NTE 轨道模型。未设置为空字符串,隐藏为 "null"
。PathData.dwellTime: int
如果这段轨道是站台的话,列车要停车的时间。不是站台时为 0。单位是 *0.5s。 PlatformInfo
属性 说明 platformInfo.route: Route
这个站台所属的路线。在站台上折返时,是折返后的路线。详情见 MTR 源码 Route.java
。PlatformInfo.route.name: String
这个站台所属的路线的名称。 PlatformInfo.station: Station
这个站台所属的车站。详情见 MTR 源码 Station.java
。PlatformInfo.station.name: String
这个站台所属的车站的名称。 PlatformInfo.platform: Platform
这个站台。详情见 MTR 源码 Platform.java
。PlatformInfo.platform.name: String
这个站台的名称。 PlatformInfo.platform.dwellTime: int
这个站台的停车时间,单位是 Tick (1/20 s)。 PlatformInfo.destinationStation: Station
这个站台所属的路线的终点站。详情见 MTR 源码 Station.java
。PlatformInfo.destinationStation.name: String
这个站台所属的路线的终点站的名称。 PlatformInfo.destinationName: String
这个站台的终点名称(考虑自定义终点名称) PlatformInfo.distance: double
这个站台末端所在位置从车库开出的距离,可以拿来和 railProgress 比较。 PlatformInfo.reverseAtPlatform: boolean
列车是否会在这个站台上折返。