Trying to make an isometric grid programmatically using Swift
Asked Answered
L

2

6

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.

Lantern answered 10/12, 2014 at 17:17 Comment(4)
you should create a new tile every time, then set its position and add it to the sceneAllegro
How do I create a new variable for each run of a for loop?Lantern
How would you do it outside of a for loop? The same way.Ninos
inside the for (var j=... loop: let tile=SKSpriteNode()/*do whatever setup here*/\*set the position*/Allegro
C
13

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

Cavetto answered 10/12, 2014 at 21:21 Comment(3)
This is fantastic! Worked great. First tutorial I came across that actually works AND makes me understand how the whole process is put together. Nicely done. One thing I'm still struggling with is how to use the building function correctly to get the staples on the board. If you have the time... :)Coastward
The buildingZPosition function returns a character's zPosition value so that it appears in the proper order relative to other characters on the grid. In the above image, the green block appears in front of the blue and brown blocks because it has a higher zPosition value than the other blocks.Cavetto
Got it! Thanks a lot! :)Coastward
E
7

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)
        }
    }
}
Effects answered 10/12, 2014 at 19:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.