はじめに
前回の続きです。
今回はステージを作っていきます。
素材準備
背景(ちょっと適切なサイズがわからない。。。)
床ブロック
実装
今回も SKScene の実装のみです。今回は全部コードで実装してますが SpriteKit Scene などのファイルを追加すれば GUI でも操作可能です。
背景表示
背景を表示します。
final class GameScene: SKScene {
    override func didMove(to view: SKView) {
        let backNode = SKSpriteNode(imageNamed: "background")
        backNode.size = frame.size
        backNode.position = .init(x: frame.midX, y: frame.midY)
        addChild(backNode)
    }
}
こんな感じです。
床表示
SKTileMapNode を使って床を作ります。
final class GameScene: SKScene {
    private let tilePositions: [(column: Int, row: Int)] = [
        (0, 0), (0, 1),
        (1, 0), (1, 1),
        (2, 0), (2, 1),
        (3, 0), (3, 1),
        (4, 0), (4, 1),
        (5, 0), (5, 1),
        (6, 0), (6, 1), (6, 2),
        (7, 0), (7, 1), (7, 2), (7, 3),
        (8, 0), (8, 1),
        (9, 0), (9, 1),
        (10, 0), (10, 1),
        (11, 0), (11, 1),
        (12, 0), (12, 1),
        (13, 0), (13, 1),
        (14, 0), (14, 1),
        (15, 0), (15, 1),
        (16, 0), (16, 1),
        (17, 0), (17, 1),
        (18, 0), (18, 1),
        (19, 0), (19, 1),
        (20, 0), (20, 1),
        (21, 0), (21, 1),
        (22, 0), (22, 1),
        (23, 0), (23, 1),
        (24, 0), (24, 1),
        (25, 0), (25, 1),
        (26, 0), (26, 1),
        (27, 0), (27, 1),
        (28, 0), (28, 1),
        (29, 0), (29, 1),
        (30, 0), (30, 1),
        (31, 0), (31, 1),
        (32, 0), (32, 1),
        (33, 0), (33, 1),
        (34, 0), (34, 1),
        (35, 0), (35, 1),
        (36, 0), (36, 1),
        (37, 0), (37, 1),
        (38, 0), (38, 1),
        (39, 0), (39, 1),
        (40, 0), (40, 1),
        (41, 0), (41, 1),
        (42, 0), (42, 1),
        (43, 0), (43, 1),
        (44, 0), (44, 1),
        (45, 0), (45, 1),
        (46, 0), (46, 1),
        (47, 0), (47, 1),
        (48, 0), (48, 1),
        (49, 0), (49, 1),
    ]
    override func didMove(to view: SKView) {
        let tileSize = CGSize(width: 32, height: 32)
        let group = SKTileGroup(tileDefinition: .init(texture: .init(imageNamed: "tile_block"), size: tileSize))
        let tileSet = SKTileSet(tileGroups: [group])
        let tileMap = SKTileMapNode(tileSet: tileSet, columns: tilePositions.last!.column + 1, rows: 4, tileSize: tileSize)
        tilePositions.forEach {
            tileMap.setTileGroup(group, forColumn: $0.column, row: $0.row)
        }
        tileMap.position = .zero
        tileMap.anchorPoint = .zero
        addChild(tileMap)
        // physicsBody設定
        tilePositions.forEach {
            let node = SKSpriteNode()
            node.position = .init(x: CGFloat($0.column) * tileSize.width + tileSize.width/2,
                                  y: CGFloat($0.row) * tileSize.height + tileSize.height/2)
            node.physicsBody = .init(rectangleOf: tileSize)
            node.physicsBody?.isDynamic = false
            tileMap.addChild(node)
        }
    }
}
こんな感じです。
ちょっと解説。tilePositions がタイルの位置を表していて(0, 0)が左下のタイルになります。下記で設定する columns と rows は横と縦の最大値になります。今回は横に 50, 縦に(最大で)4 並べるのでその数値をそれぞれ設定しています。
let tileMap = SKTileMapNode(tileSet: tileSet, columns: tilePositions.last!.column + 1, rows: 4, tileSize: tileSize)
下記の設定は床を画面の左下起点に置きたかったのでそれぞれ .zero を設定しています。
tileMap.position = .zero
tileMap.anchorPoint = .zero
下記の処理は SKTileMapNode にいい感じに physicsBody を設定する方法がない(たぶん)のでタイル1つ1つに physicsBody 設定しています。
tilePositions.forEach {
    let node = SKSpriteNode()
    node.position = .init(x: CGFloat($0.column) * tileSize.width + tileSize.width/2,
                          y: CGFloat($0.row) * tileSize.height + tileSize.height/2)
    node.physicsBody = .init(rectangleOf: tileSize)
    node.physicsBody?.isDynamic = false
    tileMap.addChild(node)
}
おわりに
前回のと合わせるとこんな感じになります。
偶然にもどこかでみたことのあるようなステージになってしまいました![]()
次回は横スクロールできるようにします!
SpriteKit あまりさわったことないのでもっといい方法あればぜひ教えて下さい![]()


