2016-08-03 36 views
1

Ich habe ein levelbasiertes Spiel, daher verwende ich den Xcode Scene Editor zur Erstellung von Levels, habe aber Probleme beim Erkennen von Kollisionen zwischen Objekten, die in separaten Szenen erstellt wurden und zog Spielszenen als Referenzknoten hinein.Zuweisen von Kategorien, Kollisionen und Kontakt-Bitmasken zu Referenzknoten im Code

Wenn ich versuche, den Physikkörper eines Objekts zu erstellen, das als Referenzknoten in dieser .scn-Datei verwendet wird, in der ich es erstellt habe, wird dieser Physikkörper nicht auf Knoten in der Spielszene verwiesen. Die Eigenschaften, die direkt im Szeneneditor erstellt wurden, sind.

Wenn ich versuche, den Physikkörper jedes Knotens, der eigentlich ein Referenzknoten ist, über den Code zu setzen, wird er gesetzt (der Physikkörper ist nicht Null), aber die Kollision wird nicht erkannt.

Dies ist der Code, wo ich die Physik Gremien:

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

Ich bin nicht über irgendwelche Kontakte kontaktiert, noch hat der Spieler mit jeder Wand physisch auf Kontakt kollidieren. Ich habe die Klasse das SCNPhysicsContactDelegate Protokoll angepasst:

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

und stellen Sie den Kontakt Delegaten meine Spielszene:

level1Scene.physicsWorld.contactDelegate = self 

Ich habe versucht, dies jetzt für zwei Tage zur Arbeit zu kommen, ohne Erfolg. Als ich mit Sprite Kit arbeitete, konnte ich fast immer relevante Beiträge zu meinem Problem finden und selbst wenn ich meine Frage posten würde, würde ich eine Antwort bekommen. Aber Scene Kit ist nicht so populär, denke ich und ich kann nichts finden.

Wenn Sie wissen, wo ich falsch liege oder wie die Kollision im Code erkannt werden könnte, bitte sagen Sie mir.

Antwort

1

Ich habe ein Beispiel losgelöst, das auf dem Code basiert, den Sie gepostet haben. Das einzige "Problem" ist, dass es funktioniert, indem der Kontaktdelegat erfolgreich aufgerufen wird. Die Player-Geometrie ist in diesem Fall das SceneKit-Raumschiff und die Wand 2 ist eine SCN-Box, die in die andere Szene eingefügt und dann aus dem Finder in die Schiffsszene gezogen wird. Ich habe die Schwerkraft eingeschlossen, also fällt das Schiff einfach auf die Wand.

Würden die Objekte sich gegenseitig abprallen, und nur Ihr Kontaktdelegat wird nicht aufgerufen? Oder gehen die Objekte durcheinander? Ich frage mich auch, wie Sie das Spielerobjekt verschieben, um den Kontakt zu verursachen?

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

Ich dachte, was das Problem war. Ich habe viele Wand Referenz Knoten und sie alle haben den gleichen Namen, also habe ich Physik Körper auf nur einer von ihnen eingestellt und der Rest wurde ohne es verlassen. Ich löste das Problem, indem ich alle untergeordneten Knoten aufzählte und diese Eigenschaften auf solche mit diesem Namen einstellte, aber ich war skeptisch, ob dies ein guter Weg ist. Ich habe 200 Wände, also wenn ich die Schleife führe, wo ich den Physikkörper für jeden von ihnen einstelle, wird das Gleiche 200 Mal wiederholt. Wäre es besser, wenn ich den Physikkörper der Wand direkt auf die Wand in der Datei setze, von der aus er referenziert wird? – Larisa

+0

Ich kann nicht sehen, wie es die Leistung in irgendeiner Weise beeinträchtigt. Ich würde es eher als eine Frage der Bequemlichkeit sehen. Wenn Sie diese Parameter in der Quell-SCN-Datei festlegen, bedeutet dies, dass alle Wände die gleichen Eigenschaften haben, während die Einrichtung in Code Ihnen eine gewisse Flexibilität bietet. Vielleicht möchten Sie, dass einige Wände mehr Sprungkraft haben als andere oder zu einer anderen Kollisionskategorie gehören ... Dennoch wäre es sinnvoll, einige physikalische Standardeigenschaften einzubeziehen. – lock