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

这种说法并不全面。事实上,RPGMaker 引擎在本质上相当异步。有几个系统允许你“调度”某些操作,让它们“在下一个 tick 运行”——例如战斗日志或事件解释器。

话虽如此,这里我们特指渲染部分,因此引擎的这一部分可能是同步的。

JS 并不缺乏类型。它知道什么是数字,也知道什么是字符串,你可以很好地询问“这是一个 Game_Actor 吗?”。而且这在 ES6 之前就已经存在了。

如果你只是在类名中加回下划线,旧插件不是可以无需任何更改就正常工作吗?

仅仅通过将 Sprite 设为 Container 的子类,就不能保持兼容性吗?有什么技术原因导致它不能成为 Container 吗?

我不知道有多少插件实际上会给 Sprite 添加子元素,但我觉得核心引擎会这样做,所以我想这个数量可能并不小。

让我这样来说:如果我给你一个变量,并提供尽可能少的上下文,你能判断出这个变量是什么类型吗?在 JS 中,变量可以是任何东西。天哪,你甚至可能不小心突然替换了它。

在 MV 中,我注意到每次保存时引擎都会短暂冻结。这是因为引擎必须等待 NodeJS 写入文件。由于引擎没有将其放入后台线程的方法,它不得不暂停。MZ 处理得更好,但如果没有 async/await,仍然很麻烦。

1 个赞

我已经完成了构建。我的做法是:如果某个命令在 PIXI8 中被更改或以不同方式处理,兼容性垫片(compatibility shim)会自动处理这些差异,无需重写插件;但如果你按照 PIXI8 的方式编写代码,它仍然可以正常运行。这使得插件与 PIXI 版本无关,唯一的缺点可能是有人写出了原本只具备部分兼容性的代码,结果却意外地运行正常。也就是说,他们可能“写错了”,但代码依然能工作。

RPG Maker 在 PIXI5 中使用的一些功能实际上在 PIXI8 中被移除了,但我们有办法在运行时将其转换为正确的命令和正确的执行方式,同时不破坏与旧插件的兼容性。关键在于使插件与 PIXI 版本无关,确实需要实现一个兼容性垫片。我用我的游戏(包含 100 多个插件)进行了测试,实现了 100% 向后兼容,尽管我对某些插件进行了针对性修复(从我个人的角度来看),但这绝对是可行的。我很期待发布 RPG Reactor,目前我正在做最后的打磨工作。

如果有人想参与测试,请告诉我!我会发送一个压缩包。

关于 JavaScript 的问题,我认为对严格类型检查的需求被夸大了,并不是什么大问题。如果我不小心将字符串声明为整数导致出错,那作为开发者,我自己得负责在犯错时找出问题所在。

2 个赞

是的,完全可以。我只是更习惯使用帕斯卡命名法(PascalCase)来命名类(这是旧有的编程习惯),但保留带下划线的名称也是 100% 可行的。

至于 Sprites 作为一个容器,这确实有点奇怪。如果我们让 RM 的 Sprite 成为容器,实际上会失去锚点功能,而不得不使用枢轴点(pivot point),说实话这简直让人抓狂。

不过,PixiJS 之所以规定只有容器才能拥有子元素,基本上是为了降低场景图的复杂性并提升性能。

(别误会,这确实是 PixiJS 开发者做出的一个奇怪的设计选择)

至于 TypeScript 方面,目前这纯粹是个人偏好问题。

关于 Shim 兼容层,我稍后再研究如何实现。这确实不是我现在能深入掌握的内容。我会写代码,但我也从来没说过自己是魔法师,哈哈。首要任务是把代码移植过来,看看不带插件的原生项目是否能正常运行。

所以,说实话,我不太擅长写代码(虽然读代码还行)。有了 AI 之后,我可以直接查看代码,找出问题所在,然后让 AI 去处理,或者我提出一些建议或解决思路,等等。接着 AI 就开始埋头苦干,它的进展速度让我感到惊讶(而且是令人惊喜的那种)。

