ios – SpriteKit中的Animate路径绘图

前端之家收集整理的这篇文章主要介绍了ios – SpriteKit中的Animate路径绘图前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在尝试使用SpriteKit在路径上绘制笔画的动画.我已经使用SKActions实现了一个工作解决方案,并使用CABasicAnimations实现了单独的实现. SKAction解决方案不是很优雅;它在SKAction.repeatAction(action:count :)调用的每次迭代中创建并描绘一个新路径,每个新路径比前一个略微更完整.
func start() {
    var i:Double = 1.0
    let spinAction:SKAction = SKAction.repeatAction(SKAction.sequence([
        SKAction.runBlock({
            self.drawCirclePercent(i * 0.01)

            if (++i > 100.0) {
                i = 1.0
            }
        }),SKAction.waitForDuration(0.01)
    ]),count: 100)
    runAction(spinAction)
}

func drawCirclePercent(percent:Double) {
    UIGraphicsBeginImageContext(self.size)

    let ctx:CGContextRef = UIGraphicsGetCurrentContext()
    CGContextSaveGState(ctx)
    CGContextSetLineWidth(ctx,lineWidth)
    CGContextSetRGBStrokeColor(ctx,1.0,1.0)
    CGContextAddArc(ctx,CGFloat(self.size.width/2.0),CGFloat(self.size.height/2.0),radius/2.0,CGFloat(M_PI * 1.5),CGFloat(M_PI * (1.5 + 2.0 * percent)),0)
    CGContextStrokePath(ctx)

    let textureImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()
    texture = SKTexture(image: textureImage)

    UIGraphicsEndImageContext()
}

虽然上面的代码有效,但它肯定不是很漂亮或有效,而且很可能不是SKActions的用途. CABasicAnimation解决方案更优雅,更高效.

let path:CGMutablePathRef = CGPathCreateMutable()
CGPathAddArc(path,nil,40.0,CGFloat(M_PI_2 * 3.0),CGFloat(M_PI_2 * 7.0),false)

let pathLayer:CAShapeLayer = CAShapeLayer()
pathLayer.frame = CGRectMake(100,100,80.0,80.0)
pathLayer.path = path
pathLayer.strokeColor = SKColor.whiteColor().CGColor
pathLayer.fillColor = nil
pathLayer.lineWidth = 3.0
self.view.layer.addSublayer(pathLayer)

let pathAnimation:CABasicAnimation = CABasicAnimation(keyPath: "strokeEnd")
pathAnimation.duration = 2.0
pathAnimation.fromValue = 0.0
pathAnimation.toValue = 1.0
pathLayer.addAnimation(pathAnimation,forKey: "strokeEndAnimation")

我的问题是我真的更喜欢将所有代码都包含在SKSpriteNode的子类中(以至于如果以上两个解决方案是我唯一的选择,我会选择第一个).有没有什么方法可以让我的SKAction实现更接近CoreAnimation实现,而不需要包含CoreAnimation?基本上,我想知道SpriteKit是否具有我不知道哪些功能可用于改进第一个实现的功能.

解决方法

您可以通过提供基于SKShader的 properties,v_path_distance和u_path_length的一些输出自定义strokeShader来为SKShapeNode的路径设置动画.这由上面的rickster暗示,完整的代码如下.在着色器中,u_current_percentage由我们添加,并引用我们想要描绘的路径中的当前点.由此,场景决定了动画抚摸的速度.另请注意,strokeShader是片段着色器,在每一步输出RGB,它允许沿路径进行颜色控制,例如,可以使渐变颜色成为可能.

着色器作为文件添加到Xcode项目“animateStroke.fsh”:

void main()  
{  
    if ( u_path_length == 0.0 ) {  
        gl_FragColor = vec4( 0.0,0.0,1.0 );   
    } else if ( v_path_distance / u_path_length <= u_current_percentage ) {  
        gl_FragColor = vec4( 1.0,1.0 );   
    } else {  
        gl_FragColor = vec4( 0.0,0.0 );   
    }  
}

