如何使用 swift 将 touchesbegan 事件委托给实体组件?

How can I delegate a touchesbegan event to an entities component using swift?

我正在使用 swift 为 ios 创建游戏。我已经从 Apples GameplayKit 中实现了组件实体系统,与 this tutorial.

中所示的非常相似

我添加了一个正方形网格,我想对点击手势做出不同的响应。当点击 UI 元素时,我将使用状态机更改游戏状态,但我还想更改每个方块对点击手势的反应。根据我目前有限的理解,最好的方法是更改​​点击手势委托。但是,我一直找不到任何简单的例子来说明如何做到这一点。正方形是 SKSpriteNodes.

代码可应要求提供;但是,我正在寻找一个脱离上下文的示例,说明如何以最简单的方式完成此操作。

有谁知道如何做到这一点或可以提出 "better" 方法。为了避免主观性,我在架构方面将更好定义为结构更好。 (例如,单个手势处理程序中的多个 if 语句似乎是执行此操作的错误方法。)

根据我得到的各种帮助和想法,我找到了解决我的问题的有效方法,但是我仍然非常愿意接受其他解决方案。

这个问题提出的主要问题是如何从 spritenode 引用回实体。 通过阅读 SKSpriteNode 的文档,我发现它的父 class SKNode 有一个 userData attribute,它允许您在该节点中存储数据。

将实体实例附加到需要在 SpriteComponent 中发生的节点,因为这是构造节点的地方,但是它不能发生在构造函数中,所以它必须在 SpriteComponent 中的函数中。

func addToNodeKey() {
    self.node.userData = NSMutableDictionary()
    self.node.userData?.setObject(self.entity!, forKey: "entity")
  }

然后在实体class构造中将组件添加到自身后调用该函数。

addComponent(spriteComponent)
spriteComponent.addToNodeKey()

现在可以从触摸事件访问 Enity 实例,我需要一种在该实例上执行功能的方法,但是您不知道该实例是否是 GKEntity 的子class 或不是,也不是什么类型。

因此,我又创建了一个组件TouchableSpriteComponent。经过一番尝试,init 函数将单个函数作为其参数,然后从场景触摸事件中调用该函数,这允许创建 TouchableSpriteComponent 的实体定义其处理事件的方式。

我创建了一个 gist for this solution,因为这里可能有太多代码无法放置。这是一个许可链接。

我真的很想知道这是否是一个 "good" 解决方案,或者是否有更清晰的路线会产生相同的效果(无需遍历所有实体或节点)。

如果我理解得很好,你应该有这样的东西:

func entityTouched(touches: Set<UITouch>, withEvent event: UIEvent?)

在您的 GKEntity 子类中。

我在游戏中这样做:

class Square: MainEntity {
    override func entityTouched(touches: Set<UITouch>, withEvent event: UIEvent?) {
        //DO something
    }
}

游戏场景:

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    super.touchesBegan(touches, withEvent: event)

    let touch = touches.first!
    let viewTouchLocation = touch.locationInView(self.view)
    let sceneTouchPoint = self.convertPointFromView(viewTouchLocation)
    let touchedNode = self.nodeAtPoint(sceneTouchPoint)

    let touchedEntity = (touchedNode as? EntityNode)?.entity

    if let myVC = touchedEntity as? MainEntity {
        myVC.entityTouched(touches, withEvent: event)
    }

其中:

实体节点:

class EntityNode: SKSpriteNode {
    // MARK: Properties
    weak var entity: GKEntity!
}

精灵组件:

class SpriteComponent: GKComponent {

    let node : EntityNode

    init(entity: GKEntity, texture: SKTexture, size: CGSize) {
        node = EntityNode(texture: texture, color: SKColor.whiteColor(), size: size)
        node.entity = entity
    }
}

主要实体:

class MainEntity: GKEntity {

    var entityManager : EntityManager!
    var node : SKSpriteNode!

    //MARK: INITIALIZE

    init(position:CGPoint, entityManager: EntityManager) {
        super.init()

        self.entityManager = entityManager

        let texture = SKTexture(imageNamed: "some image")
        let spriteComponent = SpriteComponent(entity: self, texture: texture, size: texture.size())
        node = spriteComponent.node
        addComponent(spriteComponent)
    }

    func entityTouched (touches: Set<UITouch>, withEvent event: UIEvent?) {}
}

让我知道您是否正在寻找。