确实,AI 技术让我感到如虎添翼,因为我一直都比较擅长阅读代码并理解其功能(我也了解计算机的工作原理,包括 RAM、CPU、GPU、网络协议栈、数据库等各个部分),但完全不太会写代码。这背后的原因无非是语法问题,或者记不住某个命令的名字,导致每一步都要去查资料,整个过程枯燥乏味。但现在,这部分麻烦已经基本消失了。所以我想在熟悉这些新工具的同时,出于兴趣尝试解决这个问题。这就是我的观点。我也不是什么编程高手啦!(就纯粹的编码能力而言)哈哈。

不过,深入钻研之后发现,竟然有这么多不同的“编程风格”,而且每个人对什么是好、什么是不好都有自己的强烈看法,无论何时都是如此。虽然学到了很多,但也乐在其中!

实际上,只要修复处理瓦片集的着色器,就可以使用 Pixi 6.5.10。

1 个赞

嗯,我记得试着换过,我觉得大部分代码都差不多。

@Marix 很遗憾,我只能动运行时部分,没法碰编辑器本身。

其中一项计划是为插件开发者提供实现方案,从而消除为新函数和属性进行原型补丁修补的需求。

如果你需要注入新方法和新字段:

export class StatsContainer  {
  public get maxHp(): number {
    return this._hp;
  }
}

@merge(StatsContainer)
export class MyCustomsStatsContainer extends StatsContainer {
 public get maxHunger(): number {
   return this.maxHp + 100;
 }
}

/// 将自动挂钩新函数和属性
//PluginManager.mergeClass(StatsContainer, MyCustomsStatsContainer);

如果你需要覆盖/别名化函数(但也可以通过 装饰器添加新函数):

class DummyGameParty {

  @overwrite(Game_Party)
  maxGold(this: Patched<Game_Party>){
    return Number.MAX_SAFE_INTEGER;
  }

  @alias(Game_Party, "after")
  maxLevel(this: Patched<Game_Party>) : number {
    if($gameSwitches.value(1)){
      return Number.MAX_SAFE_INTEGER;
    } else {
      return this.super();
    }
  }
}

这两种方式都有效,目前该 API 仍在开发中。
它可能会被合并到一个更接近以下形式的 API 中:

@PatchClass(Game_Party)
export class MyCustomPartyExtension extends Game_Party {
  
 public myCustomField : number = 10; // 完美运行,并会正常添加。
  public override maxGold(this: Patched<Game_Party>): number {
    console.log("修改金币上限...");
    
    // 不使用 super.maxGold(),而是调用 this.super()!
    return this.super() + 5000; 
  }
}

我想指出的是,这些是可选的插件开发工具,不会强制开发者使用。

另外,考虑到装饰器在 JavaScript 中尚未得到完全支持(但在 TypeScript 中支持),我想温和地提醒一下,你可以通过插件管理器轻松访问它们:

PluginManager.merge(baseClass, childClass);
PluginManager.patchClass(baseClass,ChildClass);
PluginManager.Inject(BaseClass, MethodName, () => {});
1 个赞

现在是2026年,为了获得一个最新的渲染后端而与2020年的古老 MZ 运行时环境破坏兼容性,这已经是一笔相当划算的交易。当这一切完成时,它就像是一个去掉了编辑器的 RPG Maker 新版本。

我也更愿意使用 ES6 之前的 JavaScript,但 TypeScript 很流行,而且拥有极好的工具支持,因此它最终会改善许多人的开发体验。这是一个非常站得住脚的选择。

哦,MZ 游戏引擎其实已经坏掉了,而且过时了。

2 个赞

我已经把编辑器搞定了(RPG Reactor)。还更新了一个运行时,它基于 PIXI8,但完全向后兼容(除了几个我还没测试过的边缘情况)。迫不及待想把它发布出去。

