1

注意:这个介绍是关于实体系统的。但是,即使您不知道这些是什么,或者自己没有实现它们,它也是非常基础的,如果您有一般的 Javascript 经验,您可能有足够的资格来回答。

我正在T=machine 博客上阅读有关实体系统的文章

作者 Adam 建议实体应该只是一个 id,可用于获取它的组件(即实体应该表示的实际数据)。

我选择了所有实体都应该存储在“一个地方”的模型,我实现这种存储的主要嫌疑人是许多人使用的数组数组方法,这意味着动态实体 id 表示组件所属的索引到一个实体,而组件在那个“一个地方”中按类型分组(从现在起我将称之为“存储”),我计划将其实现为Scene. 这Scene将是一个处理实体组合、存储并可以对实体(.addComponent(entityID, component)等)进行一些基本操作的对象。

我不关心Scene对象,我很确定这是一个很好的设计,但我不确定存储的实现。

我有两个选择:

A)使用 array-of-array 方法,其中存储如下所示:

//storage[i][j] - i denotes component type, while j denotes the entity, this returns a component instance
//j this is the entity id

[
    [ComponentPosition, ComponentPosition, ComponentPosition],
    [ComponentVelocity, undefined, ComponentVelocity],
    [ComponentCamera, undefined, undefined]
]

//It's obvious that the entity `1` doesn't have the velocity and camera components, for example.

B)将存储对象实现为字典(技术上是 Javascript 中的对象)

{
    "componentType": 
    {
        "entityId": ComponentInstance
    }
}

字典方法意味着实体 id 是static,这对于在实体系统本身之外实现游戏循环和其他功能似乎是一件非常好的事情。此外,这意味着系统可以轻松地存储他们感兴趣的实体 id 数组。entityId 变量显然也可以是字符串,而不是整数索引。

我反对array-of-arrays方法的原因是删除实体会在删除单个实体时使其他实体ID发生变化。

实际的实现细节可能很谨慎,但我想知道哪种方法在性能方面会更好?

我也感兴趣的事情(请尽可能跨平台,但如果需要,请以 V8 为例):

  • 访问属性时的开销有多大,这是如何实现的?可以说他们正在从本地范围内访问。
  • 内存中有什么undefined,需要多少?我问这个,因为在数组数组方法中,所有内部数组必须具有相同的长度,并且如果实体没有特定组件,则该字段设置为undefined.
4

1 回答 1

-1

不用担心数组。它是 JavaScript 中的对象,即没有“真正的”数组,只是索引是对象属性(字典、哈希、映射)的数字“名称”。

这个想法很简单,一个数组有一个长度属性,允许循环知道在哪里停止迭代。通过简单地从数组中删除一个元素(记住,它是一个对象),长度属性实际上并没有改变。所以...

// create an array object
var array = ['one','two', 'three'];
console.log(array.length); // 3
// these don't actually change the length
delete array['two']; // 'remove' the property with key 'two'
console.log(array.length); // 3
array['two'] = undefined; // put undefined as the value to the property with key 'two'
console.log(array.length); // 3
array.splice(1,1); // remove the second element, and reorder
console.log(array.length); // 2
console.log(array); // ['one','three']
  1. 您必须意识到 JavaScript 并不像您期望的那样“工作”。性能方面的对象和数组是相同的,即像字典一样访问数组;
  2. Scope 与其他“c 风格”语言不同。只有全局和函数作用域,即没有块作用域(永远不要在另一个 for(var i) 中写 for(var i));
  3. undefined in memory 与 null 的数量完全相同。不同之处在于 null 是故意缺失值,而 undefined 只是意外(非故意)缺失;
  4. 不要通过做来检查一个字段是否存在,if(array['two'])因为一个字段实际上可以保存undefined、null、0、""、false和评估为 false 的假值。始终检查if('two' in array)
  5. 当使用for(key in array)always use循环时,if(array.hasOwnProperty(key))您不会迭代原型的属性(从某种意义上说是父级)。此外,由构造函数创建的对象也可能使用“构造函数”键循环。
于 2012-07-21T20:39:42.970 回答