SKPhysicsBody碰撞不起作用

6
以下是我的“Floor.swift”类,它基本上是一堵墙。我有物体从屏幕顶部过来,一旦 Floor 和 SKSpriteNodes 碰撞,我希望移除 SKSpriteNode。以下是我的 Floor 类。
import Foundation
import SpriteKit

class Floor: SKNode {
    override init() {
        super.init()

        let leftWall = SKSpriteNode(color: UIColor.clear, size: CGSize(width: 5, height: 50))
        leftWall.position = CGPoint(x: 0, y: 50)
        leftWall.physicsBody = SKPhysicsBody(rectangleOf: leftWall.size)
        leftWall.physicsBody!.isDynamic = false
        self.addChild(leftWall)

        let rightWall = SKSpriteNode(color: UIColor.clear, size: CGSize(width: 5, height: 50))
        rightWall.position = CGPoint(x: 375, y: 50)
        rightWall.physicsBody = SKPhysicsBody(rectangleOf: rightWall.size)
        rightWall.physicsBody!.isDynamic = false
        self.addChild(rightWall)

        let bottomWall = SKSpriteNode(color: UIColor.clear, size: CGSize(width: 500, height: 10))
        bottomWall.position = CGPoint(x: 150, y: -5)
        bottomWall.physicsBody = SKPhysicsBody(rectangleOf: bottomWall.size)
        bottomWall.physicsBody!.isDynamic = false
        self.addChild(bottomWall)

        self.physicsBody = SKPhysicsBody(bodies: [leftWall.physicsBody!, rightWall.physicsBody!, bottomWall.physicsBody!])

        self.physicsBody?.categoryBitMask = floorCategory
        self.physicsBody?.contactTestBitMask = nailDropCategory | pointCategory | lifeCategory
        self.physicsBody?.collisionBitMask = balloonCategory
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemted")
    }
}

"func didBegin(_ contact: SKPhysicsContact)"中的GameScene类:

func didBegin(_ contact: SKPhysicsContact) {        
        if (contact.bodyA.categoryBitMask == nailDropCategory | pointCategory | lifeCategory) && (contact.bodyB.categoryBitMask == floorCategory) {
           // contact.bodyB.node!.removeFromParent()
            print("COLLISION")
        }
}

如您所见,在我的Floor类中,我将对象设置为“self.physicsBody = SKPhysicsBody(bodies :)”,并与所有的SKSpriteNode一起使用。但由于某种原因,我没有得到任何检测结果。我使我的“Floor”类成为了每个对象类别、点类别和生命类别的“contactTestBitMask”。这是我一直卡住的问题,有什么想法吗?
更新:
所以现在我正在使用下面的代码,它可以工作!唯一的问题是,默认情况下会删除我的“balloonCategory”,我不想让它这样做。如何让它忽略只有那个类别,但也像一个墙壁一样对气球起作用?
func didBegin(_ contact: SKPhysicsContact) {
        let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask

        switch contactMask {
        case balloonCategory | nailDropCategory:
            print("nailDrop and balloon have contacted.")
            contact.bodyB.node!.removeFromParent()
            self.run(SKAction.playSoundFileNamed("lostlifesound.mp3", waitForCompletion:false))
            lifeLost -= 1
        case balloonCategory | pointCategory:
            print("point and balloon have contacted.")
            contact.bodyB.node!.removeFromParent()
            totalPoints += 2
            self.run(SKAction.playSoundFileNamed("pointsound.mp3", waitForCompletion:false))
        case balloonCategory | lifeCategory:
            print("life and balloon have contacted.")
            contact.bodyB.node!.removeFromParent()
            lifeLost += 1
            self.run(SKAction.playSoundFileNamed("pointsound.mp3", waitForCompletion:false))
        default:            
            contact.bodyB.node!.removeFromParent()
            print("Removed \(String(describing: contact.bodyB.node!.name))")
        }
    }

nailDropCategory?pointCategory?lifeCategory?除了你自己,没有人知道你如何定义位掩码。 - El Tomato
好吧,我在所有其他类中都定义了它,所有其他的碰撞都有效,所以我就迷失了,哈哈 - Dewan
1
如果物理引擎已经在您的项目中工作,那么似乎这应该可以解决。您能否在示例项目中重现此问题并在Github上分享?看起来解决方案可能来自调试。 - peacetype
@peacetype 请看一下我的代码更新。我现在正在使用switch方法。在default:部分,它会删除所有其他节点,这很完美,但我不想删除我的balloonCategory,但我也不想在它与我的floorCategory碰撞时删除balloonCategory。我只想让它像墙一样对待。我该怎么做? - Dewan
@Dewan。您不能总是删除nodeB对象,因为您不知道哪个对象是nodeA,哪个是nodeB,但有一种简单的方法可以解决这个问题。您能告诉我要为每个联系人删除哪些节点吗? - Steve Ives
@Dewan 当你说你想让默认情况下的案例作为气球的墙壁时,你到底是什么意思?如果你只想让墙壁停止气球,但当它们接触时不发生其他任何事情,那么你需要确保碰撞检测设置正确,并且在 didBegin(contact:) 中你不必做任何事情。 - Steve Ives
2个回答

