我想创建一个类似吉他的弦效果,类似于Les Paul's 96th Birthday Google Doodle中的效果。我想承认,我看到过一些类似的问题,它们使用JavaScript和CSS来解决这个问题。我对使用纯快速和spritekit感兴趣。对于如何实现这一目标,我将不胜感激。

最佳答案

您可以使用SKShapeNode为吉他弦建模。在下面的示例代码中,我创建了一个场景,响应将其转发到子字符串节点的触摸事件。使用余弦波函数和阻尼振幅对细度进行建模。
对于这个示例,我通过在字符串的开始、提取和结束位置之间添加线,创建了一个简单的路径。您可以使用样条曲线创建更平滑的线(一种方法是构造沿着这些点传递的catmull-rom样条曲线,并将其转换为Bezier样条曲线,该样条曲线可以直接用SKShapeNode渲染)。
我还控制着在计算振幅时,你能拨动一根弦的最大量。在实际的字符串中,朝向字符串末端的弯曲量将远远小于字符串中间的弯曲量。您可以使用一些应用于振幅的倾斜函数对此进行建模。
您可以使用传入cosupdate函数的参数来控制字符串的振动频率。注意,我已经为这个例子硬编码了一个时间增量。
调整上述参数将允许你钉你的采摘效果到你想要的配置。
swift - 如何使用Swift和SpriteKit创建类吉他的字符串-LMLPHP

import UIKit
import SpriteKit
import PlaygroundSupport


let view = SKView(frame: .init(origin: .zero, size: .init(width: 300, height: 300)))
PlaygroundPage.current.liveView = view

class GuitarString : SKShapeNode {

    let start: CGPoint
    let end: CGPoint
    var intermediate: CGPoint = .zero
    var amplitude: CGFloat = 0.0

    required init(start: CGPoint, end: CGPoint) {
        self.start = start
        self.end = end
        self.intermediate = start
        let path = CGMutablePath()
        path.move(to: start)
        path.addLine(to: end)
        super.init()
        self.path = path
        self.strokeColor = .red
        self.lineWidth = 2.0
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }


    func pluckStringBegan(at point: CGPoint) {
        intermediate = point
        amplitude = min(abs(point.y - start.y), 100) * (point.y - start.y < 0 ? -1 : 1)
        t = 0
    }



    var t:CGFloat = 0.0

    func update(dt: CGFloat) {
        amplitude *= 0.95
        t += dt
        let a = amplitude * cos(t * 10)
        // to get a smoother line, you might
        // consider creating a catmull rom spline
        // that passes through start, f and end
        // and convert that to a bezier curve
        let path = CGMutablePath()
        path.move(to: start)
        let f = CGPoint(x: intermediate.x, y: a + start.y)
        path.addLine(to: f)
        path.addLine(to: end)
        self.path = path
    }

}

class GuitarScene : SKScene {
    override init(size: CGSize) {
        super.init(size: size)
        self.isUserInteractionEnabled = true
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let t = touches.first else { return }
        let p = t.location(in: self.children[0])
        (self.children[0] as! GuitarString).pluckStringBegan(at: p)
    }

    override func update(_ currentTime: TimeInterval) {
        (self.children[0] as! GuitarString).update(dt: 1/20)
    }
}

let scene = GuitarScene(size: view.frame.size)
scene.scaleMode = .aspectFit
view.presentScene(scene)

let string = GuitarString(start: .init(x: 0, y: 150), end: .init(x: 300, y: 150))

string.position = .zero
string.zPosition = 100
scene.addChild(string)

关于swift - 如何使用Swift和SpriteKit创建类吉他的字符串,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43921774/

10-12 00:30
查看更多