如何使用 - swift - SpriteKit编写将在特定时间运行函数的协议

时间:2017-10-07 16:35:57

标签: ios swift xcode sprite-kit protocols

是否可以创建这样的协议:

protocol SetupProt {
    func setup()
}

然后在我的didMove函数结束时,告诉应用程序运行实现此协议的所有子类的所有设置函数?

或者我是否需要存储对实现协议的所有这些对象的引用并进行迭代?

目前我正在使用该协议。

然后我有一个像这样的全局数组:

setups = [SetupProt] = []

我有"一个平台"的子类。在我的游戏中。我在XCODE编辑器中将其子类化。在aDecoder init函数中,我将该节点添加到此全局数组...

我这样做是因为此时场景属性为零,所以我无法访问它,它还没有完成加载我猜测。

在我的场景结束时移动,我遍历这个数组:

for set in setups { set.setup() }

这就完成了工作。

我想知道如果不是存储所有这些对象的数组,我可以告诉应用程序:"嘿,为实现此协议的任何内容运行setup函数。

5 个答案:

答案 0 :(得分:2)

对我来说;听起来你最好使用通知/观察者......你有多个对象想要响应一个事件。在这些对象的init或viewDidLoad函数中添加:

NotificationCenter.default.addObserver(_ observer: Any, selector aSelector: Selector, name aName: NSNotification.Name?, object anObject: Any?)

然后在didMove(_:)

的末尾
NotificationCenter.default.post(name aName: NSNotification.Name, object anObject: Any?)

这将导致这些#selector函数运行。只需确保在从内存中删除对象时删除观察者小心僵尸

答案 1 :(得分:2)

你在GameplayKit中这样做,所以你要做的就是浏览你的组件

entities.foreach{
  ($0.components.filter({$0 as? SetupProtocol != nil}) as? [SetupProtocol]).foreach{
    $0.setup()
  }
}

这将避免必须将通知侦听器附加到使用此协议的每个项目。安装通常是一个完成类型的交易,因此让您的实例“监听”仅发送一次的消息可能最终浪费资源。

游戏套件的优点在技术上你甚至不需要协议,你可以有一个专为设置而设计的组件,然后我们可以避免不必要的过滤,转换和循环。

entities.foreach{$0.component(ofType:SetupComponent).setup()}

- 内部SetupComponent

class SetupComponent : GKComponent
{
   func setup()
   { 
      guard let entity = entity as? SetupProtocol else {return}
      entity.setup()
   }
}

然后您可以更进一步,为所有组件创建“存储桶”。这将有助于您更好地管理事物。

let setupBucket =  entities.flatmap{$0.components.filter({$0 as? SetupProtocol != nil})} as? [SetupProtocol]. //I may need to verify this syntax is correct when I get home, doing it from memory.

您可以添加设置存储桶,更新存储桶等内容,所有这些都是每种类型组件的数组。这样,如果您需要在给定组件类型的所有实体上调用方法,则可以使用可以运行的存储桶。当然,您必须正确管理存储桶,并确保在组件与实体连接/移除时添加/删除。

现在我好像回想起iOS 10中我必须制作子组件类的组件问题,因为子类化不能正常工作,但我不知道它在iOS 11中的状态。我可以告诉你在XCode 9中破坏了Scenekit构建器组件,所以如果你现在可以避免使用它(你在Sprite Kit上,我不知道他们是否也在Sprite Kit上破坏了它)

答案 2 :(得分:1)

如果您的节点都是SKScene的子节点,则可以从场景开始递归调用方法。

protocol SetupProt {
    func setup()
}

class GameScene: SKScene, SetupProt {

    override func didMove(to view: SKView) {
        super.didMove(to: view)
        // Perform setup
        self.setup()
    }

    // MARK: - Private
    func setup() {
        self.setup(with: self)
    }
    func setup(with node: SKNode ) {
        // Call you method
        (node as? SetupProt)?.setup()

        // Recursively call for every node in scene
        for child in self.children where child is SetupProt {
            self.setup(with: child)
        }
    }
}

答案 3 :(得分:0)

我认为协议扩展适合你试试这个。我将举例说明如何使用协议扩展定义可选协议。

    // Protocol has empty default implementation of the following methods making them optional to implement:
// cancel()
protocol Cancelable {

    /// default implementation is empty.
    func cancel()
}

extension Cancelable {

    func cancel() {}
}

class Plane: Cancelable {
  //Since cancel() have default implementation, that is optional to class Plane
}

let plane = Plane()
plane.cancel()
// Print what you want

答案 4 :(得分:0)

如果您希望某个类的多个实例(例如某个节点)响应单个事件,最好的方法是使用通知和协议的混合。

首先,您需要像以前一样定义协议:

protocol SetupProt {
    func setup()
}

然后,创建一个实现协议的自定义节点类,并在init内,将节点作为观察者添加到将由场景发送的通知中:

class MyNode: SKNode, SetupProt {

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        // Add the node as observer for future trigger setup notifications
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(setup),
            name: NSNotification.Name("TriggerSetup"),
            object: nil
        )
    }

    // Protocol implementation
    @objc func setup() {
        // Implement your node setup here
    }
}

最后,实现您的场景并触发didMove方法中的观察者:

class MyScene: GameScene {

    override func didMove(to view: SKView) {
        super.didMove(to: view)

        // Once your Scene is in place, trigger the setup of all observers
        NotificationCenter.default.post(
            name: NSNotification.Name("TriggerSetup"),
            object: nil
        )
    }

}

通过这样做,您可以同时设置所有节点,而无需在场景中直接引用它们。它还避免使用迭代器。

您可以阅读更多关于通知和观察者如何工作的here