选择如何在 ECS 中的组件之间拆分功能

Choose how to split functionality between my components in an ECS

我目前正在构建游戏,我想使用 Gameplaykit 来组织元素。

我发现了 ECS(实体组件系统)的概念,它可以将功能放入小块(称为组件)中,然后可以添加到实体中以赋予其功能。

我想结合SpriteKit使用,我的第一个想法当然是创建一个SpriteComponent,但是由于我也在使用SpriteKit的物理引擎,所以我想知道应该如何制作PhysicsBodyComponent,因为对于这个组件要工作它需要直接访问我的 SpriteKit 节点的物理体,所以它会依赖于 SpriteComponent,但是组件相互依赖不是错误的吗?
我应该怎么做?

谢谢。

这取决于您希望如何构建组件。就像你说的,最好让它们尽可能灵活、可重用和相互独立。

所以我会像您想要的那样创建一个简单的渲染组件。这是我在游戏中使用的。

 import SpriteKit
 import GameplayKit

 /// GK sprite component
 class SpriteComponent: GKComponent {

     // MARK: - Properties

     /// The rendered node
     let node: SKSpriteNode

     // MARK: GKComponent Life Cycle

     /// Init with image
     init(imageNamed: String) {
         node = SKSpriteNode(imageNamed: imageNamed)
     }

     /// Init with texture
     init(texture: SKTexture) {
         node = SKSpriteNode(texture: texture)
     }
 }

在您的实体中 classes 您照常添加组件

 class Player: GKEntity {

     override init() { // pass in an image name if you need to
        super.init()

        let spriteComponent = SpriteComponent(imageNamed: "Player")
        addComponent(spriteComponent)
     }
 }

然后将实体添加到场景中并对其进行定位。 将组件添加到实体后,您可以使用 component(ofType: ...) 方法访问其属性,在本例中为节点 属性,并对它们执行一些操作。

 class GameScene: SKScene {

     // code to add entity to scene
     ...

     // position entity 
     if let playerNode = player.component(ofType: SpriteComponent.self)?.node {
        playerNode.position = CGPoint(...)
    }

返回实体 class 并在添加精灵组件后添加物理体。

 ... 
 addComponent(spriteComponent)

 // Set physics body
 if let sprite = component(ofType: SpriteComponent.self)?.node { // component for class is an optional and nil until component is added to entity.
      sprite.physicsBody = SKPhysicsBody(...
      sprite.physicsBody?.categoryBitMask = ...
      ...
 }

这样您的所有实体都可以使用 1 个渲染组件,但在它们上面有不同的物理体并使用不同的位置。

您可以创建一个物理体组件并将位掩码等和您希望将其添加到的节点传递给 init 方法。但是我认为那会使它变得非常混乱,所以我更喜欢这种方式。

如果您确实需要使组件相互依赖,请记住每个 GKComponent 都有一个您可以使用的实体 属性。我会尽量避免这种情况,以使您的组件更加灵活。

  class SomeComponent: GKComponent {

      func test() {
         entity?.component(ofType: SomeOtherComponent.self)?.someMethod() // only works if this component  is added to entity (entity?) and the other component is also added to entity (...self)?.

       }

  class SomeOtherComponent: GKComponent {

      func someMethod() {

      }
  }

如果您需要更多信息,您应该阅读这些文章,它们非常好。

https://www.raywenderlich.com/119959/gameplaykit-tutorial-entity-component-system-agents-goals-behaviors

http://code.tutsplus.com/tutorials/an-introduction-to-gameplaykit-part-1--cms-24483

希望对您有所帮助