SKSpriteNode не отвечает, когда я пытаюсь его скрыть (спойлер: проблема с синхронизацией SKAction)

#swift #sprite-kit #skspritenode #skaction

#swift #sprite-kit #skspritenode #skaction

Вопрос:

Хорошо, итак, я работал над созданием диалогового окна в стиле RPG для проекта, и хотя большая часть этого проходит гладко, единственное, что меня сейчас смущает, это маленький значок в углу окна, чтобы сообщить вам, что есть еще.

Я пытался выяснить, как нарисовать фигуру, но, не добившись успеха в получении Core Graphics для рисования треугольников, я решил просто использовать изображение одного из них в формате PNG. Приведенный ниже код показывает все, что относится к тому, как он был настроен и управлялся.

Теперь, когда это выяснено, я пытаюсь заставить его скрывать маркер при обновлении поля и показывать его снова позже. Вот что я пробовал до сих пор:

  1. Метод 1: используйте .alpha = 0 , чтобы скрыть его от просмотра во время обновлений, восстановите с помощью .alpha = 1
  2. Метод 2: удалите его из дерева узлов
  3. Метод 3: поместите его за фоном окна (находится по адресу .zPosition = -1 )

Результат был одинаковым для всех 3 методов: треугольник просто остается на месте, не реагируя при вызове.

 class DialogBox: SKNode {
    private var continueMarker = SKSpriteNode(imageNamed: "continueTriangle") // The triangle that shows in the lower-right to show there's more to read

    init() {
        /// Setup and placement.  It appears in the proper position if I draw it and don't try to hide anything
        continueMarker.size.width = 50
        continueMarker.size.height = 25
        continueMarker.position = CGPoint(x: ((width / 2) - (continueMarker.size.width * 0.9)), y: ((continueMarker.size.height * 0.9) - (height - margin)))
        addChild(continueMarker)
    }

    func updateContent(forceAnimation: Bool = false) {
        /// Determine what content to put into the box
        
        hideContinueMarker()
        
        /// Perform the content update in the box (which works as it should)
        
        showContinueMarker()
    }

    func showContinueMarker() {
//      continueMarker.alpha = 1 /// Method 1: Use .alpha to hide it from view during updates

//      if (continueMarker.parent == nil) { // Method 2: Remove it from the tree
//          addChild(continueMarker)
//      }

        continueMarker.zPosition = -2 /// Method 3: place it behind the box background (zPosition -1)
    }
    
    func hideContinueMarker() {
//      continueMarker.alpha = 0 /// Method 1

//      if (continueMarker.parent != nil) { /// Method 2
//          continueMarker.removeFromParent()
//      }

        continueMarker.zPosition = 2 /// Method 3
    }
}
  

Ответ №1:

Хорошо, поэтому при вводе этого у меня появилось еще несколько идей, и в итоге я решил свою собственную проблему, поэтому я решил поделиться решением здесь, а не использовать DenverCoder9 для всех.

С положительной стороны, вы увидите простой способ анимации текста в SpriteKit! Ура!

В последней проверке, чтобы убедиться, что я не сошел с ума, я добавил несколько операторов печати в showContinueMarker() и hideContinueMarker() и заметил, что они всегда появлялись одновременно.

Что это значит? SKAction вероятно, ошибка. Вот посмотрите на код для анимации обновлений в поле:

     private func animatedContentUpdate(contentBody: String, speaker: String? = nil) {
        if let speaker = speaker {
            // Update speaker box, if provided
            speakerLabel.text = speaker
        }

        var updatedText = "" // Text shown so far
        var actionSequence: [SKAction] = []
        
        for char in contentBody {
            updatedText  = "(char)"
            
            dialogTextLabel.text = updatedText

            // Set up a custom action to update the label with the new text         
            let updateLabelAction = SKAction.customAction(withDuration: animateUpdateSpeed.rawValue, actionBlock: { [weak self, updatedText] (node, elapsed) in
                self?.dialogTextLabel.text = updatedText
            })
            
            // Queue up the action so we can run the batch afterward
            actionSequence.append(updateLabelAction)
        }
        
        /// HERE'S THE FIX
        // We needed to add another action to the end of the sequence so that showing the marker again didn't occur concurrent with the update sequence.
        let showMarker = SKAction.customAction(withDuration: animateUpdateSpeed.rawValue, actionBlock: { [weak self] (node, elapsed) in
            self?.showContinueMarker()
        })
        
        // Run the sequence
        actionSequence.append(showMarker)
        
        removeAction(forKey: "animatedUpdate") // Cancel any animated updates already in progress
        run(SKAction.sequence(actionSequence), withKey: "animatedUpdate") // Start the update
    }
  

На случай, если вы пропустили это в большом блоке, вот конкретный бит в изоляции

 let showMarker = SKAction.customAction(withDuration: animateUpdateSpeed.rawValue, actionBlock: { [weak self] (node, elapsed) in
    self?.showContinueMarker()
})
  

В принципе, нам нужно было добавить отображение треугольника в качестве действия в конце последовательности обновлений вместо того, чтобы просто предполагать, что это произойдет после обновления, поскольку функция была вызвана позже. Время.

И поскольку все 3 метода работают одинаково хорошо теперь, когда время было исправлено, я вернулся к .alpha = 0 методу, чтобы упростить его.