簡體   English   中英

SceneKit:如何一起為多個SCNNode制作動畫,然后一次調用完成塊

[英]SceneKit: how to animate multiple SCNNodes together then call completion block once

目標是同時對多個SCNNode進行動畫處理,然后在所有動畫完成后調用完成塊。 並行動畫具有相同的持續時間,因此,如果一起開始,它們將在同一時間完成。

這個SO答案建議使用Sprite Kit的group函數,但是由於SCNScene類缺少runAction所以Scene Kit中沒有模擬功能。

一種選擇是對每個節點分別運行所有操作,並讓每個調用相同的完成功能,該功能必須維護一個標志以確保僅被調用一次。

另一種選擇是避免使用完成處理程序,並在與動畫持續時間匹配的延遲后調用完成代碼。 但是,這會在測試期間創建比賽條件,因為有時動畫會在完成之前停滯不前。

不過,這似乎很笨拙。 在SceneKit中將多個節點的動畫分組然后調用完成處理程序的正確方法是什么?

由於所有初始動畫都具有相同的持續時間,因此我最初采用的方法是將完成處理程序僅應用於其中一個動作。 但是,有時動畫會掛斷( SCNAction完成處理程序等待手勢執行 )。

我目前成功的解決方案是不要將完成處理程序與SCNAction一起使用,但要延遲:

func delay(delay:Double, closure:()->()) {
    dispatch_after(
        dispatch_time(
            DISPATCH_TIME_NOW,
            Int64(delay * Double(NSEC_PER_SEC))
        ),
        dispatch_get_main_queue(), closure)
}

調用示例:

delay(0.95) {
     self.scaleNode_2.runAction(moveGlucoseBack)
     self.fixedNode_2.runAction(moveGlucoseBack)
     self.scaleNode_3.hidden = true
     self.fixedNode_3.hidden = true
}

我懷疑這是否可以稱為“正確的方式”,但是它是否可以很好地用於我的用途,並消除了嘗試在具有完成處理程序的多個節點上運行動畫時遇到的隨機掛斷。

我還沒有完全考慮到這一點,但是我希望將其發布有用。

GCD的dispatch_barrier是一般問題,即在一系列操作的最后一個操作完成之后執行一些操作。 將所有塊提交到私有並發隊列,然后使用dispatch_barrier提交大結局完成塊。 大結局在所有先前的方塊完成之后開始運行。

我現在看不到的是如何將這些GCD調用與SceneKit調用和完成處理程序集成在一起。

也許dispatch_group是更好的方法。

歡迎編輯和評論!

嘗試這樣的事情:

private class CountMonitor {
    var completed: Int = 0
    let total: Int
    let then: ()->Void

    init(for total: Int, then: @escaping(()->Void)) {
        self.total = total
        self.then = then
    }

    func didOne() {
        completed += 1
        if completed == total {
            then()  // Generally you should dispatch this off the main thread though
        }
    }
}

然后創建動作如下所示:

private func test() {
    // for context of types
    let nodes: [SCNNode] = []
    let complexActionsToRun: SCNAction = .fadeIn(duration: 100)

    // Set up the monitor so it knows how many 'didOne' calls it should get, and what to do when they are all done ...
    let monitor = CountMonitor(for: nodes.count) { () in
        // do whatever you want at the end here
        print("Done!")
    }
    for node in nodes {
        node.runAction( complexActionsToRun ) { () in
            monitor.didOne()
        }
    }
}

請注意,您還應該考慮到節點數組為空(您可能仍然想在最后做任何想做的事情,在這種情況下只是立即做)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM