Search code examples
objective-csprite-kitretinatiledjstilemap

SpriteKit and JSTileMap


I am having difficulties to understand how JSTileMap works with SpriteKit and Tiled.

The problem is related to pixels and points, and also to loading apropriate tileset using JSTileMap based on screen scale factor.

File structure in project

In my project there are files which have following structure and this represents my low-res map (1024x768px with 32x32px tiles):

  • folder called SD
    • level-1.tmx
    • folder tmx-levels-sd.atlasc
      • tmx-levels-sd.1.png
      • tmx-levels-sd.plist

In this case when I load level-1.tmx on non-retina simulator everything is positioned properly. When I run the same configuration on retina simulator, again, everything is fine but tiles are scaled. Because of that quality suffers. So, how to load high-res tileset when needed?

The other solution

I also tried to solve this by using two versions of the map (low-res and high-res) for each level. That is actually what I was trying to avoid but still is acceptable:

For this situation I have files structured like this (map is 2048x1536 with 64x64px tiles):

  • folder called SD
    • level-1.tmx
    • folder tmx-levels-sd.atlasc
      • tmx-levels-sd.1.png
      • tmx-levels-sd.plist
  • folder called HD
    • level-1-hd.tmx
    • folder tmx-levels-hd.atlasc
      • tmx-levels-hd.1.png
      • tmx-levels-hd.plist

I guess that map with size 2048x1536 and doubled tilesize is appropriate for high-res version of my map? Also as you can see, there is no @2x tilesets at all in my project(I guess that we can't use @2x suffix with Tiled editor and JSTileMap?).

Problem with this configuration is that everything is altered(positions and tilesizes are doubled). JSTileMap probably works with points, Tiled with pixels, and above all that there is a known iPad simulator bug related to texture atlases which makes me difficult to understand what causing the problems with high-res map.

Can somebody clarify these things about using JSTileMap,SpriteKit and Tiled altogether ? Thanks!


Solution

  • I got your msg.

    Firstly you need both the @1x and @2x versions of the tiles (sprites). So if you have an atlas named myTiles you will need: myTiles.png & [email protected].

    I created my sprite sheet using texture packer. I added the @2x images and then on export I had it create a @1x version.

    In Tiled only use the @1x version so you would use myTiles.png

    If your map is 32x32 your @1x version will be 32x32 and your @2x version will be 64x64

    Forget the SD & HD folders and just use 1 folder called say Levels

    Inside here you need:

    level-1.tmx, tmx-levels-sd.1.png, [email protected]

    You can have sub folders under the main levels folder. Up to you, but you must have both the @1x version & @2x version of the png's and you can't just duplicate the @1x or @2x versions. The @1x version must be 32x32 based tiles and the @2x version must be double that (64x64). In the tmx file itself you don't load the @2x version as this will mess up your level.

    ** So your game will be on a 32x32 tileset. What sprite kit will do is double the pixels on retina displays so for this you need to have the @2x version available otherwise it will upscale your @1x version and the tiles will look big and pixelated. So try not to get confused with the whole pixels to points thing.

    Code Examples:

    GameViewController (Load scene):

    - (void)viewDidLoad
    {
    [super viewDidLoad];
    
    self.currentLevel = 1;
    
    // Configure the view.
    SKView * skView = (SKView *)self.view;
    skView.showsFPS = YES;
    skView.showsNodeCount = YES;
    
    /* Sprite Kit applies additional optimizations to improve rendering performance */
    skView.ignoresSiblingOrder = YES;
    
    // Create and configure the scene.
    LevelScene *scene = [[LevelScene alloc]initWithSize:skView.bounds.size level:self.currentLevel];
    scene.scaleMode = SKSceneScaleModeAspectFill;
    
    // Present the scene.
    [skView presentScene:scene];
    }
    

    LevelScene (Loads JSTileMap):

    #import "LevelScene.h"
    #import "SKTAudio.h"
    #import "JSTileMap"
    #import "Player.h"
    
    @interface LevelScene()
    
    @property (nonatomic, assign) NSUInteger currentLevel;
    @property (nonatomic, strong) SKNode *gameNode;
    @property (nonatomic, strong) JSTileMap *map;
    @property (nonatomic, strong) Player *player;
    @property (nonatomic, assign) NSTimeInterval previousUpdateTime;
    
    @implementation LevelScene
    
    -(id)initWithSize:(CGSize)size level:(NSUInteger)currentLevel {
    
    if ((self = [super initWithSize:size])) {
        self.currentLevel = currentLevel;
    self.gameNode = [SKNode node];
        [self addChild:self.gameNode];
    NSString *levelName = [levelDict objectForKey:@"level"];
        self.map = [JSTileMap mapNamed:levelName];
    
        [self.gameNode addChild:self.map];
    return self;
    }