和样本SKScene子类使用它:

import SpriteKit  
    import GameplayKit  
    func shaderWithFilename( _ filename: String?,fileExtension: String?,uniforms: [SKUniform] ) -> SKShader {  
        let path = Bundle.main.path( forResource: filename,ofType: fileExtension )  
        let source = try! NSString( contentsOfFile: path!,encoding: String.Encoding.utf8.rawValue )  
        let shader = SKShader( source: source as String,uniforms: uniforms )  
        return shader  
}  
class GameScene: SKScene {  
    let strokeSizeFactor = CGFloat( 2.0 )  
    var strokeShader: SKShader!  
    var strokeLengthUniform: SKUniform!  
    var _strokeLengthFloat: Float = 0.0  
    var strokeLengthKey: String!  
    var strokeLengthFloat: Float {  
        get {  
            return _strokeLengthFloat  
        }  
        set( newStrokeLengthFloat ) {  
            _strokeLengthFloat = newStrokeLengthFloat  
            strokeLengthUniform.floatValue = newStrokeLengthFloat  
        }  
    }  

    override func didMove(to view: SKView) {  
        strokeLengthKey = "u_current_percentage"  
        strokeLengthUniform = SKUniform( name: strokeLengthKey,float: 0.0 )  
        let uniforms: [SKUniform] = [strokeLengthUniform]  
        strokeShader = shaderWithFilename( "animateStroke",fileExtension: "fsh",uniforms: uniforms )  
        strokeLengthFloat = 0.0  
        let cameraNode = SKCameraNode()  
        self.camera = cameraNode  
        let strokeHeight = CGFloat( 200 ) * strokeSizeFactor  
        let path1 = CGMutablePath()  
        path1.move( to: CGPoint.zero )  
        path1.addLine( to: CGPoint( x: 0,y: strokeHeight ) )  

        // prior to a fix in iOS 10.2,bug #27989113  "SKShader/SKShapeNode: u_path_length is not set unless shouldUseLocalStrokeBuffers() is true"  
        // add a few points to work around this bug in iOS 10-10.1 ->  
        // for i in 0...15 {  
        //    path1.addLine( to: CGPoint( x: 0,y: strokeHeight + CGFloat( 0.001 ) * CGFloat( i ) ) )  
        // }  

        path1.closeSubpath()  
        let strokeWidth = 17.0 * strokeSizeFactor  
        let path2 = CGMutablePath()  
        path2.move( to: CGPoint.zero )  
        path2.addLine( to: CGPoint( x: 0,y: strokeHeight ) )  
        path2.closeSubpath()  
        let backgroundShapeNode = SKShapeNode( path: path2 )  
        backgroundShapeNode.lineWidth = strokeWidth  
        backgroundShapeNode.zPosition = 5.0  
        backgroundShapeNode.lineCap = .round  
        backgroundShapeNode.strokeColor = SKColor.darkGray  
        addChild( backgroundShapeNode )  

        let shapeNode = SKShapeNode( path: path1 )  
        shapeNode.lineWidth = strokeWidth  
        shapeNode.lineCap = .round  
        backgroundShapeNode.addChild( shapeNode )  
        shapeNode.addChild( cameraNode )  
        shapeNode.strokeShader = strokeShader  
        backgroundShapeNode.calculateAccumulatedFrame()  

        cameraNode.position = CGPoint( x: backgroundShapeNode.frame.size.width/2.0,y: backgroundShapeNode.frame.size.height/2.0 )              
    }  

    override func update(_ currentTime: TimeInterval) {        
        // the increment chosen determines how fast the path is stroked. Note this maps to "u_current_percentage" within animateStroke.fsh  
        strokeLengthFloat += 0.01  
        if strokeLengthFloat > 1.0 {  
            strokeLengthFloat = 0.0  
        }        
    }  
}

猜你在找的iOS相关文章