我刚刚读完一本关于游戏业内幕书(《血汗和像素》,推荐所有喜欢制作游戏的人阅读),这本书激发了我要自己制作游戏的决心。这个游戏将是一个小型2D游戏。
第一步就是选择游戏引擎。首先,我将Unity和Unreal引擎排除在外。这些引擎我都用过,并不是很喜欢,因为它们处理2D游戏的方式很不优雅。最后我还是选择了Godot和GameMaker 两款引擎间进行了比较。通过对这两款引擎进行快速试验后,我最终选择了GameMaker。
GameMaker的使用体验非常棒。即使没有任何先前的知识,我也能够在一个晚上内迅速制作一个基本的顶视角射击游戏。另外,我最喜欢的许多游戏也是以GameMaker为开发工具。唯一让人感到不爽的是GameMaker编码体验。尽管使用者们都爱用GM的可视化编码工具和GML,而我作为一个程序员就显然不能接受了。缺乏类型检查和编码器的效率也是让人感到十分失望。现代可视化编码器如VsCode和Jetbrains解决方案就远远完善于GM内置的编码工具。
为了解决上述问题,我决定绕过GameMaker自身编码问题。经过长时间的比较,考虑后,我决定使用TypeScript并将其与VsCode相结合。这也能解决上述类型检查问题,同时也能实现DX转换。
我将一切绑定成一个命令行工具方便在全世界范围内进行安装:
npm install -g @odemian/gamemaker-typescript
这个工具的来源是开源的GitHub仓库。
如何使用
我们先来谈谈GMTS如何工作的。我们假设你运行了命令行:
gmts setup
GMTS将生成两个文件:tsconfig.ts,GameMaker_Typescript扩展。
在GameMaker项目空间,GMTS将根据tsconfig.ts文件对你的项目文件进行编译并自动创建以下文件:
-tsconfig.ts文件负责配置TypeScript的编译选项,并指向适当的GML类型。
-GameMaker_Typescript扩展是一个bash脚本,它通过hooking pre_project_step将TypeScript编译转换为GML。
-项目运行在LTSversion上,因此该项目应该非常稳定。
如果不希望在项目同步或数据损坏后产生问题,编译过的TypeScript文件都应该位于_resource_文件夹下。
例如,如果你有一个obj_player对象,那么编译好的TypeScript文件应该放入以下地方:
/objects/obj_player/code.ts
你可以任意命名TS文件,GMTS将优先使用第一个发现的配置文件。
GMTS的另一个解决方案是使用绑定转换。绑定转换方式直接从.ts文件中获取文件名转换,使用它作为绑定关键字。然而,后来 GMTS决定放弃这个绑定转换方案,因为它会导致资源重建后不再引用相关的代码。但是,这也给 GMTS带来了不稳定。
GMTS在如何进行类型转换上也有许多优化的方法。它将转换TS文件中编写的语句直接转换成GM事件。因此我们可以通过GMTS来查看这些代码,甚至可以直接用GMTS来编写游戏。
GMTS会替换你的ts代码中的关键字,例如’tthis’来转换成GML中的’self’, ‘const’, ‘let’转换成‘var’,然后所有的GML事件都转换回去到GM的事件里。
所以,实际上,在GMTS中不仅可轻易使用现代的编程语言,还能够直接在GameMaker IDE里查看和编辑编写的代码,无需另外再去编写GM事件。
虽然GMTS现在仍在测试阶段,不能作为实际开发工具,但它的使用方式比起使用绑定技巧来多得多。此外,这里也分享了一部分使用GMTS编写类和继承的示例:
// objects/obj_player/code.ts
class Player extends GMObject {
_movement_speed: number;
onCreate() {
this._movement_speed = 2;
}
onStep() {
var _hspd = keyboard_check(vk_right) - keyboard_check(vk_left);
var _vspd = keyboard_check(vk_down) - keyboard_check(vk_up);
if (_hspd != 0 || _vspd != 0) {
var _dir = point_direction(0, 0, _hspd, _vspd);
this.x = this.x + lengthdir_x(this._movement_speed, _dir);
this.y = this.y + lengthdir_y(this._movement_speed, _dir);
}
}
}
}
你还能看到在使用GMTS编写代码时,变量名称更为清晰,结构可读性高。但是需要注意的是,在使用GMTS编写类时,所有在原有的GameMaker中编写脚本的事件方法都会被自动转换。
GMTS编码工具最大的优势就是可以在上述转换规则的基础上进行自定义转换。这种方式能够提供更为详细的类型检查,并且能够在转换前对源码进行更多的优化。
我们不妨试着编写一个继承的示例,然后看一下如何在GMTS中来进行类与方法的继承。
假设我们有一个类obj_base,并且带有一个方法:
// objects/obj_base/code.ts
class Base extends GMObject {
_movement_speed: number;
move (_in_h: number, _in_v: number) {
// 在_in_h和_in_v的计算里,_in_h和_in_v都采用Base类的计算方法,最后使用_base._movement_speed代替base._movement_speed。
if (_in_h != 0 || _in_v != 0) {
this.x += this._movement_speed * _in_h;
this.y += this._movement_speed * _in_v;
if (_in_h > 0) {
this.image_xscale = 1;
} else if (_in_h < 0) {
this.image_xscale = -1;
}
}
}
}
我们现在来写一个_player类,继承Base类,来让_player类拥有move方法。因为GMTS可以自定义转换,所有的类与方法在GMTS中编写后都能通过转换后成为原有GameMaker的编写方法,方法都是在后面补充上去的。
// objects/obj_player/code.ts
class Player extends Base {
onCreate(): void {
this._movement_speed = 2;
}
onStep () : void{
var _h = keyboard_check(ord("D")) - keyboard_check(ord("A"));
var _v = keyboard_check(ord("S")) - keyboard_check(ord("W"));
// this.move是在Base类中定义,所以我们可以直接使用它来取代上述_move的写法。
this.move(_h, _v);
}
}
最后,因为GMTS在编写的过程中编写出的是正常的TS代码,所以对于我们而言在转换完成后,可以任意对其进一步编写。在编写事件与方法时,我们也能够对其继续展开编写。所以,GMTS确实很有用。
GMTS的脚本部分相类似,GMTS也同样能解决类似的问题。GMTS在编写脚本的过程上同样支持代码自动转换。GMTS同样将你的TS脚本转换为正常的GML事件。
GMTS在GameMaker编码的转换时同样使用’tthis’转换成‘self’,并且在正常的GML编写方式上转换来编写GM事件。在转换脚本的时期,GMTS会直接将ts内的语句转换成正常的GML事件,GMTS能自动识别关键词和GM的编写语句,对编写的代码进行转换,因此能让我们轻松在GMTS环境中编写GM的脚本代码,然后再转换成GM的GML事件,并且能在实际运行时在GML编写的方式编写。编写的转换方式能够让编写的GSML事件更加简洁易懂,转换的结果是GML编写方式更加高效。
GMTS转换的脚本同样将正常的GM使用的事件转换成GMTS自己能识别的编写形式,因此能让脚本代码更加高效便于管理,并且能在需要时将其简单转换成正常使用的GML事件。
在实际测试的阶段后, GMTS的优点也是非常明显的。首先GMTS能让我们轻松的将程序语言转换成GM事件,并且能直接在GMTS环境里写GM的代码,GMTS能直接将GM的events中编写的代码转换成GML编写的方式,从而让我们更好地编写代码。
但 GMTS也有缺点,那就是 GMTS不是开源的,它基于一个独立的CLI工具,你还需要在项目空间安装一个小工具。GMTS不能解决类似的问题。
GMTS转换的方式也不是唯一的方法,GMTS基于一个小工具,并且不能直接从GMTS编写完的代码直接转换成正常的GML编码方式。GMTS能让我们轻松地将程序语言与正常的GM事件转换并合并到GML中,但在实现的实质上GMTS是基于一个小工具来实现的,因此可能无法直接在GM空间中编写或实现转换。
评论 (0)