在 SKAction 动画之后无法禁用然后重新启用触摸
Cannot disable, then reenable touch, after an SKAction animation
我正在制作交互式动画场景。我希望在进入时禁用场景中的所有触摸。然后,一旦场景中的对象(子 classed 节点)完成 rotating/moving,我想重新启用屏幕上的所有触摸以允许交互。我已使用此代码禁用用户交互:
override func didMove(to view: SKView) {
setupNodes()
view?.isUserInteractionEnabled = false
spinLocations()
}
这是场景文件中用于 spinLocations 的代码:
func spinLocations() {
var allLocationArrays = [[String : CGPoint]]()
var previousArray = hiddenLocationPositions
for _ in 0...SearchConstant.numSpins {
let freshArray = generateNewLocationArray(previous: previousArray)
allLocationArrays.append(freshArray)
previousArray = freshArray
}
for (item, _) in hiddenLocationPositions {
let node = fgNode.childNode(withName: item) as! LocationNode
node.spin(position: allLocationArrays) // this is function below
}
hiddenLocationPositions = previousArray
}
这是节点 class 中的动画代码:
func spin(position: [[String : CGPoint]]) {
var allActions = [SKAction]()
for array in position {
let action = SKAction.move(to: array[self.name!]!, duration: 2.0)
allActions.append(action)
}
let allActionsSeq = SKAction.sequence(allActions)
self.run(SKAction.sequence([SKAction.wait(forDuration: 5.0), allActionsSeq, SKAction.run {
self.position = position[position.count - 1][self.name!]!
},]))
}
这是将触摸传回主场景的代码 class:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let parent = self.parent else { return }
}
如您所见,这里没有禁用触摸。
我不想在 runBlock
中添加 "waitForDuration" SKAction
以更改上一个操作后的视图状态;我希望程序确定动画何时完成执行,然后重新启用触摸。
为了做到这一点,我推测使用完成处理程序可能会起作用,但它只会立即重新启用触摸(例如,处理处理程序以旋转会导致再次检测到触摸)。以前,我也尝试过在 runBlock
中禁用视图,但当然,那是 运行 瞬间。如何确保在不使用 "waitForDuration." 的情况下在动画之后重新检测到触摸?
所以,这是一个简单的示例,展示了您如何:
1) 完全禁用触摸
2) 旋转一个节点
3) 当节点完成旋转时,启用触摸
这是代码(您可以 copy/paste 它来尝试它是如何工作的):
class Object:SKSpriteNode{
func spin(times:Int,completion:@escaping ()->()) {
let duration = 3.0
let angle = CGFloat(M_PI) * 2.0
let oneRevolution = SKAction.rotate(byAngle: angle , duration: duration)
let spin = SKAction.repeat(oneRevolution, count: times)
let sequence = SKAction.sequence([spin,SKAction.run(completion)])
run(sequence, withKey:"spinning")
}
}
class WelcomeScene: SKScene {
override func didMove(to view: SKView) {
view.isUserInteractionEnabled = false
print("Touches Disabled")
let object = Object(texture: nil, color: .purple, size: CGSize(width: 200, height: 200))
addChild(object)
object.spin(times: 3, completion: {[weak self] in
self?.view?.isUserInteractionEnabled = true
print("Touches Enabled")
})
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("touch detected")
}
deinit {
print("Welcome scene deinited")
}
}
在这里,您在加载场景时禁用触摸,开始旋转对象,然后将完成块传递给它...此处使用该代码块:
let sequence = SKAction.sequence([spin,SKAction.run(completion)])
所以在旋转之后,那个块将被执行。现在,有不同的方法可以做到这一点......就我个人而言,我会使用委托,但我认为这不会那么混乱......如果需要,我也可以为委托写一个例子,但基本上,你会做的是将场景设置为自定义节点的代理,并通知它旋转已完成,这样场景可以告诉视图重新启用触摸。
我正在制作交互式动画场景。我希望在进入时禁用场景中的所有触摸。然后,一旦场景中的对象(子 classed 节点)完成 rotating/moving,我想重新启用屏幕上的所有触摸以允许交互。我已使用此代码禁用用户交互:
override func didMove(to view: SKView) {
setupNodes()
view?.isUserInteractionEnabled = false
spinLocations()
}
这是场景文件中用于 spinLocations 的代码:
func spinLocations() {
var allLocationArrays = [[String : CGPoint]]()
var previousArray = hiddenLocationPositions
for _ in 0...SearchConstant.numSpins {
let freshArray = generateNewLocationArray(previous: previousArray)
allLocationArrays.append(freshArray)
previousArray = freshArray
}
for (item, _) in hiddenLocationPositions {
let node = fgNode.childNode(withName: item) as! LocationNode
node.spin(position: allLocationArrays) // this is function below
}
hiddenLocationPositions = previousArray
}
这是节点 class 中的动画代码:
func spin(position: [[String : CGPoint]]) {
var allActions = [SKAction]()
for array in position {
let action = SKAction.move(to: array[self.name!]!, duration: 2.0)
allActions.append(action)
}
let allActionsSeq = SKAction.sequence(allActions)
self.run(SKAction.sequence([SKAction.wait(forDuration: 5.0), allActionsSeq, SKAction.run {
self.position = position[position.count - 1][self.name!]!
},]))
}
这是将触摸传回主场景的代码 class:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let parent = self.parent else { return }
}
如您所见,这里没有禁用触摸。
我不想在 runBlock
中添加 "waitForDuration" SKAction
以更改上一个操作后的视图状态;我希望程序确定动画何时完成执行,然后重新启用触摸。
为了做到这一点,我推测使用完成处理程序可能会起作用,但它只会立即重新启用触摸(例如,处理处理程序以旋转会导致再次检测到触摸)。以前,我也尝试过在 runBlock
中禁用视图,但当然,那是 运行 瞬间。如何确保在不使用 "waitForDuration." 的情况下在动画之后重新检测到触摸?
所以,这是一个简单的示例,展示了您如何:
1) 完全禁用触摸
2) 旋转一个节点
3) 当节点完成旋转时,启用触摸
这是代码(您可以 copy/paste 它来尝试它是如何工作的):
class Object:SKSpriteNode{
func spin(times:Int,completion:@escaping ()->()) {
let duration = 3.0
let angle = CGFloat(M_PI) * 2.0
let oneRevolution = SKAction.rotate(byAngle: angle , duration: duration)
let spin = SKAction.repeat(oneRevolution, count: times)
let sequence = SKAction.sequence([spin,SKAction.run(completion)])
run(sequence, withKey:"spinning")
}
}
class WelcomeScene: SKScene {
override func didMove(to view: SKView) {
view.isUserInteractionEnabled = false
print("Touches Disabled")
let object = Object(texture: nil, color: .purple, size: CGSize(width: 200, height: 200))
addChild(object)
object.spin(times: 3, completion: {[weak self] in
self?.view?.isUserInteractionEnabled = true
print("Touches Enabled")
})
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("touch detected")
}
deinit {
print("Welcome scene deinited")
}
}
在这里,您在加载场景时禁用触摸,开始旋转对象,然后将完成块传递给它...此处使用该代码块:
let sequence = SKAction.sequence([spin,SKAction.run(completion)])
所以在旋转之后,那个块将被执行。现在,有不同的方法可以做到这一点......就我个人而言,我会使用委托,但我认为这不会那么混乱......如果需要,我也可以为委托写一个例子,但基本上,你会做的是将场景设置为自定义节点的代理,并通知它旋转已完成,这样场景可以告诉视图重新启用触摸。