Rpg Maker MZ Next:现代 Rpg Maker MZ 框架

现代 RPG Maker MZ 框架

:warning: 开发中 — 本项目正处于积极开发阶段,尚未准备好用于生产环境。API 可能会发生变化,功能可能不完整,且随时可能出现破坏性变更。欢迎贡献和反馈,但在宣布稳定版本之前,不建议在正式项目中使用。


这是什么?

RPG Maker MZ Next 是对 RPG Maker MZ 运行时 的现代化改造,基于 PixiJS v8TypeScript 重建,使其符合当代 Web 开发标准。

此次重写专注于 运行时引擎 —— 编辑器保持不变。RPG Maker MZ 创建的项目是目标对象,但底层的执行层将被替换为:

  • PixiJS v8 渲染 — 利用其 WebGL/WebGPU 管线、场景图以及相较于旧版渲染器的性能提升。
  • 完整的 TypeScript 重写 — 全栈严格类型支持,提供更好的 IDE 支持、更安全的重构以及系统间更清晰的契约。
  • 原生 ESM 支持 — 运行时和插件生态均围绕 ES 模块构建,支持正确的依赖管理、Tree-shaking 以及面向插件开发者的现代化创作体验。
  • 面向开发者的工具类 — 一套实用类和辅助类,旨在使插件开发、场景管理和引擎扩展更加符合人体工程学。

为何存在此项目以及目标用户

此项目源于好奇与挫败感的交织。为 RPG Maker MZ 开发有时令人感到乏味 —— 编码体验与更广泛的 PixiJS 生态脱节,被沙盒机制限制得弊大于利,且缺乏开发者们习以为常的现代化工具。因此,与其在这些痛点上绕道而行,我决定直接解决它们。

这仅仅是一个有趣的项目吗?绝对是。但那种挫败感是真实的,希望最终成果能对有同样感受的其他人有所帮助。

本项目主要面向严肃的开发者,他们希望从 RPG Maker MZ 中获得真正的力量和灵活性 —— 那些发现自己更多是在与引擎对抗而非利用它构建游戏的人,他们需要一个能退居幕后、让他们按自己真正想要的方式工作的基础。

如果这听起来像你,欢迎回家。

开源与社区驱动

RPG Maker MZ Next 是一个完全开源的项目,托管于 GitHub。虽然它在底层对运行时进行了现代化改造,但它完全尊重并在 Kadokawa 的 RPG Maker 服务条款范围内运行。

这个帖子不仅仅是一个公告 —— 它是一份邀请。本项目旨在成为一个协作项目,由实际使用和为 RPG Maker MZ 开发的人们共同塑造。无论你是插件开发者、游戏开发者,还是仅仅拥有想法和观点的人,你的声音在这里都很重要。

对运行时应如何运作有想法?对插件 API 设计有看法?功能请求、担忧,或仅仅是对其发展方向的好奇 —— 请畅所欲言。我们的目标是构建社区真正想要的东西,而这始于这场对话。代码仓库欢迎贡献、反馈和讨论。目前项目的方向尚未定型,这是有意为之。

让我们一起构建它。

:warning: 插件兼容性

由于 RPG Maker MZ Next 是对运行时的 完整重写,绝大多数现有的 MZ 插件 无法开箱即用。这是两个重大转变带来的预期且不可避免的后果:

  • 渲染层已从 PixiJS v5 迁移至 PixiJS v8,后者引入了重大的破坏性 API 变更。
  • 代码库现在基于 TypeScript 和 ESM,脱离了大多数插件所依赖的原始全局脚本架构。

这并不意味着你喜爱的插件将永远消失。我们的计划是通过提供清晰的迁移指南、文档完善的插件 API 以及在可行情况下的兼容性工具,尽可能平稳地过渡。插件开发者将拥有适当的工具来移植和现代化他们的工作。

如果你是一位希望抢占先机的插件开发者,我们非常欢迎你对插件 API 的贡献和早期反馈。

7 个赞

正在开发一个类似的项目,我称之为“RPG Reactor”。它同样支持 PIXI8,并通过一个兼容性垫片(compatibility shim)动态将函数调用重写为 PIXI8 的等效调用,从而保留了向后兼容性。

