swift - 将类别、碰撞和接触位掩码分配给代码中的引用节点

标签 swift xcode collision-detection scenekit

我有一个基于关卡的游戏,因此我使用 Xcode 场景编辑器创建关卡,但在检测对象之间的碰撞时遇到了问题,这些对象是在单独的场景中创建并作为引用节点拖入游戏场景的。

似乎如果我尝试创建一个对象的物理体,它在我创建它的 .scn 文件中用作引用节点,那么该物理体不会被游戏场景中的节点引用,但是直接在场景编辑器中创建的属性是。

如果我尝试通过代码设置实际上是引用节点的每个节点的物理体,它确实设置了它(物理体不是零),但未检测到碰撞。

这是我设置物理体的代码:

    // player (I want to be notified when player collides with any walls)
    playerNode = level1Scene.rootNode.childNodeWithName("playerNode", recursively: true)!
    playerNode.physicsBody = SCNPhysicsBody(type: .Dynamic, shape: nil)
    playerNode.physicsBody?.affectedByGravity = false
    playerNode.physicsBody?.categoryBitMask = PhysicsCategory.Player.rawValue
    playerNode.physicsBody?.collisionBitMask = PhysicsCategory.Wall.rawValue
    playerNode.physicsBody?.contactTestBitMask = PhysicsCategory.Wall.rawValue

    //wall from separate .scn file
    let wallScene = SCNScene(named: "wallObject.scn")
    let wall = wallScene!.rootNode.childNodeWithName("wall", recursively: true)!
    wall.physicsBody = SCNPhysicsBody(type: .Kinematic, shape: nil)
    wall.physicsBody?.categoryBitMask = PhysicsCategory.Wall.rawValue
    wall.physicsBody?.collisionBitMask = PhysicsCategory.Player.rawValue
    wall.physicsBody?.contactTestBitMask = PhysicsCategory.Player.rawValue

    // walls that are reference nodes of the wall and are located in game scene 
    let wall2 = level1Scene.rootNode.childNodeWithName("wallObject reference", recursively: true)!
    wall2.physicsBody = SCNPhysicsBody(type: .Kinematic, shape: nil)
    wall2.physicsBody?.categoryBitMask = PhysicsCategory.Wall.rawValue
    wall2.physicsBody?.collisionBitMask = PhysicsCategory.Player.rawValue
    wall2.physicsBody?.contactTestBitMask = PhysicsCategory.Player.rawValue
    print(wall2.physicsBody!) // prints <SCNPhysicsBody: 0x7fe5f9dc75a0>

我不会因任何接触而与我联系,玩家也不会在接触时与任何墙壁发生物理碰撞。我已使类符合 SCNPhysicsContactDelegate 协议(protocol):

extension GameViewController: SCNPhysicsContactDelegate {
    func physicsWorld(world: SCNPhysicsWorld, didBeginContact contact: SCNPhysicsContact) {
        playerNode.physicsBody?.velocity = SCNVector3Zero
        print("player and wall collided")
    }
}

并将联系人委托(delegate)设置为我的游戏场景:

level1Scene.physicsWorld.contactDelegate = self

这两天我一直在努力让它工作,但没有成功。当我使用 Sprite Kit 时,我几乎总能找到与我的问题相关的帖子,甚至在发布我的问题时,我也会得到答案。但是我猜 Scene Kit 并不流行,我找不到任何东西。

如果您确实知道我错在哪里或如何在代码中检测到碰撞,请告诉我。

最佳答案

我根据您发布的代码粗略地拼凑了一个示例,唯一的“问题”是它有效,因为成功调用了联系人委托(delegate)。本例中的玩家几何体是 SceneKit 宇宙飞船,而 wall2 是一个添加到另一个场景中的 SCNBox,然后从 Finder 拖到飞船场景中。我已经包括了重力,所以船刚好落在墙上。

对象是否相互反弹,只是您的联系人委托(delegate)未被调用?或者物体是否相互穿过。我还想知道您是如何移动播放器对象来引起接触的?

import UIKit
import QuartzCore
import SceneKit

let colors = [UIColor.redColor(), UIColor.brownColor(), UIColor.cyanColor(), UIColor.greenColor(), UIColor.yellowColor(), UIColor.blueColor()]

enum PhysicsCategory:Int {
    case Player = 2
    case Wall = 4
}

