Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trying to make an isometric grid programmatically using Swift

The only reason I'm attempting this programmatically is so I can access the locations of each tile, making it possible to manipulate the grid. I've looked at about 15 different tutorials using other programming languages, but even with that knowledge, I'm still having a very difficult time creating one in Swift.

I've tried creating a nested for loop but I'm not even sure if the code inside the loops make logical sense for creating an isometric grid, I just took it off of one of the tutorials I found:

func generateGrid() {
    for (var i = 0; i < 5; i++) {
        for (var j = 5; j >= 0; j--){
            tile.position = CGPoint(x: (j * Int(tile.size.height) / 2) + 
                                       (i * Int(tile.size.width) / 2), 
                                    y: (i * Int(tile.size.height) / 2) - 
                                       (j * Int(tile.size.width) / 2))
            addChild(tile)
        }
    }
}

Then I tried to call this in the "didMoveToView" function, but obviously you can't add the same node more than once.

Please give me any direction that you can.

like image 913
Ethan Scott Miller Avatar asked Dec 10 '14 17:12

Ethan Scott Miller


2 Answers

Here's an example of how to create an isometric grid in SpriteKit:

Define the grid settings

let tileHeight:CGFloat = 16.0
let tileWidth:CGFloat = 32.0
let numRows = 5
let numCols = 6

Create grid elements and add them to the scene at the appropriate locations

let size = CGSizeMake(tileWidth, tileHeight)
for row in 1...numRows {
    for col in 1...numCols {
        // Create a new tile object
        let tile = newTile(size)
        // Convert (col,row) to (x,y)
        tile.position = tilePosition(col, row: row)
        self.addChild(tile)
    }
}

This function converts a grid position to x and y scene coordinates. Use this to create the grid and to add buildings on the grid.

func tilePosition(col:Int, row:Int) -> CGPoint {
    let x = (CGFloat(row) * tileWidth  / 2.0) + (CGFloat(col) * tileWidth  / 2.0)
    let y = (CGFloat(col) * tileHeight / 2.0) - (CGFloat(row) * tileHeight / 2.0)
    return CGPointMake(x+100.0, y+100.0)
}

This function creates a new diamond-shaped SKShapeNode

func newTile(size:CGSize) -> SKShapeNode {
    let shape = SKShapeNode()
    let path = UIBezierPath()
    path.move(to: CGPoint(x:0, y:size.height / 2.0))
    path.addLine(to: CGPoint(x:size.width / 2.0, y:0))
    path.addLine(to: CGPoint(x:0, y:-size.height / 2.0))
    path.addLine(to: CGPoint(x:-size.width / 2.0, y:0))
    path.close()
    shape.path = path.cgPath
    shape.lineWidth = 1.0
    shape.fillColor = SKColor.gray
    return shape
}

This function determines the appropriate z position to ensure that buildings placed on the grid will be rendered in the correct order.

func buildingZPosition(col:Int, row:Int) -> CGFloat {
    return CGFloat(row*numCols + numCols-col)
}

Isometric grid with buildings

Figure 1. Isometric Grid Created with the Above Code

like image 196
0x141E Avatar answered Nov 15 '22 08:11

0x141E


To create an isometric grid like so

Isometric grid

one has to create a two loops. One of them iterates through rows and the other iterates through columns. Notice that the center of every other column is shifted up by half of the height of the tile and the same for every other row. To compensate for this we check if the row and column is even or odd and adjust it accordingly. A potential function would look something like this:

func generateGrid() {

    for i in 0..<5 {

        // Every other line needs to be shifted
        var offsetX = 0
        if i % 2 == 0 {
            offsetX = 0
        } else {
            offsetX = tile.size.width / 2.0
        }

        for j in 0..<5 {
            var tile = Tile()

            // Every other line needs to be shifted
            var offsetY = 0
            if i % 2 == 0 {
                offsetX = 0
            } else {
                offsetX = tile.size.height / 2.0
            }

            tile.position = CGPoint(x: (i * tile.size.width) - offsetX, y: (j * tile.size.height) - offsetY)
            addChild(tile)
        }
    }
}
like image 34
Ian Avatar answered Nov 15 '22 08:11

Ian