引擎的核心部分已经完成并正常运行,目前我正在开发我称之为“锻造台”(the forge)的部分——一套用于动态创建游戏中各种资源的工具。该项目也将开源,敬请期待!

2 个赞

太棒了!

我认为,我放弃向后兼容的决定,本质上是为了让引擎能够进行更精简的重构?

基本上,我只是不想简单地移植旧代码,而是希望对其进行改进?

例如:完善的插件管理器工具、插件参数解析等。

为玩家和精灵内置支持动画精灵。

等等。

起初兼容性确实是一个考虑因素,但随着工作的深入,破坏性变更不可避免,尤其是对于那些依赖精灵操作的插件,因为 PixiJS 不再支持叶子子节点了。

我在 TypeScript 工具方面工作的一个重点是类装饰器的支持。

它运行得非常完美,特别是 TypeScript 中的装饰器可以完美地进行 polyfill。

@Psychronic 其实我有点好奇,目前最大的瓶颈是 Window Layer 类,不知道你是如何处理这个问题的?因为 PixiJS 不支持内部 GL 调用?

1 个赞

附件是 RPG Reactor 的核心脚本,兼容性补丁位于 libs 文件夹中,欢迎大家自行查看!

RPG Reactor 0.9 - 核心脚本.zip (642.3 KB)

长话短说:
修复方法是:在 Pixi v8 中跳过自定义的 GL-stencil 渲染,让标准渲染管线遍历子元素。

WindowLayer.prototype.render = function render(renderer) {
if (!this.visible) return;

// v8: 渲染管线会自动处理子元素。v8 移除了
// renderer.framebuffer.forceStencil(模板缓冲区在
// 上下文创建时默认分配——参见 pixi8 `stencil: true` ContextSystem
// 初始化),且 renderer.batch 不再是全局可刷新的批处理器
// (每个渲染管线都有自己独立的延迟批处理器)。在 v8 的延迟管线中
// 穿插原始 GL 模板操作也不符合绘制顺序。
//
// 在 v8 中跳过自定义渲染,让标准渲染管线遍历
// 子元素。视觉效果上:下层窗口的像素在高层窗口下方
// 被绘制,但随即被覆盖——对于正常的 MZ 使用场景,没有可见的回归问题。v5/v6/v7 保留下方的默认模板遮挡行为。
if (PIXI.TextureSource) {
    return;
}

// ... 下方原始的 v5/v6/v7 模板遮挡块保持不变 ...

};

  1. 使用 PIXI.TextureSource 进行版本检测,该类仅存在于 v8 中。这是一种廉价且可靠的特性嗅探方法,使同一文件能够在 v5/v6/v7/v8 之间多态工作。
  2. 为什么在 v8 中不再需要模板操作:
  • renderer.framebuffer.forceStencil() 已移除,v8 的 ContextSystem 在创建上下文时分配模板缓冲区(默认 stencil: true)。
  • renderer.batch.flush() 已移除,v8 拥有每个管线独立的延迟批处理器,没有全局刷新钩子。
  • renderer.gl 已移除,v8 抽象了后端(WebGL 或 WebGPU),因此直接的 gl.stencilFunc / gl.stencilOp / gl.blendFunc 调用没有目标对象。
  1. 跳过它会有什么损失:原始模板操作的目的是防止下层窗口的像素在高层窗口覆盖的区域下方被绘制(这是一种小幅度的填充率优化,也是一种避免重叠半透明窗口之间 Alpha 溢出的方法)。实际上,由于 v8 无论如何都按 Z 顺序绘制窗口,上层窗口会在同一帧中覆盖下层窗口,对于典型的 MZ 使用场景,视觉效果相同。唯一的边缘情况是重叠的半透明窗口,其与下层图层的 Alpha 混合可能会有细微差异;但在实际的 MZ 场景中,引擎永远不会像那样重叠两个透明窗口,因此在测试中未出现回归问题。

这里还有一些截图,我亲自测试过了!

明白了!我之前在这里遇到了很大的瓶颈,确实,大多数窗口管理器永远不会真正地将窗口彼此“推”在一起(用户自定义窗口除外)。

我原本的想法是通过 RenderTexture 来合成窗口,基本上实现批处理和遮挡剔除。这是大多数游戏框架(如 MonoGame)的做法,它们会在刷新时渲染 RenderTexture。