你倒是这么说,但你之前也说过:

所以,我不打算抱太大期望。

咱们别吵架哈,哈哈。

这确实是一个主要专注于 Runtime 的项目,尽管他们对编辑器相当宽容,但编辑器仍然是 GGG 拥有的产品。Runtime 在这方面则更加自由一些。尤其是,我主要只是提供一些改进之类的东西。

至于我对 AI 的立场,虽然我同意 AI 可以提供帮助,但我希望参与项目的成员不要直接生成完整代码然后提交 Pull Request 到仓库。至少,不要在不经过全面测试并确保其符合 RPG Maker 精神的情况下这样做。

我稍后会尝试起草一份代码规范表单。因为我确实希望保持一致性。

哦对,我确实大量使用 AI 辅助编程(很多开发者都这么做),而且我的编程基础也很扎实,不只是靠“氛围编程”(vibe coding)。这绝对是未来的开发趋势,是下一代的开发栈和方式。

我知道游戏开发圈子里很多人观念陈旧,对数字化工具公开持敌对态度。即便我的作品质量很好,我说的话也会被立刻无理地、不公平地全盘否定或无视。

我知道,当我坦诚地披露使用 AI,真诚地试图宣扬它的好处并提供证明时,这些反而成了攻击我的武器,用来贬低我或让我提出的贡献被直接无视。而我所渴望的,不过是为社区做出贡献,但社区一直以来都糟糕透顶,充满敌意。我从 90 年代就开始接触 RPG Maker 了。那时候社区还挺友好的,但到了 2010 年左右开始变得没劲,现在的情况比以往任何时候都更糟。社区 actively 阻碍项目完成。这太糟糕了。

但我不在乎别人怎么看我。我照样会把它做出来。

这么说吧……我来证明给你看。

虽然我还在这上面加一些打磨,但这是目前的效果,你要不要试试看,告诉我你的想法?压缩包里的当前游戏项目文件(Star Shift Freelancers)已经包含在内,同时也包含了 PIXI8 运行时和编辑器本身。目前新建项目在编辑器中无法工作,但打开现有项目是可以的,所以我把它放进了压缩包。

这原本是一个 MZ 游戏,带有大量插件,我仍在开发中。通过兼容性垫片和 PIXI8 运行时,它实现了向后兼容,而且确实能运行。我是言行一致的。

但我猜,即便它能运行,也没人愿意看一眼。大家好像觉得我在撒谎,或者在“假装直到成功”(fake it till you make it)之类的。如果我真想走那条路,我干脆就说一切都是我一个人做的,完全不用 AI,但我现在是诚实和真诚的。

希望未来你们不要再直接无视我,而是能认真对待我。对于我的任何主张,我都随时愿意提供证明。如果任何人觉得我的工作有价值并想合作,我也非常乐意分享和协作。

总之,链接在这里,希望大家能试试看,告诉我你的想法。虽然还没完全做完,但已经非常接近了。它是功能性的,不是理论上的,也不是“将来某一天”,它已经在运行了。

这是 Windows 版本的应用,但如果我为其他平台构建包,它在 Linux 和 MacOS 上也能无缝运行(我自己用的是 CachyOS):

好的,我希望讨论能保持在 RPG Maker Next 的主题上,你们的对话可以转为私密进行。

我支持开放交流,但就目前而言,这只是在带偏话题。

1 个赞

啊,是啊,我猜也是这样(直接跳到了屏蔽/审查/隐藏对话)。

这其实并没有偏离主题,因为这是一个相关的项目,而且我们都希望达成同样的目标。自然的进展就是合作,以便推动这件事完成/加速进行。

我并没有在和你竞争。

我会保留这个帖子,但话题已经偏离了。@Psychronic 这个项目听起来很有趣,我觉得如果把它单独开一个帖子,大家更容易找到它,而不是让它埋没在这里。@niokasgami 之前也提过同样的建议,所以你可以新建一个帖子,并把链接引回来,方便大家关注。

