Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create an SKTexture from an SKShapeNode

Is there a way to create an SKTexture from an SKShapeNode? Shape nodes are known to cause memory issues and I am looking for a way to create a static graphic from them (.png preferably).

like image 578
Ivan Lesko Avatar asked May 04 '14 21:05

Ivan Lesko


1 Answers

You can use the SKView method called textureFromNode:

Here's from the reference :

textureFromNode:

Renders and returns a Sprite Kit texture that contains the node’s contents.

- (SKTexture *)textureFromNode:(SKNode *)node

Parameters

node

A node object representing the content you want to render to the texture.

Return Value

A Sprite Kit texture that holds the rendered image.

Discussion The node being rendered does not need to appear in the view’s presented scene. The new texture is created with a size equal to the rectangle returned by the node’s calculateAccumulatedFrame method. If the node is not a scene node, it is rendered with a clear background color ([SKColor clearColor]).

UPDATE-- After exploring SKShapeNode a bit and verifying there indeed was a memory leak issue revolving around assigning a path and then removing the node, I had an idea...

Not really a new idea, more of a repurposed one. This wonderful idea actually allowed me to use SKShapeNodes to my hearts content :)

POOLING

Yep... I just created a pool of SKShapeNodes that I reused as needed. What a difference that makes :) So simply redefine the path whenever needed, when done using return to your pool, and it'll be waiting there for you to play with again at a later time.

You simply redefine the path whenever needed, when done using return to your pool, and it'll be waiting there for you to play with again at a later time.

Create a ivar or property NSMutableArray in your SKScene called pool and create it when you init the SKScene. You can either populate the array with your shape nodes during init, or you can create them as needed.

This is something quick method I created for grabbing a new node from the pool :

-(SKShapeNode *)getShapeNode
{
    if (pool.count > 0)
    {
        SKShapeNode *shape = pool[0];
        [pool removeObjectAtIndex:0];
        return shape;
    }

    // if there is not any nodes left in the pool, create a new one to return
    SKShapeNode *shape = [SKShapeNode node];

    return shape;
}

So wherever in the scene you need a SKShapeNode you'd do this :

SKShapeNode *shape = [self getShapeNode];
// do whatever you need to do with the instance

When you are done using the shape node, just return it to the pool and set the path to . For example :

[pool addObject:shape];
[shape removeFromParent];
shape.path = NULL;

I know it's a workaround and not an ideal solution, but certainly this is a very viable workaround for anyone wanting to use a large number of SKShapeNodes and not bleed memory.

like image 177
prototypical Avatar answered Nov 02 '22 00:11

prototypical