我也考虑到这可能会稍微有点重,但窗口本质上并不会每帧都重绘。

1 个赞

实际上,您能把它发布为 GitHub 仓库吗?比起下载一个随机的压缩包,我更愿意直接查看仓库内容。(我对此表示歉意,但在当今这个充斥着骗子和恶意软件的时代,我们怎么小心都不为过。)

最终,唯一的问题是开发时项目目录有点杂乱,里面有很多文件/演示项目,占用空间太大,导致我无法上传到 GitHub。不过,zip 包中只包含核心脚本(即您放入项目文件夹的内容),而不包含引擎本身。

当我将其上传到 GitHub 时,我会通知您,不过可能需要一点时间。

是的,我相信您会发现 zip 包中没有任何病毒或恶意软件,我也无意欺骗任何人,我同样讨厌骗子。

1 个赞

哎呀,别担心,这只是基础网络安全,哈哈。我很期待看到你的进展!

如果需要,你可以在 GitHub 上只发布核心脚本(使用 .gitignore 排除其他文件),但别担心!

很高兴看到其他人也感兴趣,想让 MZ 变得更现代化!

1 个赞

我把它看作 RPG Maker 的一个分支。我试图进行创新,添加一些让开发更便捷、而在原版引擎中并不存在的功能,比如添加 F、G、H 图块层(2048x2048)。还有额外的事件命令(如视频叠加)、3D 动画的 3D 控制等。

我不仅仅是在复制 RPG Maker MZ,而是试图对其进行创新,因为在我看来,现有的公司/产品已经陷入停滞。当然,我也在加入自己的特色。

不过,等它更接近完成时,我会通知你它在 GitHub 上的情况。我相信里面会有对你帮助项目有用的东西。

2 个赞

祝你好运!

至于映射层,我建议你了解一下 PixiJS 全新的渲染层系统,它看起来相当有趣。不过我还没亲自尝试过。

当然,如果你已经研究过了的话。

我觉得一个很酷的功能是能够将自定义层挂载到 SceneMap 上,而不会干扰其渲染过程。

我还在考虑将相机逻辑从 GameMap 类中拆分出来,独立为一个 GameCamera 类,以便更好地控制(可能还支持像素级移动)。

2 个赞

我已经在用自定义插件做类似的事情。比如我的多视差插件允许我设置多个视差图像,并根据地图设置它们的 z-index;我的视频覆盖插件也是如此。

我同意,让我们开始吧!

1 个赞

显然,不是为我。

我觉得我们对什么是“符合人体工程学”的开发有着不同的理解。

你的观点我完全无法共鸣。

  • PIXI v8?好吧,可以,但它相对于现有的 PIXI v5 渲染器究竟带来了什么_真正、具体_的改进?而且没有任何缺点,比如渲染插件不兼容?反正我在用 RPGMaker 工作时并不直接使用 PIXI,所以我并不指望这会对我有影响。
  • TypeScript,为什么要用?我_更_熟悉 ES6 之前的 JavaScript(也就是 RPGMaker 所使用的语言),而不是 TypeScript。最糟糕的是,它是一种编译型语言,增加了测试的额外门槛。
  • ES 模块——除非它们在 Web 构建中能用,否则真的没有意义。如果你_真的_想要模块,Node 模块就很好用(至少我假设是这样,除了偶尔使用内置模块外,我不怎么用它们)。如果可能的话,我也不想折腾 NPM。

简而言之,你似乎在致力于“修复”一个甚至没有坏掉的东西,在我看来,这纯粹是浪费时间。不过没关系——显然,对你来说这并不是浪费时间。

但抛开这一切……你甚至没有尝试去保持兼容性。如果这是一个主要为你个人使用的项目,你只是在分享它以防其他人感兴趣,那没问题。但如果你真的想吸引其他人加入,保持兼容性对于让人们上手是_绝对关键_的。没有人愿意切换到新运行时,结果发现他们使用的 107 个插件中有 95 个根本无法工作。只是一个友好的建议。

1 个赞

据我回忆,基础引擎实际上已经支持这一功能,只需进行极少数微调即可。(我之前曾研究过相关内容,这是基于实际经验。)我认为这完全可以通过一个应用于基础引擎的插件来实现。

