3

几个星期以来,我一直在考虑在脑海中创建一种基于 ECS 的编程语言的想法。但是,我不太确定创建基于 ECS 的通用语言是否可行。

数据结构将如何实现?你怎么能做图形的东西或网络的东西?

我开始认为这是不可能的,但我决定在放弃这个想法之前先在这里问一下。我真的很想完成这项工作,但我只是不知道这是否可能。

那么,有可能吗?你会怎么做我提到的事情?

提前致谢!

4

1 回答 1

3

我们实际上有一个专有的,我们在我们的案例中使用。它远不是一种功能齐全的语言,而只是一种旨在使使用 ECS 数据结构和组件更容易的 DSEL。

我们的主要关注点实际上是编译时反射,例如语言中定义的任何数据类型的自动序列化(UDT 使用相同的structC 中具有相同成员对齐的接口)以及允许在该语言中定义的任何数据类型立即用作场景中的组件类型,而无需任何数据类型的显式注册(每个数据类型都有自己的唯一类型索引,可以在没有 RTTI 的情况下很容易在编译时抓取)。大多数情况下,我们发现像序列化和类型注册,最重要的是,在 C 和 C++ 等语言中进行反射往往需要大量的样板文件或极其花哨的模板元编程。我们开始厌倦了这一切,所以我们制作了一种相当简单的类 C 语言(编译器实际上只是生成 C 代码)为我们自动完成所有工作。实际上,一旦 C++reflexprReflection TS.

该语言实际上主要侧重于以与 C 兼容的方式定义数据类型,但会自动生成函数来序列化、反序列化、比较、交换和向 ECS 注册它们。在那里做一些事情很简单,比如在编译时迭代 a 的所有成员变量struct并将它们序列化、交换它们等。我们最终仍然在 C++ 中实现我们的大部分逻辑,并且只是通过我们的语言将数据传递给 C++。例如,我们可以只写:

struct Foo
{
    float x, y, z;
};

...并立即将Foo组件插入到我们的 ECS 场景中,而无需编写类似ecs.register<Foo>();或任何类似性质的内容。我从来没有发现类型注册如此重要,因为大多数引擎没有超过几十个组件类型,但是序列化和反序列化尤其是在我们的编辑器中生成 GUI 是一个很大的 PITA。该语言的重点主要是让它变得轻而易举,尽管它确实围绕着 ECS 作为存储和表示所有程序数据的中心方式。它允许我们执行以下操作:

def(generic_type) void serialize(out_stream& out, generic_type udt)
{
    // Compile-time reflection: the key feature of our language and the
    // main rationale for its existence. Calls serialize(out, member) for
    // each member of the user-defined type/struct.
    $for_each_member(udt, serialize, out);
}
def void serialize(out_stream& out, float val)
{
    out.write_float(val);
}

如上所示,我们还对泛型以及函数重载有一些有限的支持(我们实际上没有成员函数,但编写x.some_func(y)只是编写的语法替代方案some_func(x, y)——我们没有为封装和面向对象编程而烦恼,因为主要关注点是 ECS)。

至于 ECS 数据结构,它们与我们用 C 或 C++ 等语言实现它们的方式没有什么不同,实际上,它们是用 C++ 实现的。我们对编译器所做的第一件事是确保它可以轻松地与 C 互操作,并调用 C API 函数,以便我们可以在 C 端实现我们需要的任何东西(包括基本的 ECS 数据结构以及图形函数之类的东西) . 这是相当标准的东西,尽管在实现一种新语言时,编译器/解释器是通过一些统一的 API 或外部函数接口让它与像 C 这样的语言互操作。在我们的例子中,由于我们的编译器生成的是 C 代码而不是机器代码,因此允许它立即调用我们喜欢通过 dylib 导出的任何 C 函数(包括用 C++ 实现的函数)非常简单。

于 2020-11-02T06:51:35.000 回答