我有一个基于关卡的游戏,所以我使用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
协议:
extension GameViewController: SCNPhysicsContactDelegate {
func physicsWorld(world: SCNPhysicsWorld, didBeginContact contact: SCNPhysicsContact) {
playerNode.physicsBody?.velocity = SCNVector3Zero
print("player and wall collided")
}
}
并将联系人代表设置为我的游戏场景:
level1Scene.physicsWorld.contactDelegate = self
两天来,我一直在努力让它发挥作用,但没有成功。当我使用Sprite Kit时,我几乎总能找到关于我的问题的相关帖子,即使在发布我的问题时,我也会得到答案。但我想场景工具包并没有那么受欢迎,我什么都找不到。
如果你知道我错在哪里,或者如何在代码中检测到冲突,请告诉我。
我粗略地根据您发布的代码拼凑了一个示例,唯一的"问题"是它有效,因为成功地调用了联系人委托。在这种情况下,玩家的几何体是SceneKit宇宙飞船,wall2是添加到另一个场景中的SCNBox,然后从Finder拖动到飞船场景中。我已经计算了重力,所以船刚好掉到墙上。
对象是否会相互反弹,只是没有调用您的联系人代理?或者这些物体互相穿过。我还想知道你是如何移动玩家对象来引起接触的?
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
}
}