虽然我觉得你的语气相当傲慢且无礼,但我会暂且不予计较。

我创建这个项目的初衷主要是出于我个人的兴趣、好奇心以及使用需求。

PIXI v8?好吧,没问题,但它相对于现有的 PIXI v5 渲染器到底带来了什么真正、具体的改进?而且没有任何副作用,比如渲染插件不兼容?反正我在 RPG Maker 中工作时并不直接使用 PIXI,所以我不认为这会对我有影响。

如果你对 PIXI 的工作原理稍有了解,你就会知道它带来了大量的性能提升、生活质量(QOL)改进,修复了许多内存泄漏,并淘汰了旧有的奇怪缺陷。此外,还添加了大量新功能,极大地简化了游戏开发乃至一般的软件开发。

你之所以从不使用 pixi,是因为 RPG Maker 的沙盒机制使得使用任何 PIXI 的其他功能都变得极其糟糕。鉴于 PIXI v5 是一个充满奇怪缺陷且容易出错的混乱集合体。

TypeScript,究竟为什么?比起 TypeScript,我更习惯使用 ES6 之前的 JavaScript(即 RPG Maker 所使用的语言)。最糟糕的部分在于它是一种编译型语言,增加了测试的额外门槛。

恕我直言,我不同意。ES6 之前的代码处理起来简直是噩梦,其逻辑复杂且充斥着毫无意义的冗长代码。

此外,我并没有强迫任何人使用 TypeScript。最终发布的产品将被编译成完全正常的 JavaScript。但是,如果你曾参与过任何比小脚本大一点的项目,你就会很快发现 TypeScript 能帮助减少大型项目中的许多痛苦。作为一个曾在 RPG Paper Maker 运行时 V2 上工作过的人,我很快就意识到了这一点。但如果有人觉得非常痛苦,他们完全可以简单地通过纯 JavaScript 编写插件或扩展核心脚本。这主要是为了核心脚本运行时的开发,因为我确信没人会愿意尝试使用 JSDoc 来获取正确的类型定义。

TypeScript 实际上是 2026 年现代 Web 开发或 Web 游戏开发中最基本的需求。

所以目前为止,你只是在谈论你自己的偏好。

ES 模块——除非它们在网页构建中能正常工作,否则毫无意义。Node 模块工作起来完全没问题,如果你真的想要模块的话(至少我是这么认为的,除了偶尔使用内置模块外,我不使用它们)。如果可能的话,我也不想碰 NPM。

ES 模块就是简单的 import 和 export,它们甚至与 NPM 没有直接关系。是的,它们经常指向 node_modules,但这是现代 JavaScript 中最基本的功能之一,可以指向基本的 JavaScript 文件,也可以用于 Bundler(这又是现代 JavaScript 的一部分)。

简而言之,你似乎专注于“修复”一些甚至没有损坏的东西,在我看来这听起来像是在浪费时间。不过没关系——显然,这对你来说并不是浪费时间。

但抛开所有这些……你甚至没有试图保持兼容性。如果这主要是一个个人项目,你只是在分享它以防其他人感兴趣,那没问题。但如果你确实希望吸引其他人加入,保持兼容性对于让人们接受是绝对关键的。没人想切换到新运行时,却发现他们使用的 107 个插件中有 95 个根本无法工作。只是一个友好的建议。

再次说明,这纯粹是出于好奇心以及“为什么不试试”的心态。如果你觉得这是浪费时间,那当然可以。继续使用普通的 RPG Maker 吧,我没有强迫任何人使用 RmNext。我从未打算让它面向初学者休闲玩家。它是为那些希望为自己的游戏访问 PixiJS v8 现代生态系统的开发者而创建的。

至于兼容性作为先决条件?并不完全是。这只是 RPG Maker 用户群体中一种非常有毒的心态。他们期望一切都能即插即用且毫无错误,但作为 MV 和 MZ 发行期间的见证者,当人们发现无法直接将 MV 插件即插即用进 MZ 而不需要实际移植它们时,他们都在大声抗议。RPG Maker 的开发人员从未关心过版本间的向后兼容性,而且天哪,如果下一个 RPG Maker 使用 PixiJS v8(而不是 Unity),他们会破坏整个生态系统,而用户群体又会再次抱怨。周而复始。

