how do you get collision detection on different materials within an scn node

房东的猫 提交于 2019-12-11 05:33:27

问题


I'm trying to get collision detection between different materials within an scn node. I have a cube with 6 different materials/ colors and balls coming at the cube. I'd like to detect same and different colored collisions but don't know how to apply different categories to each material.

import UIKit
import SceneKit

class GameViewController: UIViewController, SCNPhysicsContactDelegate {

Can I create categories to assign to different sides of the cube later?

let ballCategory = 0
let cubeCategory = 1
let ballGreen = 2
let ballRed = 3
let ballBlue = 4
let ballYellow = 5
let ballPurple = 6
let ballOrange = 7
let cubeGreen = 8
let cubeRed = 9
let cubeBlue = 10
let cubeYellow = 11
let cubePurple = 12
let cubeOrange = 13

setup stuff

var scnView: SCNView!
var scnScene = SCNScene()
var cameraNode: SCNNode!
var cubeNode = SCNNode()
var ball = SCNNode()

var randomColor: UIColor?

var timer = Timer()

override func viewDidLoad() {
    super.viewDidLoad()

    scnScene.physicsWorld.contactDelegate = self

    scnView = self.view as? SCNView

        view.scene = scnScene
        view.isPlaying = true

    }

    setupView()
    setupScene()
    setupCamera()
    spawnCube()

}

Will physics world did begin contact work?

func physicsWorld(world: SCNPhysicsWorld, didBegin contact: SCNPhysicsContact) {
            print("Physics called")

    if (contact.nodeA == cubeNode || contact.nodeA == ball) && (contact.nodeB == cubeNode || contact.nodeB == ball) {

        print("contact")

    }

    if (contact.nodeA.physicsBody!.categoryBitMask == 2 && contact.nodeB.physicsBody!.categoryBitMask == 8) || (contact.nodeB.physicsBody!.categoryBitMask == 2 && contact.nodeA.physicsBody!.categoryBitMask == 8)  {

        print("green contact")

    }

    if (contact.nodeA.physicsBody!.categoryBitMask == 3 && contact.nodeB.physicsBody!.categoryBitMask == 9) || (contact.nodeB.physicsBody!.categoryBitMask == 3 && contact.nodeA.physicsBody!.categoryBitMask == 9)  {

        print("green contact")

    }

    if (contact.nodeA.physicsBody!.categoryBitMask == 4 && contact.nodeB.physicsBody!.categoryBitMask == 10) || (contact.nodeB.physicsBody!.categoryBitMask == 4 && contact.nodeA.physicsBody!.categoryBitMask == 10)  {

        print("green contact")

    }

    if (contact.nodeA.physicsBody!.categoryBitMask == 5 && contact.nodeB.physicsBody!.categoryBitMask == 11) || (contact.nodeB.physicsBody!.categoryBitMask == 5 && contact.nodeA.physicsBody!.categoryBitMask == 11)  {

        print("green contact")

    }

    if (contact.nodeA.physicsBody!.categoryBitMask == 6 && contact.nodeB.physicsBody!.categoryBitMask == 12) || (contact.nodeB.physicsBody!.categoryBitMask == 6 && contact.nodeA.physicsBody!.categoryBitMask == 12)  {

        print("green contact")

    }

    if (contact.nodeA.physicsBody!.categoryBitMask == 7 && contact.nodeB.physicsBody!.categoryBitMask == 13) || (contact.nodeB.physicsBody!.categoryBitMask == 7 && contact.nodeA.physicsBody!.categoryBitMask == 13)  {

        print("green contact")

    }

}

func setupView() {
    scnView = self.view as! SCNView
    scnView.showsStatistics = false
    scnView.allowsCameraControl = false
    scnView.autoenablesDefaultLighting = true

}

func setupScene() {
    scnScene = SCNScene()
    scnView.scene = scnScene
    scnScene.background.contents = UIColor.black
}

func setupCamera() {

    cameraNode = SCNNode()

    cameraNode.camera = SCNCamera()
    cameraNode.position = SCNVector3(x: 0, y: 0, z: 10)
    scnScene.rootNode.addChildNode(cameraNode)

}

Cube setup, I'm getting an error when I try to add a category to the different sides/ materials

