为 SKLabelNode 中的单个角色设置动画

Animating individual characters in a SKLabelNode

有没有一种更有效的方法来在一个 sklabelnode 中通过打字来动画文本颤抖?我正在尝试在某些游戏中实现这种效果,例如 undertale,其中的文字在同时发抖的同时出现打字风格。

到目前为止,我只能做到这一点,但幸运的是:

class TextEffectScene: SKScene {

    var typeWriterLabel : SKLabelNode?
    var shiveringText_L : SKLabelNode?
    var shiveringText_O : SKLabelNode?
    var shiveringText_S : SKLabelNode?
    var shiveringText_E : SKLabelNode?
    var shiveringText_R : SKLabelNode?

    var button : SKSpriteNode?


    override func sceneDidLoad() {
        button = self.childNode(withName: "//button") as? SKSpriteNode

        self.scaleMode = .aspectFill //Very important for ensuring that the screen sizes do not change after transitioning to other scenes

        typeWriterLabel = self.childNode(withName: "//typeWriterLabel") as? SKLabelNode
        shiveringText_L = self.childNode(withName: "//L") as? SKLabelNode
        shiveringText_O = self.childNode(withName: "//O") as? SKLabelNode
        shiveringText_S = self.childNode(withName: "//S") as? SKLabelNode
        shiveringText_E = self.childNode(withName: "//E") as? SKLabelNode
        shiveringText_R = self.childNode(withName: "//R") as? SKLabelNode
    }



    // Type writer style animation

    override func didMove(to view: SKView) {
        fireTyping()
        shiveringText_L?.run(SKAction.repeatForever(SKAction.init(named: "shivering")!))
        shiveringText_O?.run(SKAction.repeatForever(SKAction.init(named: "shivering2")!))
        shiveringText_S?.run(SKAction.repeatForever(SKAction.init(named: "shivering3")!))
        shiveringText_E?.run(SKAction.repeatForever(SKAction.init(named: "shivering4")!))
        shiveringText_R?.run(SKAction.repeatForever(SKAction.init(named: "shivering5")!))
    }


    let myText = Array("You just lost the game :)".characters)
    var myCounter = 0
    var timer:Timer?

    func fireTyping(){
        typeWriterLabel?.text = ""
        timer = Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(TextEffectScene.typeLetter), userInfo: nil, repeats: true)
    }


    func typeLetter(){
        if myCounter < myText.count {
            typeWriterLabel?.text = (typeWriterLabel?.text!)! + String(myText[myCounter])
            //let randomInterval = Double((arc4random_uniform(8)+1))/20 Random typing speed

            timer?.invalidate()
            timer = Timer.scheduledTimer(timeInterval: 0.2, target: self, selector: #selector(TextEffectScene.typeLetter), userInfo: nil, repeats: false)
        } else {
            timer?.invalidate() // stop the timer
        }
        myCounter += 1
    }


    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        let touch = touches.first

        if let location = touch?.location(in: self) {
            if (button?.contains(location))! {
                print("doggoSceneLoaded")
                let transition = SKTransition.fade(withDuration: 0.5)
                let newScene = SKScene(fileNamed: "GameScene") as! GameScene
                self.view?.presentScene(newScene, transition: transition)
            }

        }


    }



}

如您所见,我必须在一个单词中为每个单独的标签节点设置动画 "loser"。

要创建此效果:

我在这方面有很多经验......除了你已经在做的事情之外,没有办法正确地做到这一点。我的解决方案(对于文本游戏)是将 NSAttributedString 与 CoreAnimation 一起使用,这使您可以在 UILabels 上获得疯狂的好动画...然后将 UILabels 添加到 SpriteKit 之上。

我正在研究一个更好的 SKLabel 子类,但最终放弃了,因为我意识到如果不做更多的工作就无法获得正确的字距调整。

可以使用 SKSpriteNode 并将视图作为纹理,然后您只需每帧更新纹理,但这需要更多的时间/资源。

执行此操作的最佳方法是在 SK 编辑器中按照您的操作方式进行操作。如果你需要 lot 的动画文本,那么你需要使用 UIKit 和 NSAttributedString 以及 CoreAnimation 来实现花哨的东西。

这是 IMO 的一个巨大的疏忽,是 SpriteKit 的一个相当大的缺点。 SKLabelNode 糟透了。

正如我在评论中所说,您可以从 SKNode 子类化并使用它为每个字符生成标签。然后将标签存储在数组中以供将来参考。

我很快就把一些东西放在一起,而且效果很好。我不得不玩一点定位,所以它看起来不错,因为空间有点太小了。另外每个标签的水平对齐必须是.left 否则,它会全部歪斜。

总之,超级好用!去试试吧!

这是我刚刚创建的要点 link。

https://gist.github.com/sonoblaise/e3e1c04b57940a37bb9e6d9929ccce27

对于那些可能对 Swift 4 感兴趣的人,我实现了一个 gitHub 项目此特殊请求称为 SKAdvancedLabelNode。 您可以找到 here 所有来源。

用法:

// horizontal alignment : left
var advLabel = SKAdvancedLabelNode(fontNamed:"Optima-ExtraBlack")
advLabel.name = "advLabel"
advLabel.text = labelTxt
advLabel.fontSize = 20.0
advLabel.fontColor = .green
advLabel.horizontalAlignmentMode = .left
addChild(self.advLabel)
advLabel.position = CGPoint(x:frame.width / 2.5, y:frame.height*0.70)
advLabel.sequentiallyBouncingZoom(delay: 0.3,infinite: true)

输出: