- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我想创建一个类似吉他的弦乐效果,类似于 Les Paul's 96th Birthday Google Doodle 中的那个.我想承认我已经看到一些使用 Javascript 和 CSS 解决这个问题的类似问题。我对使用纯粹的 Swift 和 SpriteKit 很感兴趣。我将不胜感激有关如何实现这一目标的任何建议。
最佳答案
您可以使用 SKShapeNode
为您的吉他弦建模。在下面的示例代码中,我创建了一个响应触摸事件的场景,将触摸事件转发给它的子字符串节点。使用余弦波函数和应用的振幅阻尼对拉丝性进行建模。
对于示例,我通过在弦乐的开始、拨弦和结束位置之间添加线条创建了一个简单的路径。您可以使用样条曲线创建更平滑的线(一种方法是构建一个通过这些点的 Catmull Rom 样条,并将其转换为可以直接使用 SKShapeNode
渲染的 Bezier 样条)。
我还控制了在计算振幅时您可以拨弦的最大量。在真实的琴弦中,琴弦两端的弯曲量将比琴弦中间的弯曲量小得多。您可以使用一些应用于振幅的斜坡函数对此进行建模。
您可以使用传递给 update
中的 cos
函数的参数来控制琴弦振动的频率。请注意,我为此示例硬编码了时间增量。
调整上述参数将使您能够将拨弦效果钉在您想要的配置上。
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/
我在 Rails 应用程序中有一个花哨的“工作表”样式 View ,加载时间太长。 (在开发模式下,是的,我知道那里没有缓存,“在 57893 毫秒内完成(查看:54975,DB:855)”)工作表是
我是一名优秀的程序员,十分优秀!