带圆角的渐变进度条 SpriteKit Swift
Gradient progress bar with rounded corners SpriteKit Swift
我正在尝试在 SpriteKit 中构建一个带有圆角的渐变进度条,但我完全卡在了这一点上。我已经尝试了 SKCropNode、SKShapeNodes 等的不同组合,但我似乎无法让它工作。
感谢任何帮助,亲切的问候!
它是关于 SKCropNode + 它的 maskNode 属性。来自文档:
SKCropNode is a container node that you use to crop other nodes in the
scene. You add other nodes to a crop node and set the crop node's
maskNode property. For example, here are some ways you might specify a
mask:
An untextured sprite that limits content to a rectangular portion of
the scene.
A textured sprite that works as a precise per-pixel mask.
A collection of child nodes that form a unique shape.
You can animate the shape or contents of the mask to implement
interesting effects such as hiding or revealing.
所以,一个简单的例子是这样的:
class GameScene: SKScene {
override func sceneDidLoad() {
super.sceneDidLoad()
createProgressBar()
}
private func createProgressBar(){
let barFrame = CGRect(x: 0, y: 0, width: 300, height: 15)
if let cgImage = createImage(frame: barFrame) {
let texture = SKTexture(cgImage: cgImage)
let sprite = SKSpriteNode(texture: texture)
let cropNode = SKCropNode()
let mask = SKSpriteNode(color: .gray, size: barFrame.size)
cropNode.addChild(sprite)
cropNode.maskNode = mask
sprite.anchorPoint = CGPoint(x: 0.0, y: 0.5)
mask.anchorPoint = CGPoint(x: 0.0, y: 0.5)
var counter:Double = 0
let action = SKAction.run {[weak self, sprite] in
guard let `self` = self, counter < 100 else {
sprite?.removeAction(forKey: "loop")
return
}
counter += 1
let newWidth = self.getWidth(percents: counter, spriteWidth: barFrame.width)
print("Bar width \(newWidth), percentage \(counter)")
mask.size = CGSize(width: newWidth, height: barFrame.height)
}
let wait = SKAction.wait(forDuration: 0.05)
let sequence = SKAction.sequence([wait, action])
let loop = SKAction.repeatForever(sequence)
addChild(cropNode)
cropNode.position = CGPoint(x: self.frame.width / 2.0, y: self.frame.height / 2.0)
sprite.run(loop, withKey: "loop")
}
}
private func getWidth(percents:Double, spriteWidth:Double)->Double{
let onePercent = spriteWidth / 100.0
return onePercent * percents
}
private func createImage(frame barFrame:CGRect) -> CGImage?{
if let ciFilter = CIFilter(name: "CILinearGradient"){
let ciContext = CIContext()
ciFilter.setDefaults()
let startColor = CIColor(red: 0.75, green: 0.35, blue: 0.45, alpha: 1)
let endColor = CIColor(red: 0.45, green: 0.35, blue: 0.75, alpha: 1)
let startVector = CIVector(x: 0, y: 0)
let endVector = CIVector(x: barFrame.width, y: 0)
ciFilter.setValue(startColor, forKey: "inputColor0")
ciFilter.setValue(endColor, forKey: "inputColor1")
ciFilter.setValue(startVector, forKey: "inputPoint0")
ciFilter.setValue(endVector, forKey: "inputPoint1")
if let outputImage = ciFilter.outputImage {
let cgImage = ciContext.createCGImage(outputImage, from: CGRect(x: 0, y: 0, width: barFrame.width, height: barFrame.height))
return cgImage
}
}
return nil
}
}
现在因为这只是一个例子,我不会一直去实现这个权利,但你可以用可设计和可检查的属性制作一个 class,优化代码,使其可重用等。但是这里显示了总体思路。
您使用SKCropNode
在其中添加进度条,并使用maskNode
属性随着百分比的增加显示进度条。我还提供了一种以编程方式创建纹理的方法,但您可以只使用 .png 文件。
此处仅使用裁剪节点来产生渐变(因为我们不想缩放图像,而是逐部分显示)。显然,如果进度条只有一种颜色,则不需要裁剪节点。
这是最终结果:
我正在尝试在 SpriteKit 中构建一个带有圆角的渐变进度条,但我完全卡在了这一点上。我已经尝试了 SKCropNode、SKShapeNodes 等的不同组合,但我似乎无法让它工作。 感谢任何帮助,亲切的问候!
它是关于 SKCropNode + 它的 maskNode 属性。来自文档:
SKCropNode is a container node that you use to crop other nodes in the scene. You add other nodes to a crop node and set the crop node's maskNode property. For example, here are some ways you might specify a mask:
An untextured sprite that limits content to a rectangular portion of the scene.
A textured sprite that works as a precise per-pixel mask.
A collection of child nodes that form a unique shape.
You can animate the shape or contents of the mask to implement interesting effects such as hiding or revealing.
所以,一个简单的例子是这样的:
class GameScene: SKScene {
override func sceneDidLoad() {
super.sceneDidLoad()
createProgressBar()
}
private func createProgressBar(){
let barFrame = CGRect(x: 0, y: 0, width: 300, height: 15)
if let cgImage = createImage(frame: barFrame) {
let texture = SKTexture(cgImage: cgImage)
let sprite = SKSpriteNode(texture: texture)
let cropNode = SKCropNode()
let mask = SKSpriteNode(color: .gray, size: barFrame.size)
cropNode.addChild(sprite)
cropNode.maskNode = mask
sprite.anchorPoint = CGPoint(x: 0.0, y: 0.5)
mask.anchorPoint = CGPoint(x: 0.0, y: 0.5)
var counter:Double = 0
let action = SKAction.run {[weak self, sprite] in
guard let `self` = self, counter < 100 else {
sprite?.removeAction(forKey: "loop")
return
}
counter += 1
let newWidth = self.getWidth(percents: counter, spriteWidth: barFrame.width)
print("Bar width \(newWidth), percentage \(counter)")
mask.size = CGSize(width: newWidth, height: barFrame.height)
}
let wait = SKAction.wait(forDuration: 0.05)
let sequence = SKAction.sequence([wait, action])
let loop = SKAction.repeatForever(sequence)
addChild(cropNode)
cropNode.position = CGPoint(x: self.frame.width / 2.0, y: self.frame.height / 2.0)
sprite.run(loop, withKey: "loop")
}
}
private func getWidth(percents:Double, spriteWidth:Double)->Double{
let onePercent = spriteWidth / 100.0
return onePercent * percents
}
private func createImage(frame barFrame:CGRect) -> CGImage?{
if let ciFilter = CIFilter(name: "CILinearGradient"){
let ciContext = CIContext()
ciFilter.setDefaults()
let startColor = CIColor(red: 0.75, green: 0.35, blue: 0.45, alpha: 1)
let endColor = CIColor(red: 0.45, green: 0.35, blue: 0.75, alpha: 1)
let startVector = CIVector(x: 0, y: 0)
let endVector = CIVector(x: barFrame.width, y: 0)
ciFilter.setValue(startColor, forKey: "inputColor0")
ciFilter.setValue(endColor, forKey: "inputColor1")
ciFilter.setValue(startVector, forKey: "inputPoint0")
ciFilter.setValue(endVector, forKey: "inputPoint1")
if let outputImage = ciFilter.outputImage {
let cgImage = ciContext.createCGImage(outputImage, from: CGRect(x: 0, y: 0, width: barFrame.width, height: barFrame.height))
return cgImage
}
}
return nil
}
}
现在因为这只是一个例子,我不会一直去实现这个权利,但你可以用可设计和可检查的属性制作一个 class,优化代码,使其可重用等。但是这里显示了总体思路。
您使用SKCropNode
在其中添加进度条,并使用maskNode
属性随着百分比的增加显示进度条。我还提供了一种以编程方式创建纹理的方法,但您可以只使用 .png 文件。
此处仅使用裁剪节点来产生渐变(因为我们不想缩放图像,而是逐部分显示)。显然,如果进度条只有一种颜色,则不需要裁剪节点。
这是最终结果: