GDevelop 扩展如何用 PropertyDescriptor 声明对象属性并实现 updateProperty
【免费下载链接】GDevelop🎮 Open-source, cross-platform 2D/3D/multiplayer game engine designed for everyone.项目地址: https://gitcode.com/GitHub_Trending/gd/GDevelop
开发 GDevelop 扩展时,如果你的对象(object)或行为(behavior)有用户需要在编辑器里修改的字段——文本、数字、开关、资源引用——就需要做两件事:用PropertyDescriptor声明这些属性,让属性面板自动生成对应的输入控件;再实现updateProperty,在用户在编辑器中修改属性时把新值写回对象内容。GDevelop 的官方说明文档 Properties-schema-and-PropertiesEditor-explanations.md 描述了这套机制,本文结合仓库中 Video 对象和 TextObject 的真实代码,给出 JS 扩展的完整操作路径。
属性从哪里来:PropertyDescriptor 与属性面板的关系
在 GDevelop 中,一个"属性"由 GDCore 里的 PropertyDescriptor 类定义。属性面板的显示逻辑是:
- 对象/行为声明一组
PropertyDescriptor(每个含值、类型、标签等); - 这些描述符被映射为 PropertiesEditor 使用的 schema;
- 用户改动属性后,编辑器回调你实现的
updateProperty(C++ 中为UpdateProperty)。
文档明确提示:只声明属性是不够的,还必须实现updateProperty,它会在用户在编辑器中修改属性时被调用,你可以在其中加入任何需要的校验逻辑。
PropertyDescriptor的完整 API 见 Core/GDCore/Project/PropertyDescriptor.h,除SetValue、SetType、SetLabel外还支持SetDescription、SetGroup、AddChoice、SetHidden、SetDeprecated、SetAdvanced等链式调用,返回PropertyDescriptor&,因此可以连续调用。
在 JS 扩展中声明属性(getProperties)
以仓库中 Video 扩展的 Extensions/Video/JsExtension.js 为例,在ObjectJsImplementation上挂一个getProperties函数,返回gd.MapStringPropertyDescriptor:
videoObject.getProperties = function () { var objectProperties = new gd.MapStringPropertyDescriptor(); objectProperties .getOrCreate('Looped') .setValue(this.content.loop ? 'true' : 'false') .setType('boolean') .setLabel(_('Loop the video')) .setGroup(_('Playback settings')); objectProperties .getOrCreate('Volume') .setValue(this.content.volume.toString()) .setType('number') .setLabel(_('Video volume (0-100)')) .setGroup(_('Playback settings')); objectProperties .getOrCreate('videoResource') .setValue(this.content.videoResource) .setType('resource') .addExtraInfo('video') .setLabel(_('Video resource')); return objectProperties; };对应的默认值放在videoObject.content中(如opacity: 255, loop: false, volume: 100),getProperties只负责把content里的值转成描述符。getOrCreate的参数就是属性名,后续updateProperty收到的propertyName与它一致。
文档中列出的可用setType取值:
| 类型 | 编辑器控件 | 附加要求 |
|---|---|---|
"string" | 文本输入框 | 默认类型 |
"number" | 数字输入框 | 无 |
"boolean" | 复选框 | 无 |
"resource" | 资源选择器 | 必须再调用addExtraInfo指定资源类型:"image"、"audio"、"font"或"json" |
资源类型下,值以字符串形式存储,但编辑器会显示选择器,被选中的资源会加入项目。
注意:类型字符串的合法取值由"负责更新属性网格的类"来解释(见PropertyDescriptor.h中对SetType的注释),上表来自官方说明文档;如果你使用文档未列出的自定义类型,需要自行确认属性面板一侧是否认识它。
实现 updateProperty 把编辑器输入写回 content
同一个文件中,updateProperty接收属性名和新值,按名字分发更新this.content,处理成功返回true,不认识的名字返回false:
videoObject.updateProperty = function (propertyName, newValue) { if (propertyName === 'Opacity') { this.content.opacity = parseFloat(newValue); return true; } if (propertyName === 'Looped') { this.content.loop = newValue === '1'; return true; } if (propertyName === 'Volume') { this.content.volume = parseFloat(newValue); return true; } if (propertyName === 'videoResource') { this.content.videoResource = newValue; return true; } return false; };要点:
- 新值
newValue始终是字符串,数字属性用parseFloat转换,布尔属性按编辑器传入的字符串形式判断(Video 示例中对Looped判断newValue === '1')。 - 文档建议在这个方法里加入属性校验逻辑,这是编辑器侧值生效前的必经回调。
- 除对象属性外,Video 示例还展示了实例(instance)侧的一对方法:
updateInitialInstanceProperty和getInitialInstanceProperties,签名分别为(instance, propertyName, newValue)和(instance),用于场景内实例的可编辑属性;实例不需要额外属性时返回false/ 空的MapStringPropertyDescriptor即可。
C++ 扩展的对应写法
C++ 侧的用法与 JS 基本一致:对象实现GetProperties()返回std::map<gd::String, gd::PropertyDescriptor>,并实现UpdateProperty。官方说明文档给出的 Video 对象示例(文档示例,照抄自上述文档):
std::map<gd::String, gd::PropertyDescriptor> videoObject::GetProperties() const { std::map<gd::String, gd::PropertyDescriptor> properties; properties[_("Opacity")] .SetValue(opacity) .SetType("number") .setLabel(_("Video opacity (0-255)")); // ... 其余属性同理 properties[_("Video resource")] .SetValue(videoDataFilename) .SetType("resource") .AddExtraInfo("video") .SetLabel(_('Video resource')); return properties; }仓库中可直接参考的完整 C++ 实现是 TextObject:TextObject::UpdateProperty位于第 44 行,TextObject::GetProperties位于第 139 行,行为(behavior)与实例属性也有各自的对应方法。
修改后如何验证属性生效
按 Extensions/Video/JsExtension.js 文件头的说明:
JsExtension.js会被监视,编辑器正在运行时改动会被自动导入;- 也可以手动执行导入:在
newIDE/app/scripts目录下运行node import-GDJS-Runtime.js; - 如果改动后扩展没有加载,打开开发者控制台搜索错误信息,这是文档给出的排查入口。
加载成功后,在编辑器中创建你的对象,属性面板会按getProperties的声明自动生成输入框(类型决定控件样式),修改某个属性触发updateProperty;返回false的名字不会被处理。
限制与后续方向
type与extraInformation本身是"任意字符串",其合法取值由解释它们的类决定(PropertyDescriptor.h注释原文),新增类型前先核对属性面板一侧的支持范围。- 官方文档指出
PropertyDescriptor与前端 schema 两个概念"应当在未来合并"(原文:The two concepts should be merged at some point),即这条链路两侧的实现仍在演进,改动前建议对照当前版本的 PropertiesMapToSchema.js。 - 属性声明(
getProperties/GetProperties)与回调(updateProperty/UpdateProperty)缺一不可,只声明属性时用户看到的控件不会把值写回对象。
【免费下载链接】GDevelop🎮 Open-source, cross-platform 2D/3D/multiplayer game engine designed for everyone.项目地址: https://gitcode.com/GitHub_Trending/gd/GDevelop
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考