Can I create SpriteKit texture atlas in runtime

612 views Asked by At

I'm developing an os x / iOS crossword game which uses SKLabelNode to display the crossword letters as a child on a SKNode subclass.

So for each letter there is SKNode.SKLabelNode. Without using SKLabelNode the draw counts are in the range of 6-8. With using SKLabelNode they go up to the amount of children in the scene which can be almost 100.

I am now looking for a way to avoid that and came up with the idea to rasterize the SKLabelNode to a texture but this does not lower the draw counts since there are still lots of different textures.

My Idea is now to rasterize these SKNode-Subclasses and to put the textures into a texture atlas.

So question is, is it possible to create a texture atlas in runtime? What to do if a single texture changes? Is it possible to exchange a single texture in the atlas or so I have to rebuild it?

And maybe there is a "best way" to handle lot's of different SKLabelNodes!?

2

There are 2 answers

6
Whirlwind On BEST ANSWER

I would go with a letter class which is subclass of SKSpriteNode and an atlas called letters. That way, you will draw all letters in single draw pass(100 draw passes are unnecessary in this situation). Or you don't even have to make a subclass of SKSpriteNode...You can just do this :

 SKSpriteNode *letterSprite = [SKSpriteNode spriteNodeWithTexture:[atlas textureNamed:[NSString stringWithFormat:@"%@",character]]];

The limitation of this approach is that letters would have pre-determined size. I doubt that you would need different sized letters in your crossword game. If you need to change size of letters you can still scale them, but I guess some quality loss will theoretically occur because of scaling bitmaps. I say theoretically because in most cases the quality loss is not noticeable.

Here is an example of my TextNode which parses given string (numbers in my case) and create sprites which are drawn in single pass (instead of using SKLabelNode for every single number). Images in atlases should be named like [email protected], [email protected], or if using numbers [email protected], [email protected] etc.

static const float kCharacterDistance = 6.0f;

#import "TextNode.h"

@interface TextNode()


@property (nonatomic,strong) NSMutableArray* characters;

@end

@implementation TextNode

-(instancetype)initWithPosition:(CGPoint)position andText:(NSString*)text{

    if(self =[super init]){

        self.characters = [[NSMutableArray alloc] initWithCapacity:[text length]];

        SKTextureAtlas *atlas = [SKTextureAtlas atlasNamed:@"numbers"];



        for(NSUInteger i =0; i < [text length];i++){

            NSString *character = [text substringWithRange:NSMakeRange(i, 1)];

            SKSpriteNode *characterSprite = [SKSpriteNode spriteNodeWithTexture:[atlas textureNamed:[NSString stringWithFormat:@"%@",character]]];
            characterSprite.color = [SKColor yellowColor];
            characterSprite.colorBlendFactor = 1.0f;
            characterSprite.position = CGPointMake(i*kCharacterDistance,0);

            [self.characters addObject:characterSprite];

            [self addChild:characterSprite];
        }
   self.position = position;
    }

    return self;
}

@end

Hope this helps and will give you the basic idea of how to draw all letters in single draw pass. And note how I colorize letters. In texture atlas images are white, but I colorize them easily to desired color.

1
sangony On

As long as your FPS is good, don't worry about anything else. Also, remember that Xcode auto creates texture atlases at runtime so it's not something you have to do yourself.

You can set skView.ignoresSiblingOrder = YES; to improve your performance a bit.