谢谢!

1 个赞

好的,听起来不错,已经上线了:

1 个赞

RPG Maker Next 底层的一项新变更是对 Bitmap API 的重构。

其基本工作方式相同,唯一的区别是加载新纹理时变为异步操作。

const bitmap = new Bitmap(); 
bitmap.on("load", () => {});

bitmap.on 现在将取代 .addLoadListener,改用原生的 Event Emitter。

Bitmap 现在内部使用 PingPongBuffer,以支持高性能的 GPU 操作。整个 API 现在完全基于 GPU,而非 CPU。

可通过以下方式访问:

bitmap.buffer

BaseTexture 已重命名为 textureSource,以符合 PixiJS v8 的命名规范。

现在可以同时访问 texture 和 textureSource。

文本渲染功能尚未实现,因为我仍在通过实验观察 PixiJS 的实现方式如何处理文本。

2 个赞

更新!

窗口实现。

我一直在努力进行移植工作,并遇到了一个奇怪的 Bug。

问题出在窗口类的实现上。我遇到了各种各样的问题,其中之一就是它无法渲染。
我仍在调试这个问题,以查明它为什么不显示。但在调试显示问题的过程中,我注意到我想使用 PixiJS v8 的 NineSliceSprite 实现来管理窗口的所有调整大小部分,而不是 RPG Maker 当前的管理方式。
然而,由于 RPG Maker 对 window.png 纹理的格式处理方式,默认的 PixiJS NineSliceSprite 实现会导致方向键(d-pad)区域出现溢出。

遗憾的是,你不能直接在 NineSlice 精灵上“挖个洞”,我也不想更改资源格式。

因此,我的解决方案是创建一个类似于旧版 RPG Maker 方式的自定义实现。但不是硬编码,我计划为此创建一个可复用的 Pure 类。

命名为:SpriteFrame
该类的目的类似于 NineSlice,但在中间有一个空洞。
用法:

  const texture = await ImageManager.loadSystem("window");
  const border = 24; // 也可以是对象

  
  const frame = new SpriteFrame(texture, border, rect); 
  frame.setBorder(border); /// 可以通过命令设置

通过这种方式,你可以轻松拥有特殊的 MZ 窗口框架。它将自动计算框架每个的大小和位置。但是,也可以手动指定坐标。

2 个赞

又更新一下:

我已经解决了窗口系统的问题。


现在可以正常工作了!

不过,之前无法工作的原因是新的 Bitmap/Resources 加载器的处理机制发生了变化。

在旧版的 RPG Maker 中,你可以这样做:

 const bitmap = Bitmap.load("url");
 bitmap.addLoadListener(callback);

这样就可以监听加载事件。

我原本打算在 Bitmap 类中添加一个事件发射器(EventEmitter),并使用如下函数:

 const bitmap = await Bitmap.load("url");
 bitmap.on("complete", callback);

但由于其异步特性,事件总是会在订阅时立即完成,导致线程始终被锁定。这是基于 Promise 的,所以一旦订阅,complete 事件就会触发。这在某些区域(例如 windowSkin)中成了一个问题。

我找到的修复方法如下:

  set windowskin(value: Bitmap) {
    if (this._windowskin === value) return;
    this._windowskin = value;
    // 由于 PixiJS 的异步特性以及新的 Bitmap API,我们采用“一旦加载完成”的处理方式
    value.onceLoaded(() => this._onWindowskinLoad());
  }

onceLoaded 是一个检查 Bitmap 是否已准备好使用的函数。如果尚未加载完成,它会将回调添加到事件回调栈中。

不过,我知道在某些情况下,用户可能希望监听 Bitmap 的加载过程。

对于这种情况,你们有什么建议吗?在这种情况下,我可以移除 EventEmitter,因为通常 Bitmap 加载是基于 Promise 的,使用 EventEmitter 效率并不高?

1 个赞