extension GameViewController: SCNPhysicsContactDelegate {

    func physicsWorld(world: SCNPhysicsWorld, didBeginContact contact: SCNPhysicsContact) {
        playerNode.geometry?.firstMaterial?.diffuse.contents = colors[Int(arc4random_uniform(UInt32(colors.count)))]
        print("player and wall collided")
    }
}

class GameViewController: UIViewController {

    var playerNode:SCNNode!

    override func viewDidLoad() {
        super.viewDidLoad()

        // create a new scene
        //let scene = SCNScene()
        let scene = SCNScene(named: "art.scnassets/ship.scn")!

        //playerNode = SCNNode(geometry: SCNBox(width: 1, height: 1, length: 1, chamferRadius: 0))
        playerNode = scene.rootNode.childNodeWithName("ship", recursively: true)!
        playerNode.geometry?.firstMaterial?.diffuse.contents = UIColor.redColor()
        playerNode.physicsBody = SCNPhysicsBody(type: .Dynamic, shape: nil)
        playerNode.physicsBody?.affectedByGravity = true
        playerNode.physicsBody?.categoryBitMask = PhysicsCategory.Player.rawValue
        playerNode.physicsBody?.collisionBitMask = PhysicsCategory.Wall.rawValue
        playerNode.physicsBody?.contactTestBitMask = PhysicsCategory.Wall.rawValue

        initPlayer()
        //scene.rootNode.addChildNode(playerNode)

        //let wall = SCNNode(geometry: SCNBox(width: 20, height: 0.25, length: 20, chamferRadius: 0))
        let wallScene = SCNScene(named: "art.scnassets/wallObject.scn")
        let wall = wallScene!.rootNode.childNodeWithName("wall", recursively: true)!
        wall.physicsBody = SCNPhysicsBody(type: .Kinematic, shape: nil)
        wall.physicsBody?.categoryBitMask = PhysicsCategory.Wall.rawValue
        wall.physicsBody?.collisionBitMask = PhysicsCategory.Player.rawValue
        wall.physicsBody?.contactTestBitMask = PhysicsCategory.Player.rawValue
        //scene.rootNode.addChildNode(wall)

        let wall2 = scene.rootNode.childNodeWithName("wallObject reference", recursively: true)!
        wall2.physicsBody = SCNPhysicsBody(type: .Kinematic, shape: nil)
        wall2.physicsBody?.categoryBitMask = PhysicsCategory.Wall.rawValue
        wall2.physicsBody?.collisionBitMask = PhysicsCategory.Player.rawValue
        wall2.physicsBody?.contactTestBitMask = PhysicsCategory.Player.rawValue


        scene.physicsWorld.contactDelegate = self

        // retrieve the SCNView
        let scnView = self.view as! SCNView
        scnView.playing = true
        scnView.scene = scene
        scnView.allowsCameraControl = true
        scnView.autoenablesDefaultLighting = true
        scnView.showsStatistics = true
        scnView.backgroundColor = UIColor.lightGrayColor()

        // add a tap gesture recognizer
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
        scnView.addGestureRecognizer(tapGesture)
    }

    func handleTap(gestureRecognize: UIGestureRecognizer) {
        initPlayer()
    }

    func initPlayer() {
        playerNode.position = SCNVector3Make(0, 12, 0)
        playerNode.eulerAngles = SCNVector3Make(Float(drand48() * M_PI/2), Float(drand48() * M_PI/2), Float(drand48() * M_PI/2))
        playerNode.physicsBody?.velocity = SCNVector3Zero
        playerNode.physicsBody?.angularVelocity = SCNVector4Zero
    }
}

关于swift - 将类别、碰撞和接触位掩码分配给代码中的引用节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38737364/

相关文章:

iOS SDK 检测应用程序是否已更新或新安装

c++ - Xcode 6 : Set Preprocessor Macros per architecture

ios - 未显示 Xcode 目标图标

swift - 如何检测快速移动的分数节点

collision-detection - 如何处理同时发生的碰撞,以便处理顺序无关紧要?

IOS navigationBar 不在屏幕边缘

ios - Health Kit 读取权限状态

swift - 使用带有未知字典键的 Swift 4 Codable 协议(protocol)

ios - 代码 8 : Auto layout Leading & Trailing

python - 碰撞检测程序在 Turtle 中不起作用