我在早期阶段考虑过适当的插件兼容性支持,但随着你发现 PixiJS v8 的变化,你会意识到你不能指望让一切都能正常工作。因为,Sprites 和容器/渲染在 PixiJS 中的工作方式如此该死的不同,即使我想编写一个适当的 shim 层,可能也会繁琐到难以工作。

我解决这个问题的方法,或者说至少让那些想要切换或尝试的人更容易一些,是让 API 保持与原始版本极其接近,这样他们只需要修改部分代码即可。

(大多数 game_object 类基本上是一样的,或者至少行为方式与旧版本相似)

唯一经过重构的类是 Managers,使其更像服务定位器,但这主要是我个人的偏好,目前仍处于草稿阶段。

场景的处理方式现在使用混合异步加载(因为 PixiJS v8 的资源加载是异步的)。

还有一些 Spriteset 的处理方式,因为只有容器才能有子元素。

好吧。但如果你确实希望吸引其他人加入,保持兼容性对于让人们接受是绝对关键的。没人想切换到新运行时,却发现他们使用的 107 个插件中有 95 个根本无法工作。只是一个友好的建议

再次强调,我并没有在刻意寻求(推广)。我是在邀请那些愿意参与此类项目的人。虽然我英语不是特别好,所以可能听起来像是在寻求什么,大概吧?

我真心只是想分享这个项目,让感兴趣的人参与其中。如果人们认为这是浪费时间,我根本不在乎。

但如果最终没有成功,嘿,至少我从中学习到了东西,并且这是一次有趣的经历。我所做的只是享受这个过程。

1 个赞

关于你对 TypeScript 的看法,我有很多话想说,但我不想再继续偏离你的话题了。

我想在这里澄清一点:如果你希望除了你自己和少数爱好者之外还有更多人使用它,那么兼容性就是一个先决条件。大多数用户不会切换到你的 RMNext 分支,因为他们知道他们的插件会停止工作。但看来你对此并不在意,祝你好运吧。

我同意兼容性很重要。就我个人而言,我并不太觉得 TypeScript 有什么价值(普通的 JavaScript 就足够了),但我确实认为 RPG Maker 引擎已经停滞不前了。我希望能进行创新,为游戏带来新的元素(同时保持向后兼容性)。目前我正在开发我的游戏(使用了大量插件)。我确信可能还有一些我没见过的边缘情况,但这些问题可以在出现时逐一修复。

1 个赞

我觉得这里有很多误解。TypeScript 主要用于核心脚本,而不是插件开发。它只是让引擎在开发过程中更加可预测(加上类型检查)。对于插件,人们可以直接使用默认的 JavaScript。我个人在开发插件时使用 TypeScript,因为它基本上提供了一层安全保障,并消除了许多容易出错的问题。但对于核心脚本,使用 TypeScript 是有道理的,因为它可以相对容易地进行文档编写。

至于兼容性,重构工作仍处于早期阶段,所以我会等到它完成时再来看。但正如之前解释的,我们无法让一切都兼容。很抱歉,这不现实。有时候为了创新,你不得不打破一些鸡蛋。

我认为这个话题的讨论会持续下去,所以这大概是我最后一次对此发表意见了。

很抱歉,但……要让(至少90%的)东西兼容是完全可能的。达到100%兼容可能也是_可能_的,但鉴于整个底层渲染库已被替换,这可能会带来难以承受的难度。不过,如果你将兼容性限制在RPGMaker对象的外部API上(即Game_*Sprite_*Window_**Manager类,以及一些其他核心类),那应该是完全可行的。当然,这并不意味着事情会变得简单——你需要切实付出努力来确保兼容性得以维持。

这听起来没什么道理。TypeScript本身并没有任何功能能让事情变得更“可预测”。诚然,TypeScript理论上确实能帮你发现那些因传入错误类型而可能遗漏的错误。但你同样可以通过JavaScript的linting工具来捕获这些错误。TypeScript并不会让这变得更容易,它只是在你确实想要指定类型时,改变了你所使用的语法。

总之,关于TypeScript的话题,这大概会是我最后的发言了(至少在这个帖子中)。

1 个赞

