【问题标题】:Draw a grid with SpriteKit使用 SpriteKit 绘制网格
【发布时间】:2016-02-01 14:05:25
【问题描述】:

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

  • 以编程方式输入列数和行数(5x5、10x3、3x4 等)。
  • 使用SKSpriteNodeSKShapeNode 之类的东西以编程方式绘制它,因为我觉得仅使用square like this 的图像效率不高。
  • 方格应具有固定大小(假设每个方格为 40x40)。
  • 网格应在视图中垂直和水平居中。

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

我很欣赏 Swift 中的解决方案(最好是 2.1),但 Objective-C 也可以。计划仅在 iPhone 设备上使用此功能。
我的问题很接近to this one。任何帮助表示赞赏。

【问题讨论】:

  • 为什么不用 CGContext (Quartz) 来画线呢?看看 CGPaths。您唯一需要注意的是确保坐标重合。毕竟精灵就是精灵……
  • 网格是否需要在孔屏幕上,因为您应该只划分屏幕的长度,然后扔出您想要的网格长度。
  • 回答你的问题,不,网格不需要在整个屏幕上。
  • 嗨,迈克尔 L!谢谢你的建议。我不知道如何以有效的方式使用这些 CGPath,但 0x141E 的答案完美地做到了。

标签: ios swift sprite-kit


【解决方案1】:

我建议您将网格实现为 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)")
        }
    }
}

【讨论】:

  • 非常感谢这个解决方案,@0x141E!这正是我一直在寻找的。你如何让SpriteKit 在一次绘制中渲染网格真的很酷。额外感谢gridPosition 功能,它比我想象的要好。
  • 如何区分网格中的每个框?假设我将 skspritenodes 添加为 Grid 类的子项,我将如何为网格中的每个框使用 touches started?
  • 将 touchesBegan 添加到 Grid 类不起作用。您需要将它添加到添加到网格的节点实例中。我怀疑这是因为您将网格中的框添加为整个网格精灵的子项。因此,我们需要为每个盒子在不同的类中继承SKSpriteNode,并在那里覆盖touchesBegan。这对我有用。我很难理解这一点。谢谢你的回答。
  • @Boggartfly 查看touchesBegan 方法的更新。
猜你喜欢
  • 2011-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-31
  • 2021-07-11
  • 2016-02-06
  • 2011-08-05
相关资源
最近更新 更多