【问题标题】:Detect collision between two objects in Swift在 Swift 中检测两个对象之间的碰撞
【发布时间】:2015-02-18 23:39:28
【问题描述】:

在 Swift 中碰撞检测非常简单 - 但在这个特定项目中,身体碰撞并没有像往常一样触发 didBeginContact 事件。

这是我的两具碰撞检查清单(使用士兵和子弹):

  1. SKPhysicsContactDelegate 添加到班级。
  2. 适当地设置physicsWorld,通常是:self.physicsWorld.contactDelegate = self
  3. 为您将拥有的每组节点创建类别。例如。 let bulletCategory = 0x1 << 0
  4. 为每个子弹和士兵创建 SKNode。
  5. 给每个子弹和士兵一个形状匹配的物理体。
  6. 将每个子弹的 categoryBitMask 设置为 bulletCategory(士兵设置为士兵类别)。
  7. 将每个子弹的contactBitMask设置为soldierCategory(士兵设置为bulletCategory)。
  8. 定义didBeginContact()处理程序。

以下是我的完整代码。这是一个最小的〜20行“Hello World”的碰撞。

如果您创建一个新的“游戏”并将其复制粘贴到 GameScene.swift 中,它将运行,只是不会触发任何碰撞事件。

import SpriteKit

class GameScene: SKScene, SKPhysicsContactDelegate {
    var soldier = SKShapeNode(circleOfRadius: 40)

    let soldierCategory:UInt32 = 0x1 << 0;
    let bulletCategory:UInt32 = 0x1 << 1;

    override func didMoveToView(view: SKView) {
        self.physicsWorld.contactDelegate = self

        // THE soldier
        soldier.fillColor = SKColor.redColor()
        soldier.position = CGPoint(x: CGRectGetMidX(self.frame), y: 40)
        soldier.physicsBody = SKPhysicsBody(circleOfRadius: 20)
        soldier.physicsBody!.dynamic = false
        soldier.physicsBody!.categoryBitMask = soldierCategory
        soldier.physicsBody!.contactTestBitMask = bulletCategory
        soldier.physicsBody!.collisionBitMask = 0


        // bulletS
        var timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("makeBullet"), userInfo: nil, repeats: true)

        self.addChild(soldier)
    }

    func makeBullet() {
        var bullet = SKShapeNode(rect: CGRect(x: CGRectGetMidX(self.frame), y: self.frame.height, width: 10, height: 40), cornerRadius: CGFloat(0))
        bullet.fillColor = SKColor.redColor()

        bullet.physicsBody = SKPhysicsBody(rectangleOfSize: CGSize(width: 10, height: 40))
        bullet.physicsBody?.dynamic = false
        bullet.physicsBody?.categoryBitMask = bulletCategory
        bullet.physicsBody?.contactTestBitMask = soldierCategory
        bullet.physicsBody?.collisionBitMask = soldierCategory

        var movebullet = SKAction.moveByX(0, y: CGFloat(-400), duration: 1)
        var movebulletForever = SKAction.repeatActionForever(movebullet)
        bullet.runAction(movebulletForever)

        self.addChild(bullet)
    }

    func didBeginContact(contact: SKPhysicsContact) {
        print("CONTACT")
    }

    override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
        /* Called when a touch begins */
    }

    override func update(currentTime: CFTimeInterval) {
        /* Called before each frame is rendered */
    }
}

【问题讨论】:

  • 等一下。如果physicsBody 不是“动态的”,它就不会与任何东西发生碰撞吗?

标签: ios swift sprite-kit collision-detection


【解决方案1】:

您的清单中缺少以下几项:

  1. 其中一个物理物体必须是动态的
  2. 物理体必须通过力/脉冲或通过设置它们的速度来移动
  3. 物理实体的位置应与其对应的精灵/形状节点匹配

对于 (2),您通过使用 SKAction 随时间改变其位置来移动每个子弹。

对于 (3),每个子弹的位置从 (0, 0) 开始,而形状绘制在场景的顶部中心。由于物理体以形状节点的位置为中心,形状和物理体的位置不匹配;子弹的物理体从不与士兵接触。要解决此问题,请尝试

    var bullet = SKShapeNode(rectOfSize: CGSizeMake(10, 40))
    bullet.position = CGPointMake(self.size.width/2.0, self.size.height)

此外,士兵的物理身体是其形状半径的一半。

【讨论】:

  • 这太棒了,谢谢。有没有办法可以调试或查看物理体的位置?我想看看它们的移动/设置方式与对象的不同,但我无法为它们着色。
  • didMoveToView 或您的视图控制器中设置view.showsPhysics = true
  • 两个物理体都需要是动态的吗?在另一个项目中,我克隆了FlappyBirdy,只有一个对象是动态的(鸟),而管道不是动态的,只是使用SKAction.moveByX()移动,仍然发生接触事件
  • 我建议您使用performSelector SKAction 来调用makeBullet 而不是使用NSTimer。当您暂停游戏(使用view.paused = true)时,动作会适当地暂停/恢复,并在您转换场景时自动删除。
  • 所以现在当一颗子弹撞到一个士兵时,它会推那个士兵。你知道如何让他们触发碰撞,但继续通过彼此吗?
猜你喜欢
  • 1970-01-01
  • 2016-02-17
  • 1970-01-01
  • 2013-03-19
  • 1970-01-01
  • 2018-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多