SKCameraNode.position didSet не срабатывает при перемещении с помощью SKAction
У меня есть простой подкласс SKCameraNode
что я звонил InteractiveCameraNode
, Пока все очень просто: мне нужно, чтобы что-то происходило при изменении положения моей камеры. Вот что я сделал:
class InteractiveCameraNode: SKCameraNode {
// MARK: - Properties
var enableInteraction = true
var positionResponders = [(CGPoint, CGPoint) -> Void]()
/// Calls every closure in the `positionResponders` array
override var position: CGPoint {
didSet {
if enableInteraction {
for responder in positionResponders {
responder(oldValue, position)
}
}
}
}
}
Поскольку при перемещении камеры может происходить несколько вещей, у меня есть массив замыканий, которые вызываются при изменении положения камеры. Пока все работает отлично, кроме didSet
Наблюдатель не будет вызван, если я перемещу камеру с помощью действия. Если я использую ограничение на камеру, чтобы она отслеживала узел, а затем перемещала этот узел с действием, это работает. Если я перемещаю камеру рукой, она работает. Почему это не работает с действиями?
1 ответ
Мой предыдущий ответ был неверным на 100%.. Что бы ни привело меня к этому ответу, это была какая-то другая ошибка с моей стороны, и я прошу прощения.. Я также узнал кое-что полезное сегодня:)
Похоже, то поведение, которое вы видите, это либо A) ошибка, либо B) какой-то более глубокий механизм Swift / SK, который я не понимаю.
Вот обходной путь, который работал для меня на детской площадке:
class Noder: SKSpriteNode {
var myPosition: CGPoint = CGPoint.zero { didSet { print(position) } }
func initialize(scene: SKScene) {
isUserInteractionEnabled = true
scene.addChild(self)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
position = touches.first!.location(in: self.scene!)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
print(self.position)
run(.moveBy(x: -35, y: 0, duration: 0.5), completion: {
self.myPosition = self.position
})
}
}
использовать:
// In didmovetoview:
let node = Noder(color: .black, size: CGSize(width: 25, height: 25))
node.initialize(scene: self)
вывод, показывающий, что фактическая позиция была обновлена из действия и didSet
:
(50,0, -118,0)
(14.9999971389771, -118,0)
Но это, вероятно, будет слишком медленным для того, что вы хотите, поэтому вам лучше будет вручную установить position
или же myPosition
в update()
каждый кадр (какой будет работать для didSet
лол..)
(Благодарим за путаницу за этот абзац).
Кроме того, мне интересно, будет ли здесь работать KVO... Я не использовал их, но CameraNode уже является NSObject... что-то, на что можно посмотреть, так как это, вероятно, ошибка какого-то рода...
Выполнение действия, которое изменяет позицию вызывающего Node
подкласс не устанавливает свою позицию, свойство наблюдателя (в вашем случае didSet
) не вызывается и, следовательно, ваш код никогда не выполняется.
В этом случае решение заключается в использовании
SKSceneDelegate
и сравнить положение узла по двум его обратным вызовам. Вы сохраняете начальную позицию узла в обновлении (_:for:), которое вызывается в начале каждого кадра, а затем рассчитываете любое изменение позиции вdidEvaluateActions(for:)
, который вызывается после оценки действий.