func spawnCube() {

    var geometry:SCNGeometry

    geometry = SCNBox(width: 1, height: 1, length: 1, chamferRadius: 0.05)

    cubeNode = SCNNode(geometry: geometry)

    let greenMaterial = SCNMaterial()
    greenMaterial.diffuse.contents = UIColor.green
    greenMaterial.locksAmbientWithDiffuse = true

    let redMaterial = SCNMaterial()
    redMaterial.diffuse.contents = UIColor.red
    redMaterial.locksAmbientWithDiffuse = true

    let blueMaterial  = SCNMaterial()
    blueMaterial.diffuse.contents = UIColor.blue
    blueMaterial.locksAmbientWithDiffuse = true

    let yellowMaterial = SCNMaterial()
    yellowMaterial.diffuse.contents = UIColor.yellow
    yellowMaterial.locksAmbientWithDiffuse = true

    let purpleMaterial = SCNMaterial()
    purpleMaterial.diffuse.contents = UIColor.purple
    purpleMaterial.locksAmbientWithDiffuse = true

    let orangeMaterial = SCNMaterial()
    orangeMaterial.diffuse.contents = UIColor.orange
    orangeMaterial.locksAmbientWithDiffuse   = true

    geometry.materials = [greenMaterial,  redMaterial,    blueMaterial,
                          yellowMaterial, purpleMaterial, orangeMaterial]

    cubeNode.physicsBody?.mass = 10000
    cubeNode.physicsBody?.restitution = 0
    cubeNode.physicsBody?.damping = 0
    cubeNode.physicsBody = SCNPhysicsBody.kinematic()
    cubeNode.physicsBody?.categoryBitMask = Int(cubeCategory)
    cubeNode.physicsBody?.contactTestBitMask = Int(ballCategory)
    cubeNode.physicsBody?.isAffectedByGravity = false

    cubeNode.position = SCNVector3(x: 0, y: 0, z: 0)

    scnScene.rootNode.addChildNode(cubeNode)
}

Ball setup, I'm also getting an error when I try to add a different category to different ball colors

func spawnBall() {

    var geometry:SCNGeometry

    geometry = SCNSphere(radius: 0.25)

    let ball = SCNNode(geometry: geometry)

    let randomNumberForColor = Int(arc4random_uniform(6))

    if randomNumberForColor == 1 {
        randomColor = UIColor.green
    }
    if randomNumberForColor == 2 {
        randomColor = UIColor.red
    }
    if randomNumberForColor == 3 {
        randomColor = UIColor.blue
    }
    if randomNumberForColor == 4 {
        randomColor = UIColor.yellow
    }
    if randomNumberForColor == 5 {
        randomColor = UIColor.purple
    }
    if randomNumberForColor == 6 {
        randomColor = UIColor.orange
    }
    if randomNumberForColor == nil {
        randomColor = UIColor.green
    }

    let greenMaterial = SCNMaterial()
    greenMaterial.diffuse.contents = randomColor
    greenMaterial.locksAmbientWithDiffuse = true;

    geometry.materials = [greenMaterial]

    ball.physicsBody?.mass = 0.00001
    ball.physicsBody?.restitution = 1
    ball.physicsBody?.damping = 0
    ball.physicsBody = SCNPhysicsBody.dynamic()
    ball.physicsBody?.categoryBitMask = Int(ballCategory)
    ball.physicsBody?.contactTestBitMask = Int(cubeCategory)
    ball.physicsBody?.isAffectedByGravity = false

    randomX()
    randomY()
    randomZ()

    ball.position = SCNVector3(x: Float(randomNumX!), y: Float(randomNumY!), z: Float(randomNumZ!))

    scnScene.rootNode.addChildNode(ball)

    let force = SCNVector3(x: Float(-randomNumX!)/2, y: Float(-randomNumY!)/2, z: Float(-randomNumZ!)/2)

    ball.physicsBody?.applyForce(force, at: cubeNode.position, asImpulse: true)

}

func randomX() {

    randomNumX = Int(arc4random_uniform(10)) - 5

}

func randomY() {

    randomNumY = Int(arc4random_uniform(20)) - 10

}

func randomZ() {

    randomNumZ = Int(arc4random_uniform(10)) - 5

}

}

Maybe there's a way to simplify this and just detect ball and cube collisions with a qualifier of matching color?

Thanks!


回答1:


The SCNBox class automatically creates SCNGeometryElementobjects as needed to handle the number of materials. In your case, you are adding 6 different materials to geometry.materials, so you automatically have 6 different GeometryElements, one for each side of the cube.

From the SCNPhysicsContact, you can get the contact point between the two physics bodies.

With that point, you can then do a Hit Test, which will give you an Array of Hit Test Result's. In this case the array will have 2 elements, meaning 2 Results, one for the cube and one for the ball.

Go through those 2 elements and determine which one is the cube (do that by getting the 'node' property of the result and see if the node's name is 'cube' or 'ball', of course you will need to set the name property of the nodes when you create them).

Now that you know which one is the result for the Cube, get the Geometry Index property of the Result. Use that index to get the color of the face which was collided by the ball.

The geometry elements will have the same order as the materials in your array of materials, so for example if you got Geometry Element index 0, that is the first material in your materials array, and so on.



来源:https://stackoverflow.com/questions/46188618/how-do-you-get-collision-detection-on-different-materials-within-an-scn-node

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!