web-dev-qa-db-ja.com

SpriteKitでグリッドを描く

SpriteKit 2Dゲームエンジンを使用して このようなグリッド を描画するための最良の方法は何でしょうか?要件:

  • 列と行の数(5x5、10x3、3x4など)をプログラムで入力します。
  • このような正方形 の画像を使用するだけではあまり効率的ではないように思われるため、SKSpriteNodeSKShapeNodeなどを使用してプログラムで描画します。
  • 正方形のサイズは固定されている必要があります(それぞれが40x40であるとしましょう)。
  • グリッドは、ビューの垂直方向と水平方向の中央に配置する必要があります。

このグリッド内のさまざまな正方形を移動するプレーヤーとして、(画像からの)SKSpriteNodeを使用することを計画しています。
そこで、各正方形の中心点(x、y)を2次元配列に保存してから、プレーヤーの現在の位置からその位置に移動します。これについてももっと良い提案があれば、私はそれを聞きたいです。

Swift(できれば2.1))の解決策をいただければ幸いですが、Objective-Cでも同様です。これはiPhoneデバイスでのみ使用することを計画しています。
私の質問は近いです これに 。どんな助けでも大歓迎です。

18
Alex

Sprite Kitは1回の描画呼び出しでグリッドをレンダリングするため、グリッドをSKSpriteNodeのテクスチャとして実装することをお勧めします。これを行う方法の例を次に示します。

class Grid:SKSpriteNode {
    var rows:Int!
    var cols:Int!
    var blockSize:CGFloat!

    convenience init?(blockSize:CGFloat,rows:Int,cols:Int) {
        guard let texture = Grid.gridTexture(blockSize: blockSize,rows: rows, cols:cols) else {
            return nil
        }
        self.init(texture: texture, color:SKColor.clear, size: texture.size())
        self.blockSize = blockSize
        self.rows = rows
        self.cols = cols
    }

    class func gridTexture(blockSize:CGFloat,rows:Int,cols:Int) -> SKTexture? {
        // Add 1 to the height and width to ensure the borders are within the Sprite
        let size = CGSize(width: CGFloat(cols)*blockSize+1.0, height: CGFloat(rows)*blockSize+1.0)
        UIGraphicsBeginImageContext(size)

        guard let context = UIGraphicsGetCurrentContext() else {
            return nil
        }
        let bezierPath = UIBezierPath()
        let offset:CGFloat = 0.5
        // Draw vertical lines
        for i in 0...cols {
            let x = CGFloat(i)*blockSize + offset
            bezierPath.move(to: CGPoint(x: x, y: 0))
            bezierPath.addLine(to: CGPoint(x: x, y: size.height))
        }
        // Draw horizontal lines
        for i in 0...rows {
            let y = CGFloat(i)*blockSize + offset
            bezierPath.move(to: CGPoint(x: 0, y: y))
            bezierPath.addLine(to: CGPoint(x: size.width, y: y))
        }
        SKColor.white.setStroke()
        bezierPath.lineWidth = 1.0
        bezierPath.stroke()
        context.addPath(bezierPath.cgPath)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return SKTexture(image: image!)
    }

    func gridPosition(row:Int, col:Int) -> CGPoint {
        let offset = blockSize / 2.0 + 0.5
        let x = CGFloat(col) * blockSize - (blockSize * CGFloat(cols)) / 2.0 + offset
        let y = CGFloat(rows - row - 1) * blockSize - (blockSize * CGFloat(rows)) / 2.0 + offset
        return CGPoint(x:x, y:y)
    }
}

グリッドを作成してゲームピースをグリッドに追加する方法は次のとおりです

class GameScene: SKScene {
    override func didMove(to: SKView) {
        if let grid = Grid(blockSize: 40.0, rows:5, cols:5) {
            grid.position = CGPoint (x:frame.midX, y:frame.midY)
            addChild(grid)

            let gamePiece = SKSpriteNode(imageNamed: "Spaceship")
            gamePiece.setScale(0.0625)
            gamePiece.position = grid.gridPosition(row: 1, col: 0)
            grid.addChild(gamePiece)
        }
    }
}

更新:

どのグリッドの正方形がタッチされたかを判別するには、これをinitに追加します

self.isUserInteractionEnabled = true

そしてこれをGridクラスに:

override func touchesBegan(_ touches: Set<UITouch>, withEvent event: UIEvent?) {
    for touch in touches {
        let position = touch.location(in:self)
        let node = atPoint(position)
        if node != self {
            let action = SKAction.rotate(by:CGFloat.pi*2, duration: 1)
            node.run(action)
        }
        else {
            let x = size.width / 2 + position.x
            let y = size.height / 2 - position.y
            let row = Int(floor(x / blockSize))
            let col = Int(floor(y / blockSize))
            print("\(row) \(col)")
        }
    }
}
30
0x141E