2015-11-01 92 views
9

通过使用SpriteKit 2D游戏引擎绘制grid like this的最佳方式是什么? 要求:用SpriteKit绘制网格

  • 以编程方式输入列数和行数(5x5,10x3,3x4等)。
  • 使用类似SKSpriteNodeSKShapeNode的程序来绘制它,因为只使用square like this的图像对我来说似乎不是很有效。
  • 广场应该有一个固定的大小(假设每个是40x40)。
  • 网格应该在视图中垂直和水平居中。

我打算使用SKSpriteNode(来自图片)作为在此网格中以不同方格移动的玩家。
因此,我将在2维数组中保存每个方块的中心点(x,y),然后从玩家的当前位置移动到该位置。如果您也有更好的建议,我想听听。

我很感谢Swift(最好是2.1)的解决方案,但Objective-C也会这样做。规划仅在iPhone设备上使用此功能。
我的问题是关闭to this one。任何帮助表示赞赏。

+0

为什么不使用CGContext(Quartz)来画线?看看CGPaths。唯一需要注意的是确保坐标共同引入。毕竟,精灵是精灵... – 2015-11-01 17:27:38

+0

嘿,迈克尔L!感谢您的建议。我不知道如何以有效的方式使用这些CGPath,但0x141E的答案完美无缺。 – Alex

+0

网格是否需要在屏幕上显示,因为您应该将屏幕的长度分成所需的网格长度。 – Cing

回答

19

我建议你将网格实现为SKSpriteNode的纹理,因为Sprite Kit将在一次绘制调用中呈现网格。这里有一个如何做一个例子:

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)") 
     } 
    } 
} 
+1

真的很感谢解决方案,@ 0x141E!这正是我所期待的。真的很酷你如何让'SpriteKit'在单个绘制中呈现网格。另外感谢'gridPosition'函数,它比我想的要好。 – Alex

+0

你会如何区分网格中的每个框?假设我将skspritenodes添加为Grid类的子元素,那么我将如何使用网格中的每个元素开始触摸? – Boggartfly

+0

添加touchesBegin到'Grid'类不起作用。您需要将其添加到添加到网格的节点实例中。我怀疑这是因为您要将网格中的框添加为整个网格精灵的子节点。因此,我们需要在每个盒子的不同类中继承“SKSpriteNode”,并在其上覆盖“touchesBegan”。这对我来说很有用。我觉得这很困难。感谢您的回答。 – Boggartfly