skip to Main Content

Is it possible to create an SKAction for SKSpriteNode in SpriteKit that generates the same effect as “Photoshop” with the Edit->Transform->Distort option?

Example:

Distort image

3

Answers


  1. Chosen as BEST ANSWER

    I solve with this implementation:

    Swift 5

    extension SKSpriteNode {
    
        func addSkew(value: CGFloat = -1){
    
            var effectNode = SKEffectNode()
            effectNode.shouldRasterize = true
            effectNode.shouldEnableEffects = true
            effectNode.addChild(SKSpriteNode(texture: texture))
            effectNode.zPosition = 1
            let transform = CGAffineTransform(a:  1    , b:  0,
                                              c:  value, d:  1,
                                              tx: 0    , ty: 0)
            let transformFilter = CIFilter(name: "CIAffineTransform")!
            transformFilter.setValue(transform, forKey: "inputTransform")
            effectNode.filter = transformFilter
            addChild(effectNode)
            texture = nil
    
        }
    
    }
    

  2. The list of available SKAction‘s is here: https://developer.apple.com/reference/spritekit/skaction

    There is none to do exactly what you describe. Instead, you can export multiple sprite images from a photo editing tool like Photoshop, and use an animation action like class func animate(with: [SKTexture], timePerFrame: TimeInterval).

    This is a little more work, but should achieve the desired effect.

    Login or Signup to reply.
  3. You can create a skew using a 1×1 warp mesh. This is supported in iOS10.0+.

    This extension receives the skew angle in degrees, and distorts around the anchor point of the given sprite.

    Swift 4.2

    extension SKWarpGeometryGrid {
    
        public static var skewPosGridZero:[float2] {
            get {
                return [float2(0.0, 0.0), float2(1.0, 0.0),
                        float2(0.0, 1.0), float2(1.0, 1.0)]
            }
        }
    
        public static func skewXPosGrid(_ skewX: CGFloat, node:SKSpriteNode? = nil) -> [float2] {
    
            let anchorY:Float = Float(node?.anchorPoint.y ?? 0.5)  
            var skewPosGrid = skewPosGridZero
            let offsetX = Float(tan(skewX.degToRad()) * (node == nil ? 1.0 : (node!.size.height/node!.size.width)) )
            skewPosGrid[2][0] += offsetX * (1.0 - anchorY)
            skewPosGrid[3][0] += offsetX * (1.0 - anchorY)
            skewPosGrid[0][0] -= offsetX * anchorY
            skewPosGrid[1][0] -= offsetX * anchorY
    
            return skewPosGrid
    
        }
    
        public static func skewYPosGrid(_ skewY: CGFloat, node:SKSpriteNode? = nil) -> [float2] {
    
            let anchorX:Float = Float(node?.anchorPoint.x ?? 0.5)  
            var skewPosGrid = skewPosGridZero
            let offsetY = Float(tan(skewY.degToRad()) * (node == nil ? 1.0 : (node!.size.width/node!.size.height)) )
            skewPosGrid[1][1] += offsetY * (1.0 - anchorX)
            skewPosGrid[3][1] += offsetY * (1.0 - anchorX)
            skewPosGrid[0][1] -= offsetY * anchorX
            skewPosGrid[2][1] -= offsetY * anchorX
    
            return skewPosGrid
    
        }
    
        public static func skewX(_ angle: CGFloat, node:SKSpriteNode? = nil) -> SKWarpGeometryGrid {
    
            return SKWarpGeometryGrid(columns: 1, rows: 1, sourcePositions: skewPosGridZero, destinationPositions: skewXPosGrid(angle, node:node))
    
        }
        public static func skewY(_ angle: CGFloat, node:SKSpriteNode? = nil) -> SKWarpGeometryGrid {
    
            return SKWarpGeometryGrid(columns: 1, rows: 1, sourcePositions: skewPosGridZero, destinationPositions: skewYPosGrid(angle, node:node))
    
        }
    
        public static func skewZero() -> SKWarpGeometryGrid {
            return SKWarpGeometryGrid(columns: 1, rows: 1)
        }
    
    }
    

    Example animation:

        let spriteNode = SKSpriteNode(imageNamed: "tex")
        spriteNode.anchorPoint = CGPoint(x:0.25, y:1.0)
        let skewA = SKWarpGeometryGrid.skewX(-45.0, node: spriteNode)
        let skewB = SKWarpGeometryGrid.skewX(45.0, node: spriteNode)
        spriteNode.warpGeometry = skewB
        if let skewActionA = SKAction.warp(to: skewA, duration: 3.0),
            let skewActionB = SKAction.warp(to: skewB, duration: 3.0){
            // Individual easing
            skewActionA.timingMode = .easeInEaseOut
            skewActionB.timingMode = .easeInEaseOut
            spriteNode.run(SKAction.repeatForever(SKAction.sequence([skewActionA,skewActionB])))
        }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search