1

我正在尝试围绕游戏实体系统并使用 GamePlayKit。我在以下情况下苦苦挣扎:

  • RenderComponent是一个GKComponent引用一个SKSpriteNode来显示我的实体。
  • MetaDataComponent是另一个包含有关实体的各种信息的组件(例如,在我的情况下,这将包含诸如MapX, MapY, ... 之类的属性)

我有一个CharacterEntity源自GKEntity.

为了初始化我的实体,我传递了用于精灵的纹理名称。这允许我创建RenderComponent.

要初始化MetaDataComponent我有三个选项,我想知道其中一个是否被认为是最佳实践(以及,哪一个是最差实践)?

  • 对于我的组件中的每个属性,添加一个参数到init()
  • 在类中公开属性,Character这将更新组件的属性。
  • 将模型对象传递给我的实体并从中初始化组件。

我的想法:

  • 第 1 点:我的实体拥有的组件越多,我得到的参数就越多……这不是我的偏好。
  • 第 2 点:一个实体应该是“愚蠢的”并且不携带任何数据。在最纯粹的形式中,实体只是一个数字。在那里添加道具“感觉”是错误的。
  • 第 3 点:拥有像MetaData我这样的模型对象感觉最好,但也是多余的,因为数据在组件模型对象中。也许让组件存储模型对象而不是其属性?

再举一个例子:如果我希望一个实体有一个RenderComponent,我可以查询那个组件并使用它。或者我可以向实体本身添加一个方法,例如setRenderPosition检查所需组件是否存在并更新它。再次的问题是,这样做是对还是错?

4

2 回答 2

2

如果您正在寻找纯净,Entity Component System那么设计包括三个部分:

Entity: 正如你所说,只是一个数字。没有其他的。

Component: 这只是数据。没有其他的。

System: 被遗忘的部分。这就是逻辑所在。您可以继承GKComponentSystem<GKComponent>自在 SpriteKit 中创建自己的系统。

This article and it's supporting code helped me a lot in understanding ECS. The DemoBots example is another one to look at for a spriteKit oriented implementation.

Since SpriteKit has it's own implementation of ECS and other quirks, some compromise is necessary I believe e.g. you need to render a node, so if you want a SpriteComponent, then you'll need to embed the node into the SpriteComponet or do something else - I preferred not to have a SpriteComponent, I created a VisualEntity that inherits from GKEntity, but that's my preference to focus on components that have behaviour that depends on the update run loop.

To answer your question about properties on entities, it doesn't seem necessary, since you can query the entity for any component you need access to.

guard let spriteComponent = entity?.component(ofType: SpriteComponent.self) else {
   return
}

The important thing is to be flexible, fit in with SpriteKit and be aware of the compromises you are making.

于 2017-01-15T19:42:27.563 回答
0

An option to consider is having extensions on GKEntity.

import SpriteKit
import GameplayKit

extension GKEntity {
    var isSelected: Bool {
        guard let component = self.component(ofType: SelectionComponent.self) else {
            return false
        }

        return component.selectionLocation != nil
    }
}

This makes the functionality available to all entities.

if self.someEntity.isSelected {
    // Handle 
}
于 2017-01-23T19:28:15.043 回答