4

I'm trying to warp an SKLabelNode as a child of SKEffectNode (documentation says you can do that), but it flips the label node upside-down before it applies the warp. This may be a bug, but before I file it, I thought I'd ask on here...

Here's my code:

func warpNode(_ node: SKEffectNode)
{
    if #available(iOS 10.0, *)
    {
        let sourcePositions: [vector_float2] =
            [
                vector_float2(0, 0),   vector_float2(0.5, 0),   vector_float2(1, 0),  //bottom row of object
                vector_float2(0, 0.5), vector_float2(0.5, 0.5), vector_float2(1, 0.5),  //middle row of object
                vector_float2(0, 1),   vector_float2(0.5, 1),   vector_float2(1, 1)  //top row of object
            ]

        let destinationPositions: [vector_float2] =
            [
                vector_float2(0, 0),   vector_float2(0.5, 0),   vector_float2(1, 0),  //bottom row of object
                vector_float2(0, 0.5), vector_float2(0.5, 0.5), vector_float2(1, 0.5),  //middle row of object
                vector_float2(0, 0.8), vector_float2(0.5, 0.8), vector_float2(1, 0.8)  //top row of object
            ]

        let warpGeometryGrid = SKWarpGeometryGrid(columns: 2, rows: 2, sourcePositions: sourcePositions, destinationPositions: destinationPositions)

        let warpGeometryGridNoWarp = SKWarpGeometryGrid(columns: 2, rows: 2)

        node.warpGeometry = warpGeometryGridNoWarp

        let warpAction = SKAction.animate(withWarps: [warpGeometryGridNoWarp, warpGeometryGrid, warpGeometryGridNoWarp], times: [0.25, 0.5, 0.75], restore: true)

        node.run(warpAction!)
    }
    else
    {
        print("Need iOS >= iOS 10 to warp!!!")
    }
}

let effectNode = SKEffectNode()
effectNode.shouldEnableEffects = true                
addChild(effectNode)

let labelNode = SKLabelNode(fontNamed: "Chalkduster")
labelNode.text = "Label"
effectNode.addChild(labelNode)

warpNode(effectNode)

This code should squish the top of the label down and then return it to its original position (as if you pushed on a ball or something), however, it flips it upside-down, then squishes the top (which is now the bottom of the word), and then returns it to its original size and position (rightside-up).

EDIT: Based on 0x141E's comment, I converted the SKLabelnode to SKTexture and added a new SKSpriteNode with that texture. If I used the warpNode function on the effectNode, it had the same effect of flipping the word upside-down and then applying the squish. However, if I used the warpNode function directly on the new SKSpriteNode, it worked properly.

New code below:

func warpNode(_ node: SKSpriteNode)
{
    if #available(iOS 10.0, *)
    {
        let sourcePositions: [vector_float2] =
            [
                vector_float2(0, 0),   vector_float2(0.5, 0),   vector_float2(1, 0),  //bottom row of object
                vector_float2(0, 0.5), vector_float2(0.5, 0.5), vector_float2(1, 0.5),  //middle row of object
                vector_float2(0, 1),   vector_float2(0.5, 1),   vector_float2(1, 1)  //top row of object
            ]

        let destinationPositions: [vector_float2] =
            [
                vector_float2(0, 0),   vector_float2(0.5, 0),   vector_float2(1, 0),  //bottom row of object
                vector_float2(0, 0.5), vector_float2(0.5, 0.5), vector_float2(1, 0.5),  //middle row of object
                vector_float2(0, 0.8), vector_float2(0.5, 0.8), vector_float2(1, 0.8)  //top row of object
            ]

        let warpGeometryGrid = SKWarpGeometryGrid(columns: 2, rows: 2, sourcePositions: sourcePositions, destinationPositions: destinationPositions)

        let warpGeometryGridNoWarp = SKWarpGeometryGrid(columns: 2, rows: 2)

        node.warpGeometry = warpGeometryGridNoWarp

        let warpAction = SKAction.animate(withWarps: [warpGeometryGridNoWarp, warpGeometryGrid, warpGeometryGridNoWarp], times: [0.25, 0.5, 0.75], restore: true)

        node.run(warpAction!)
    }
    else
    {
        print("Need iOS >= iOS 10 to warp!!!")
    }
}

let labelNode = SKLabelNode(fontNamed: "Chalkduster")
labelNode.text = "Label"

let labelNodeTexture = SKView().texture(from: labelNode)! 
let labelNodeSprite = SKSpriteNode(texture: labelNodeTexture)

addChild(labelNodeSprite)

warpNode(labelNodeSprite)

I just eliminated the whole effectNode part of the code and added the new sprite and did the warp on that.

Darth Flyeater
  • 151
  • 1
  • 5
  • 2
    It looks like a bug. Alternatively, you can convert the label to a texture, via `SKView`'s `texture()` method, create an `SKSpriteNode` from the texture, and then warp the sprite. – 0x141E Nov 26 '16 at 05:37
  • Have been trying to get this to work for a couple of hours now, does not play nice with texture atlases either... This unfortunately is a trend for new SpriteKit features - very limited. – CloakedEddy Dec 04 '16 at 22:59

2 Answers2

1

Edited my question as the answer based on 0x141E's comment.

Darth Flyeater
  • 151
  • 1
  • 5
  • I had the same issue still in iOS 10.3.1. Doing the warp on an SKSpriteNode works well, but breaks if done on an SKEffectsNode. 0x141E's comment to convert into an SKSpriteNode worked perfectly. Not the first time we have to find work-arounds for Apple's bugs. Pity that "it just works" doesn't apply to sprite kit. One would expect better quality - it's Apple after all, not an indie dev shop... – JohnV May 03 '17 at 12:27
0

If you're always warping your label node (either animating it continuously or applying the warp initially) you can pre-emptively flip your label node by using labelNode.yScale = -1. Then when you warp, it'll be right side up. A little silly, but it works for my purposes.

Brad Root
  • 483
  • 5
  • 14