PhysicsBody 使用 SpriteKit 和 Swift 为零

Posted

技术标签:

【中文标题】PhysicsBody 使用 SpriteKit 和 Swift 为零【英文标题】:PhysicsBody is nil using SpriteKit with Swift 【发布时间】:2014-07-18 22:22:54 【问题描述】:

我正在构建一个 SpriteKit 游戏,我正在从多维数组加载一个关卡。 loadlevel 函数第一次工作。如果我在physicsBody 分配上方(在初始化physicBody 之后)执行physicsBodyprintln,它确实会失败。当我第二次运行负载级别时使用removeChildrenInArray 删除所有图块时,它会抛出一个错误,指出fatal error: unexpectedly found nil while unwrapping an Optional 并指向下方println 正下方的行。而println 表示physicsBody 就是nil。在我看来,新初始化的PhysicsBody 没有理由永远是nilprintln 打印 physicsBody nil。我不知道为什么physicsBody 会是nil。我只是想通过删除所有块节点并根据关卡地图在原始位置添加新节点来重置关卡。

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++
        
    

这是我的 ColliderType

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

这是我的reset函数内容:

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

这是我的 Level 结构

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]
        ]
    ]

如果这是 Swift 中的一个错误,我正在尝试找出解决方法,以便我可以完成这项工作。

【问题讨论】:

有什么理由先将 body 分配给 var 而不是直接分配给 tile.physicsBody? @LearnCocos2D 只是尝试解决这个错误。前几次我都按照你说的做。 其实,对于初学者来说,你不应该在 swift 中使用内置的物理引擎作为平台游戏。为每个图块制作物理实体过于密集,可能会导致故障。在这里阅读更多:learn-cocos2d.com/2013/08/… 其次,您的删除功能可以简化为 scene.removeAllChildren() 我尝试了您的代码,但无法重现该问题。您能否将其简化为仍然存在问题的较小示例?顺便说一句,像这样使用enum 是错误的,因为Wall == Block & Paddle 会与两者发生冲突。您可能想使用RawOptionSet 【参考方案1】:

看起来SKPhysicsBody 被实例化为空大小。尝试创建具有明确大小的物理体对象,如下所示:

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

或者,您可以直接在 SKSpriteNode 上设置大小,或使用其构造函数之一,该构造函数采用 CGSize 构造,例如 initWithTexture:color:size:

【讨论】:

以上是关于PhysicsBody 使用 SpriteKit 和 Swift 为零的主要内容,如果未能解决你的问题,请参考以下文章

Spritekit 碰撞检测无法正常工作

Spritekit - 将加速应用于物理主体

Spritekit 碰撞

Spritekit - 屏幕坐标的底部

SpriteKit:对象彼此下方

Swift Spritekit 应用旋转脉冲