Multiple skshapenode in one draw?
Asked Answered
F

1

1

Hi I have drawn skshapenodes connecting the nodes in my graph for my visual a* representation.

for(int x=0; x<64; x++)
        {
            for(int y=0; y<48; y++)
            {
                PathFindingNode *node = [[gridToDraw objectAtIndex:x] objectAtIndex:y];
                for(int i=0; i< node.connections.count; i++)
                {
                    PathFindingNode *neighbor = [node.connections objectAtIndex:i];

                    SKShapeNode *line = [SKShapeNode node];
                    CGMutablePathRef pathToDraw = CGPathCreateMutable();
                    CGPathMoveToPoint(pathToDraw, NULL, node.position.x, node.position.y);
                    CGPathAddLineToPoint(pathToDraw, NULL, neighbor.position.x, neighbor.position.y);
                    line.path = pathToDraw;
                    line.lineWidth = 0.1f;
                    [line setStrokeColor:[UIColor blueColor]];
                    line.alpha = 0.1f;
                    [self addChild:line];
                }
            }
        }

There are lots of nodes in my graph and this draws almost 22,000 shapes. Is there a way I can draw these shapes in one draw call, as they are all the same, the only difference is the start and end location of them.

If I used a texture instead, which would be loaded in once, how could I change the rotation of it to join all of my nodes up like above.

Regards,

UPDATE:

SKShapeNode *line = [SKShapeNode node];
        CGMutablePathRef pathToDraw = CGPathCreateMutable();

        for(int x=0; x<64; x++)
        {
            for(int y=0; y<48; y++)
            {
                PathFindingNode *node = [[gridToDraw objectAtIndex:x] objectAtIndex:y];
                for(int i=0; i< node.connections.count; i++)
                {
                    PathFindingNode *neighbor = [node.connections objectAtIndex:i];
                    CGPathMoveToPoint(pathToDraw, NULL, node.position.x, node.position.y);
                    CGPathAddLineToPoint(pathToDraw, NULL, neighbor.position.x, neighbor.position.y);
                }
            }
        }

        line.path = pathToDraw;
        line.lineWidth = 0.1f;
        [line setStrokeColor:[UIColor blueColor]];
        line.alpha = 0.1f;
        [self addChild:line];

I have updated my code to look like the above, this draws one sknode, but it draws 185 times, why is this?

Foy answered 27/12, 2013 at 20:42 Comment(2)
22,000 nodes is really a lot, probably too much for any device to handle, sprites or otherwise, batched or not. In fact in my OS X test app Sprite Kit crashes if you use more than several thousand nodes (actual number depends on node type). You should try drawing (creating) only those nodes currently visible on screen.Sirup
Found your question in the revision queue. Please do not add more code when you edit your question. Edit the question again and replace the old code with the edited one. There is a question history to back if needed. Doing this helps us read the question; we don't have to sort the old from the new.Acroter
C
6

I was going to answer this yesterday on a similar question but it disappeared.

You can create one path and draw everything as one SKShapeNode using CGPathAddPath to merge the paths as you go.

Here's an example :

SKEffectNode *effectNode = [[SKEffectNode alloc]init];
SKShapeNode  *shape = [[SKShapeNode alloc] init];
CGMutablePathRef myPath = CGPathCreateMutable();
CGPathAddArc(myPath, NULL, 0,0, 15, 0, M_PI*2, YES);

CGMutablePathRef pathTwo = CGPathCreateMutable();
CGPathAddArc(pathTwo, NULL, 50,0, 15, 0, M_PI*2, YES);     
CGPathAddPath(myPath, NULL, pathTwo);

CGMutablePathRef pathThree = CGPathCreateMutable();
CGPathAddArc(pathThree, NULL, 100,0, 15, 0, M_PI*2, YES);
CGPathAddPath(myPath, NULL, pathThree);

shape.path = myPath;

[effectNode addChild:shape];
[self addChild:effectNode];

effectNode.shouldRasterize = YES;  // if you don't rasterize it's horrifically slow.

This was just an example of how to merge the different paths to create one SKShapeNode that has all visual elements you are seeking. You'll need to apply this concept to your code.

I added the resulting SKShapeNode to an SKEffectNode so that I could utilize the shouldRasterize property to cache the shape, otherwise your framerate will be horrible.

Coth answered 28/12, 2013 at 1:26 Comment(6)
Thanks for the answer, I've extracted out some of the logic (see updated answer. This means I only use 1 node now, although it draws 185 times, why is this?Foy
Did you use the SKEffectNode with shouldRasterize ? I didn't check how many draws it was doing or performance beyond a grid the size of the screen. I think the comment on your question was a good one in that you might only want to be rendering what is visible if your grid is so large.Coth
Also, do you mean it draws 185 times per frame or when you create it ? Big difference.Coth
Are you looking to manipulate this grid in real-time ? My impression was this was meant to be a static image. In which case if you use shouldRasterize, it should use only one draw call per frame as it's using the cached version.Coth
For the record, I believe the same would be the case if you added all your SKShapeNodes in an SKEffectNode and set the shouldRasterize property. I have not tried that, but in theory it should flatten and used the cached version.Coth
Wow! +1 for the SKEffectNode::shouldRasterize !Testosterone

© 2022 - 2024 — McMap. All rights reserved.