5

听起来你会受益于给所有的对象类型分配名称,像这样:

class Balloon: SKSpriteNode {
    init() {
        super.init(texture: nil, color: .blue, size: CGSize(width: 50, height: 50))
        self.name = "balloon"
    }
}

现在当您在开关中进行检查时,您可以在决定删除对象之前验证其身份。请参见我对以下开关语句中默认情况所做的更改。这样,如果它是气球,则该节点将不会被删除。物理碰撞将继续工作。
func didBegin(_ contact: SKPhysicsContact) {
    let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask

    switch contactMask {
    case balloonCategory | nailDropCategory:
        print("nailDrop and balloon have contacted.")
        contact.bodyB.node!.removeFromParent()
        self.run(SKAction.playSoundFileNamed("lostlifesound.mp3", waitForCompletion:false))
        lifeLost -= 1
    case balloonCategory | pointCategory:
        print("point and balloon have contacted.")
        contact.bodyB.node!.removeFromParent()
        totalPoints += 2
        self.run(SKAction.playSoundFileNamed("pointsound.mp3", waitForCompletion:false))
    case balloonCategory | lifeCategory:
        print("life and balloon have contacted.")
        contact.bodyB.node!.removeFromParent()
        lifeLost += 1
        self.run(SKAction.playSoundFileNamed("pointsound.mp3", waitForCompletion:false))
    default:
        if contact.bodyB.node!.name == "balloon" {
            print("Balloon collided but we will not remove it.")
            return
        } else {
            contact.bodyB.node!.removeFromParent()
            print("Removed \(String(describing: contact.bodyB.node!.name))")
    }
}

兄弟,我非常感激你的帮助!你是我的福音,希望你有一个美好的新年!再次感谢你! - Dewan
1
祝你好运,祝你的游戏顺利! - peacetype
1
谢谢!最后一个问题,你个人最喜欢的iOS广告网络是什么? - Dewan
1
抱歉,我无法回答这个问题,因为我从未使用过它们。我相信设计应该有针对性和直接的盈利模式(付费应用程序、应用内购买或免费增值模式)。话虽如此,如果你能制作一款深受休闲玩家欢迎的游戏,你可能可以选择任何顶级广告网络来赚钱。只需在谷歌上搜索“iOS顶级广告网络”,看看你会得到什么 :) - peacetype
你是个真正的好人,祝你获得许多祝福。我现在就去做,一切顺利! - Dewan
@Dewan - 如果你不想让气球碰到墙壁时发生任何事情,那么只需关闭这些对象之间的接触检测,而不是在didBegin中编写代码来忽略接触。这样你的游戏将运行更快,并且代码量也会减少。 - Steve Ives

1
你无法保证nodeB是地板,而nodeA是否真的是nailDropCategory | pointCategory | lifeCategory
我假设、和是你想要在任何一个对象接触到时收到通知的三个对象,因此尝试按照以下方式构建:
  func didBegin(_ contact: SKPhysicsContact) {
     print("didBeginContact entered for \(String(describing: contact.bodyA.node!.name)) and \(String(describing: contact.bodyB.node!.name))")

     let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask

     switch contactMask {
     case nailDropCategory | FloorCategory:
        print("nailDrop and floor have contacted.")
     case pointCategory | FloorCategory:
        print("point and floor have contacted.")
     case lifeCategory | FloorCategory:
        print("life and floor have contacted.")
     default:
        print("Undetected collision occurred")
     }
 }

你是否已经创建了一个来自你的Floor类的对象?


它说:“didBeginContact为nil和nil输入”,并在开关中返回“default:”。此外,执行“self.physicsBody = SKPhysicsBody(bodies:[leftWall.physicsBody!,rightWall.physicsBody!,bottomWall.physicsBody!])”会重叠我现有的physicsBody并引起一些问题。不太确定发生了什么,因为之前可以正常工作,所以我完全迷失了。 - Dewan
所以我们知道有东西发生了碰撞 - 确保场景中的每个节点都有一个名称,然后你就会知道发生了什么。当你说self,physicsBody...覆盖了现有的物理体时,我不确定你的意思,因为根据你的代码,Floor对象没有现有的物理体。 - Steve Ives
SKPhysicsBody数组包含所有物体,同时还有这行代码“bottomWall.physicsBody = SKPhysicsBody(rectangleOf:bottomWall.size)”,我也对leftWall和rightWall做了同样的操作。我实际上创建了双重物理体,它们重叠在一起,所以现在我不确定发生了什么。这很让人感到压力。 - Dewan
看看我的代码更新。如果你能帮我解决这个问题,那么我会把你的答案标记为我的问题的答案,因为你帮我解决了这个问题。 - Dewan
@Dewan 你似乎已经得到了答案,但是如果没有要忽略联系(比如您的气球和墙壁)的代码,请确保这些联系从未发生。也就是说,如果你不想在气球碰到墙壁时做任何事情,就不要设置它们的contactTestBitMasks,这样当它们接触时didBegin就不会被调用。 - Steve Ives

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接