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:), который вызывается после оценки действий.

Прочитайте больше

Другие вопросы по тегам