Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PhysicsBody is nil using SpriteKit with Swift

I have a SpriteKit game I am building and I am loading a level from a multidimensional array. The loadlevel function works the first time. It does fail if I do a println of the physicsBody above the physicsBody assignment (after the initialization of the physicBody). When I remove all the tiles with removeChildrenInArray the secondtime I run load level it throws an error saying fatal error: unexpectedly found nil while unwrapping an Optional and it points to line right below the println below. And the println indicates that it is the physicsBody that is nil. In my mind there is no reason a freshly initialize PhysicsBody should ever be nil. The println prints physicsBody nil. I have no idea why the physicsBody would be nil. I am just trying to reset the level by removing all block nodes and adding new ones in the original place according to the level map.

func loadLevel() {
    var levels = Levels().data
    var frameSize = view.frame.size
    var thisLevel = levels[currentLevel]
    println("running load level")
    for (rowIndex,row) in enumerate(thisLevel) {
        for (colIndex,col) in enumerate(row) {
            if col == 4 {
                continue
            }
            println("COL: \(col)")
            var tile = SKSpriteNode(texture: SKTexture(imageNamed: "brick_\(tileMap[col])"))
            tile.name = "tile_\(rowIndex)_\(colIndex)"
            tile.position.y = frameSize.height - (tile.size.height * CGFloat(rowIndex)) - (tile.size.height/2)
            tile.position.x = tile.size.width  * CGFloat(colIndex) + (tile.size.width/2)
            var physicsBody = SKPhysicsBody(rectangleOfSize: tile.size)
            tile.physicsBody = physicsBody
            tile.physicsBody.affectedByGravity = false
            tile.physicsBody.categoryBitMask = ColliderType.Block.toRaw()
            tile.physicsBody.contactTestBitMask = ColliderType.Ball.toRaw()
            tile.physicsBody.collisionBitMask = ColliderType.Ball.toRaw()
            scene.addChild(tile)
            tileCount++
        }
    }
}

Here is my ColliderType

enum ColliderType:UInt32 {
    case Paddle = 1
    case Block = 2
    case Wall = 3
    case Ball = 4
}

This is my reset function contents:

func reset() {
    tileCount = 0
    var removeTiles = [SKSpriteNode]()
    // remove all the tiles
    for child in scene.children {
        var a_tile = child as SKSpriteNode
        if a_tile.name.hasPrefix("tile_") {
            a_tile.removeFromParent()
            a_tile.name = ""
            removeTiles.append(a_tile)
        }
    }
    removeTiles.removeAll(keepCapacity: false)
    ball!.position = CGPoint(x: 200, y: 200)
    ballVel = CGPoint(x: 0, y: -5)
    currentLevel++
    loadLevel()
    lost = false
    won = false
}

Here is my Level structs

struct Tile {
    let map = ["blue","green","purple","red"]
}

struct Levels {
    let data = [
        [
            [4,4,0,4,0,4,0,4,0,4,0,4,0,0,4,4],
            [4,4,1,4,1,4,1,4,1,4,1,4,1,1,4,4],
            [4,4,2,4,2,4,2,4,2,4,2,4,2,2,4,4],
            [4,4,3,4,3,4,3,4,3,4,3,4,3,3,4,4]
        ],
        [
            [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
            [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
            [2,2,2,2,2,2,2,4,2,2,2,2,2,2,2,2],
            [3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]
        ]
    ]
}

If this is a bug in Swift I am trying to figure out a way around so I can just make this work.

like image 654
Johnston Avatar asked Jul 18 '14 22:07

Johnston


1 Answers

Looks like SKPhysicsBody is instantiated with an empty size. Try to create the physics body object with an explicit size, like so:

var physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(100, 100))

Alternatively, you can set the size directly on the SKSpriteNode or use one of its constructors that take a CGSize construct like initWithTexture:color:size:

like image 58
jverrijt Avatar answered Oct 04 '22 16:10

jverrijt