SKTiled Framework

repository·master·Indexed 42 days ago

https://github.com/mfessenden/sktiled

A Swift framework for integrating Tiled assets with Apple's SpriteKit. It supports TMX file loading via SKTilemap.load, various map projections, all layer types (tile, object, image, and group), custom properties, and animated tiles. The framework provides utilities for coordinate conversion between SpriteKit and Tiled, debug drawing options, and the ability to map Tiled custom types to specific Swift classes via the SKTilemapDelegate protocol.

Tokens
22.4K
Snippets
81
Records
97
Agent score
53%

What's inside SKTiled

  1. Overview of SKTiled

    master
    SKTiled is a Swift framework designed to enable the use of Tiled assets within Apple's SpriteKit engine. It provides specialized frameworks for macOS, iOS, and tvOS, allowing developers to bridge tile-based map data from the Tiled editor into SpriteKit scenes.
  2. How the 'type' property works in SKTiled

    master

    The SKTiledObject protocol includes a type property. This allows you to assign a type to any object in your scene, including tilesets, all layer types, and the map itself.

    If an object in Tiled has a built-in type property, that value is assigned. If the object does not have a built-in type but has a custom string property named type, that custom value will be used instead.

  3. Understand the SKTiled class hierarchy

    master

    SKTiled is built on top of Apple's SpriteKit framework. Most SKTiled components inherit from standard SpriteKit nodes like SKNode, SKEffectNode, or SKSpriteNode. Understanding this hierarchy helps you determine how to add SKTiled objects to your scene and how they interact with the SpriteKit rendering tree.

    Core Hierarchy Overview

    • Scenes: SKTiledScene inherits from SKScene (which is an SKEffectNode).
    • Tilemaps: SKTilemap inherits from SKEffectNode.
    • Layers: SKTiledLayerObject inherits from SKEffectNode. Specific layer types include:
      • SKTileLayer
      • SKObjectGroup
      • SKImageLayer
      • SKGroupLayer
    • Tiles: SKTile inherits from SKSpriteNode.
    • Objects: SKTileObject inherits from SKShapeNode.
    • Cameras: SKTiledSceneCamera inherits from SKCameraNode.
  4. Use Tile and Text objects from Tiled

    master

    SKTiled supports specialized object types from Tiled:

    1. Tile Objects: Objects assigned a tile ID. They render the associated tile within the object's bounds, including support for animated textures.
    2. Text Objects: Objects assigned text properties. They automatically render text within the shape's bounds. You can create dynamic labels by updating the SKTileObject.text attribute or any font attributes, which triggers an automatic redraw.
  5. How layers work in SKTiled

    master

    Layers in SKTiled are containers for different data types and are all subclasses of SKTiledLayerObject. This base class provides coordinate transformation and positioning information.

    Supported layer types include:

    • Tile layers: Hold an array of tile sprites and tileset data.
    • Object groups: Contain vector shape objects.
    • Image layers: Display a single image.
    • Group layers: Encapsulate other layers.

    You can query layers by their specific type, by their name, or by their index.

    // query layers by type
    let tileLayers = tilemap.tileLayers
    let objectGroups = tilemap.objectGroups
    let imageLayers = tilemap.imageLayers
    let groupLayers = tilemap.groupLayers
    
    // query named layers
    let groundLayers = tilemap.getLayers(named: "Ground") as! [SKTileLayer]
    let objectGroups = tilemap.getLayers(named: "Objects") as! [SKObjectGroup]
    let hudLayers = tilemap.getLayers(named: "HUD") as! [SKImageLayer]
    
    // query layer at a specific index
    if let firstLayer = tilemap.getLayer(atIndex: 1) as! SKTileLayer {
        firstLayer.visible = true
    }
  6. Avoid protocol implementation issues when subclassing SKTilemapDelegate

    master

    In Swift, if a base class conforms to a protocol with default implementations (like SKTilemapDelegate), subclassing that base class to override protocol methods may fail because Swift may favor the default protocol implementation over your subclass's override.

    To ensure your custom logic is called, you have two options:

    1. Implement the protocol on the base class: Ensure the base class provides the necessary implementation so that overrides in the subclass are recognized.
    2. Use a secondary method pattern: Implement the protocol method in the base class, which then calls a separate, non-protocol method. You can then override that secondary method in your subclass.

    It is generally recommended to implement protocols directly on your objects rather than relying on subclassing classes that already conform to them.

    // Recommended pattern: Use a secondary method to bypass protocol implementation issues
    class BaseScene: SKScene, SKTilemapDelegate {
        func didRenderMap(_ tilemap: SKTilemap) {
            // call a secondary method that can be overridden
            setupTilemap(tilemap)
        }
    
        func setupTilemap(_ tilemap: SKTilemap) {
            print("BaseScene: setting up tilemap: \"\(tilemap.name!)\"")
        }
    }
    
    class LevelScene: BaseScene {
        override func setupTilemap(_ tilemap: SKTilemap) {
            print("LevelScene: setting up tilemap: \"\(tilemap.name!)\"")
        }
    }
  7. Identify SKTiled protocols and delegates

    master

    SKTiled uses several protocols to define object capabilities and delegate patterns for scene and tilemap management.

    SKTiledObject Protocol

    Objects conforming to SKTiledObject include:

    • SKTileset
    • SKTilesetData
    • SKTiledLayerObject
    • SKTilemap

    Delegate Protocols

    • SKTiledSceneDelegate: Used by SKTiledScene to handle scene-specific events.
    • SKTilemapDelegate: Used by SKTiledScene to handle tilemap-specific events.
    • SKTiledSceneCameraDelegate: Used by both SKTiledScene and SKTilemap to handle camera-related events.
    • XMLParserDelegate: Used by SKTilemapParser for parsing tilemap data.
  8. How the Tiled Scene architecture works

    master

    A standard Tiled scene setup typically involves an SKTiledSceneDelegate which manages the relationship between a camera, a world container, and the tilemap.

    In this model:

    1. World Node: A container node (usually at 0,0) that parents all Tiled assets.
    2. Tilemap: The loaded SKTilemap is parented to the world node.
    3. Camera: An SKTiledSceneCamera interacts with the world node to allow navigation via mouse or touch events.

    By conforming to SKTiledSceneDelegate, you can implement a template for how maps are loaded and how the camera behaves.

    public protocol SKTiledSceneDelegate: class {
        var worldNode: SKNode! { get set }
        var cameraNode: SKTiledSceneCamera? { get set }
        var tilemap: SKTilemap? { get set }
        func load(tmxFile: String) -> SKTilemap?
    }
  9. Enable Effects and Shaders on Tilemaps

    master

    Since SKTilemap and SKTiledLayerObject are subclasses of SKEffectNode, you can apply Core Image effects, shaders, and distortions.

    To use shaders, you must set shouldEnableEffects = true.

    Warning: Enabling effects consumes more CPU/GPU. Additionally, SKEffectNode uses a buffer with a maximum texture size of 2048x2048. If your map exceeds these dimensions, it will appear cropped. Enabling effects also softens the edges of nearest-neighbor textures, which may affect the look of retro-style games.

    // 1. Enable effects
    tilemap.shouldEnableEffects = true
    
    // 2. Load and configure shader
    let shader = SKShader(fileNamed: "waves")
    shader.attributes = [SKAttribute(name: "a_map_size", type: .vectorFloat2)]
    tilemap.shader = shader
    
    // 3. Pass data to shader
    tilemap.setValue(SKAttributeValue(vectorFloat2: tilemap.sizeInPoints.toVec2), forAttribute: "a_map_size")