macOS 10.13,Xcode 10b3
我有一个SpriteKit应用程序,其中SKSpriteNodes排成一行(它们包含在数组中),我想在该行/数组中插入新元素,并沿同一行移开先前的节点。 (想想Zuma的复仇,一连串的节点移动,您可以射击以将新的节点插入到该链中。)
我尝试了以下方法:
以递归方式计算节点是否有近邻(一个距离单位),如果是,则询问该节点是否有近邻并将其移开。失败很严重,因为确保节点在分流操作之前运行checkNeighbour动作的唯一方法是将它们作为一组SKAction运行,并且SKAction的评估周期与普通代码不同,因此有效地是>
let result = checkNearNeighbour(for:currentNode,at:currentNodeIndex) // checkNearNeighbour递归运行,并且仅在评估整个链时才返回值
切换结果{ 正确的情况: allNodes.insert(node,at:index)
的顺序不正确,这意味着在之前插入了一个新节点,前一个节点完成了对附近邻居的检查,在这种情况下,新插入的节点将被计为附近邻居,并且原来的邻居被分流了两次。
(所有这些计算都在SKScene内部进行,所以我没有更好的移动它们的地方。大节点是我在其后插入新节点的节点,最右边的节点已检查了邻居两次,因此两次移动。)
在这一点上,我没有主意。我需要一种方法a)可视地插入节点,b)将其插入基础数组。我不愿屈服于递归(这似乎是合理的解决方案,但是它行不通),但是我现在看不到实现这一目标的另一种方法,至少没有一种方法不涉及使自己陷入困境。
更新
根据Knight0fDragon's的建议,我现在首先将节点插入阵列,并开始检查在同一位置是否还有另一个节点。 (这意味着使用moveTo而不是moveBy,因为moveBy非常不精确,因此您需要舍入该位置)。这对于单次插入非常有用,但是如果您快速插入节点,则先前的节点不会足够快地移开路径(与基于atPoint的递归相同的问题);由于SpriteKit和Cocoa处于不同的周期,因此似乎只有在最后一个节点移入位置后才触发下一个插入的方法。
我的基本递归函数(减去安全性)是
func checkNearNeighbour(for node: SKSpriteNode, index: Int) -> Bool{
let nextNode = allNodes[nodeIndex + 1]
guard (nextNode.position.x == node.position.x) else {return false}
let nextPosition = CGPoint(x: nextNode.position.x + nodeDistance, y: nextNode.position.y)
let moveAction = SKAction.move(to: nextPosition, duration: 0.5)
let checkNext = SKAction.run {
self.calculateNearNeighbour(for: nextNode, index: nodeIndex + 1)
}
nextNode.run(SKAction.sequence([moveAction, checkNext]))
return true
}
我看不到有任何办法可以延迟对newNode的下一次调用(该调用只是将节点插入到数组中并运行checkNearNeighbour),直到该函数最终返回为止。