这种情况更为复杂,但从 v5 升级到 v8 不可能做到 100% 兼容。从 v7 开始,Pixi 专注于异步(意味着代码可以在不阻塞线程的情况下执行任务)。RPG Maker MZ 本质上是同步的,因此需要大规模重写(或采用变通方案)来处理这一问题。我不得不处理异步与同步的混合逻辑(至少在 JS 中),这非常痛苦。我不得不使用回调,以便我制作的自定义加密功能同时适用于 MV 和 MZ。这实在令人不快(尤其是与 C# 的 Task 处理相比)。

TypeScript 旨在提供生活质量类功能(如类型,这是 JS 所缺乏的),从而帮助开发者编写更好的代码。作为一名同时使用 JS 和 C# 的开发者,我会尽可能使用 C#,因为我知道被我标记为 string 的变量确实是字符串。JS(至少是 ES5 及更早版本)没有这种便利。大多数 JS 开发者使用 TypeScript 是有原因的。它让编写更优质的 JS 代码变得容易得多。

3 个赞

是的,但就内部的 Sprite 系统而言,它的处理方式截然不同。至少在处理父节点和子节点时是这样的。

(前文已解释过)在 PixiJS v8 中,现在只有容器(Container)才能拥有子节点。这本身并不是什么坏事,但它确实导致了一些难以避免的破坏性变更(例如在 Spriteset 的情况下)。

我在想的一种至少能缓解移植问题的方法,是提供一个类似旧版 Spriteset 行为方式的 Spriteset 类。

export class SpritesetBase extends Container { 
   
   protected _anchor: ObservablePoint; // 用于复现 spriteset 的 x 锚点行为
  constructor(){ 
  
  }

} 

正如之前所说,大多数游戏对象类都是相似的(有一些例外)。

Windows 类的行为与之前的 RPG Maker 完全相同。我只是改变了窗口在内部的构建方式,并且没有人会去动 Core_window.js 这个类。

它基本上使用的是 PixiJS 内部的九宫格切片精灵系统,而不是它自己的系统。

(它也被重命名为 RpgWindow,只是为了避免与 IntelliSense 产生奇怪的冲突问题)

场景的渲染方式现在是一种混合异步模式,但它的构建旨在保持尽可能简单。只需要添加 await 或者使用新的 ImageManager 队列系统即可。这基本上复现了旧版 RPG Maker 加载图形时阻塞线程的方式。

ImageManager.requestQueue("folder","assetsName"); 

现在的大多数加载和 Bitmap 处理都是基于 GPU 的,而不是基于 CPU 的。

我考虑过完善的兼容性,但说实话,即插即用并不容易。但这主要归结为要做以下操作:

旧版:

//PluginA 

Scene_Menu.prototype.create = function(){
  this._mySprite = new Sprite();
  this._mySprite.bitmap = ImageManager.loadSomething("spriteName");
  this.addChild(this._mySprite);
}; 

新版:

import {SceneMenu} from "rm-next";

const alias =  SceneMenu.prototype.create;
SceneMenu.prototype.create = async function() { 
  alias.call(this); 
  this._mySprite = new Sprite();
  this._mySprite.bitmap = await ImageManager.loadSomething("spriteName");
  this.addChild(this._mySprite);
}

// 在需要锁定线程的边缘情况下,但这基本上就是你在旧版 RPG Maker 中会做的事情

SceneMenu.prototype.MyLockingFunction = function(){
  ImageManager.request("folder", "assetName").then((bitmap) => { 
     this._mySprite.bitmap = bitmap;
   });
}

SceneMenu.prototype.checkIfSpriteIsReady = function() {
 if(ImageManager.isReady()) { // 只要 imageManager 正在加载,它就不会执行任何操作。
 // 执行相关操作
 } 
}

API 基本上是一样的,但如果有人编写了这样的插件:

const sprite = new Sprite();
const sprite2 = new Sprite();
sprite.addChild(sprite2);

那么它就会报错。这个问题无法修复,这就是 PixiJS V8 现在的工作方式。

你必须这样修复这个问题:

 const container = new Container();
 const mySprite = new Sprite();
 const mySprite2 = new Sprite();
 container.addChild(mySprite,mySprite2);

总而言之,我确实思考过如何解决这些摩擦,但你能做的也就那么多了。

1 个赞