Swift SceneKit物理学变得疯狂

时间:2016-01-29 13:05:53

标签: swift scenekit

我正在尝试制作这些" Cows"在某种程度上充当骰子,但无论出于何种原因,他们的物理开始变得疯狂。我一直试图解决这个问题大约10个小时而且不能理解。我正在关注另一个关于SceneKit和他的球的教程,他所做的并不是那样,所以我们使用的模型会出现问题吗?

以下是我的应用程序正在执行的操作的视频:

Youtube Video

这是我的视图控制器代码:

import UIKit
import SceneKit

class RootViewController: UIViewController, SCNSceneRendererDelegate, SCNPhysicsContactDelegate {

let BALL_RADIUS = CGFloat(15)

var _scene:SCNScene!
var _cameraNode:SCNNode!
var _cameraHandle:SCNNode!
var _cameraOrientation:SCNNode!
var _spotLightNode:SCNNode!
var _spotLightParentNode:SCNNode!
var _floorNode:SCNNode!
var _rollingBall:SCNNode!

var _cowNode:SCNNode!

var _ambientLightNode:SCNNode!

var _cameraHandleTranforms = [SCNMatrix4](count:10, repeatedValue:SCNMatrix4(m11: 0.0, m12: 0.0, m13: 0.0, m14: 0.0, m21: 0.0, m22: 0.0, m23: 0.0, m24: 0.0, m31: 0.0, m32: 0.0, m33: 0.0, m34: 0.0, m41: 0.0, m42: 0.0, m43: 0.0, m44: 0.0))


override func viewDidLoad() {
    super.viewDidLoad()
    setup()

}

@IBAction func dropCow(sender: UIButton) {
    setUpCows()
}
func setup() {
    let sceneView = view as! SCNView



    sceneView.backgroundColor = UIColor.blackColor()

    setupScene()


    sceneView.scene = _scene

//      sceneView.scene?.physicsWorld.speed = CGFloat(2.0)
//      
//      sceneView.scene?.physicsWorld.gravity = SCNVector3Make(0, -70, 0)

//      let bridge = PhysicsWorldBridge()
//      bridge.physicsWorldSpeed(sceneView.scene, withSpeed: 2.0)
//      bridge.physicsGravity(sceneView.scene, withGravity: SCNVector3Make(0, -70, 0))

    sceneView.delegate = self

    sceneView.jitteringEnabled = true

    sceneView.pointOfView = _cameraNode

    sceneView.showsStatistics = true
}


func setupScene() {
    _scene = SCNScene()
    setupEnviroment()
    setupInitial()
}

func setupEnviroment() {
    //create main camera
    _cameraNode = SCNNode()
    _cameraNode.position = SCNVector3Make(0, 0, 120)

    //create a node to manipulate the camera orientation
    _cameraHandle = SCNNode()
    _cameraHandle.position = SCNVector3Make(0, 60, 0)

    _cameraOrientation = SCNNode()

    _scene.rootNode.addChildNode(_cameraHandle)
    _cameraHandle.addChildNode(_cameraOrientation)
    _cameraOrientation.addChildNode(_cameraNode)

    _cameraNode.camera = SCNCamera()
    _cameraNode.camera!.zFar = 400

    if UIDevice.currentDevice().userInterfaceIdiom == UIUserInterfaceIdiom.Phone {
        _cameraNode.camera!.yFov = 55
    } else {
        _cameraNode.camera!.xFov = 75
    }

    _cameraHandleTranforms.insert(_cameraNode.transform, atIndex: 0)

    let position = SCNVector3Make(200, 0, 1000)

    _cameraNode.position = SCNVector3Make(200, -20, position.z+150)
    _cameraNode.eulerAngles = SCNVector3Make(CFloat(-M_PI_2)*0.06, 0, 0)

    //add an ambient light
    _ambientLightNode = SCNNode()
    _ambientLightNode.light = SCNLight()

    _ambientLightNode.light!.type = SCNLightTypeAmbient
    _ambientLightNode.light!.color = UIColor(white: 0.3, alpha: 1.0)
    _scene.rootNode.addChildNode(_ambientLightNode)

    //add a spot light to the scene
    _spotLightParentNode = SCNNode()
    _spotLightParentNode.position = SCNVector3Make(0, 90, 20)

    _spotLightNode = SCNNode()
    _spotLightNode.rotation = SCNVector4Make(1, 0, 0, CFloat(-M_PI_4))
    _spotLightNode.light = SCNLight()
    _spotLightNode.light!.type = SCNLightTypeSpot
    _spotLightNode.light!.color = UIColor(white: 1.0, alpha: 1.0)
    _spotLightNode.light!.castsShadow = true
    _spotLightNode.light!.shadowColor = UIColor(white: 0, alpha: 0.5)
    _spotLightNode.light!.zNear = 30
    _spotLightNode.light!.zFar = 800
    _spotLightNode.light!.shadowRadius = 1.0
    _spotLightNode.light!.spotInnerAngle = 15
    _spotLightNode.light!.spotOuterAngle = 70

    _cameraNode.addChildNode(_spotLightParentNode)

    print(_cameraNode.position)
    _spotLightParentNode.addChildNode(_spotLightNode)


    //floor
    let floor = SCNFloor()
    floor.reflectionFalloffEnd = 0
    floor.reflectivity = 0

    _floorNode = SCNNode()
    _floorNode.geometry = floor
    _floorNode.geometry!.firstMaterial!.diffuse.contents = "art.scnassets/textures/grass.jpg"
    _floorNode.geometry!.firstMaterial!.locksAmbientWithDiffuse = true
    _floorNode.geometry!.firstMaterial!.diffuse.wrapS = SCNWrapMode.Repeat
    _floorNode.geometry!.firstMaterial!.diffuse.wrapT = SCNWrapMode.Repeat
    _floorNode.geometry!.firstMaterial!.diffuse.mipFilter = SCNFilterMode.Linear

    _floorNode.physicsBody = SCNPhysicsBody(type: SCNPhysicsBodyType.Static, shape: nil)
    _floorNode.physicsBody!.restitution = 1.0

    _scene.rootNode.addChildNode(_floorNode)
}

func setUpCows() {
    let cow  = SCNScene(named: "art.scnassets/cow.scn")!

    _cowNode = cow.rootNode.childNodeWithName("scene", recursively: true)
    _cowNode?.scale = SCNVector3Make(20, 20, 20)

    //print(cowNode)

    let cowShape = SCNPhysicsShape(node: _cowNode!, options: nil)
    let cowBody = SCNPhysicsBody(type: .Dynamic, shape: cowShape)
    _cowNode?.physicsBody = cowBody

    _cowNode?.position = SCNVector3(200.0, 0.0, 200)

    let position = SCNVector3Make(200, 0, 1000)
    _cowNode.position = position
    _cowNode.position.y += CFloat(20)


    let gravityField = SCNPhysicsField.dragField()
    gravityField.strength = -1.0
    _cowNode.physicsBody!.restitution = 0.9
    _cowNode.physicsBody!.angularVelocity = SCNVector4(x: 5, y: 1, z: 1, w: 1)
    _cowNode?.physicsField = gravityField

    //print(cowNode)

    _scene.rootNode.addChildNode(_cowNode!)

}

func setupInitial() {
    //initial dark lighting
    _ambientLightNode.light!.color = UIColor.blackColor()
    _spotLightNode.light!.color = UIColor.blackColor()
    _spotLightNode.position = SCNVector3Make(50, 90, -50)
    _spotLightNode.eulerAngles = SCNVector3Make(CFloat(-M_PI_2)*0.75, CFloat(M_PI_4)*0.5, 0)

    setUpCows()

    SCNTransaction.begin()
    SCNTransaction.setAnimationDuration(1.0)
    SCNTransaction.setCompletionBlock() {
        SCNTransaction.begin()
        SCNTransaction.setAnimationDuration(2.5)
        self._spotLightNode.light!.color = UIColor(white: 1, alpha: 1)
        SCNTransaction.commit()
    }

    _spotLightNode.light!.color = UIColor(white: 0.001, alpha: 1)
    SCNTransaction.commit()

}

func handleTap() {
    SCNTransaction.begin()
    SCNTransaction.setAnimationDuration(1.0)

    SCNTransaction.setCompletionBlock() {
    print("done")
    }

    _cameraNode.position.z -= 100

    SCNTransaction.commit()
}


override func shouldAutorotate() -> Bool {
    return true
}

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
        return UIInterfaceOrientationMask.AllButUpsideDown
    } else {
        return UIInterfaceOrientationMask.All
    }
}


override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Release any cached data, images, etc that aren't in use.
}

}

对此有任何帮助将不胜感激

1 个答案:

答案 0 :(得分:2)

由于这种引力场,你的奶牛行为有点疯狂。

let gravityField = SCNPhysicsField.dragField()
gravityField.strength = -1.0
_cowNode.physicsBody!.restitution = 0.9
_cowNode.physicsBody!.angularVelocity = SCNVector4(x: 5, y: 1, z: 1, w: 1)
_cowNode?.physicsField = gravityField

如果您希望您的奶牛摔倒并弹跳骰子,您需要移除此gravityField并配置新的物理环境。

设定你的世界的引力:

sceneView.scene?.physicsWorld.gravity = SCNVector3Make(0, -400, 0)

将一些物理学应用于你的奶牛:

_cowNode.physicsBody!.friction = 0.3
_cowNode.physicsBody!.restitution = 0.7
_cowNode.physicsBody!.mass = 0.5
_cowNode.physicsBody!.angularVelocity = SCNVector4(x: 5, y: 1, z: 1, w: 1)

这是你的代码的工作样本(我用立方体替换了奶牛):

import UIKit
import SceneKit

class ViewController: UIViewController, SCNSceneRendererDelegate, SCNPhysicsContactDelegate {

    let BALL_RADIUS = CGFloat(15)

    var _scene:SCNScene!
    var _cameraNode:SCNNode!
    var _cameraHandle:SCNNode!
    var _cameraOrientation:SCNNode!
    var _spotLightNode:SCNNode!
    var _spotLightParentNode:SCNNode!
    var _floorNode:SCNNode!
    var _rollingBall:SCNNode!

    var _cowNode:SCNNode!

    var _ambientLightNode:SCNNode!

    var _cameraHandleTranforms = [SCNMatrix4](count:10, repeatedValue:SCNMatrix4(m11: 0.0, m12: 0.0, m13: 0.0, m14: 0.0, m21: 0.0, m22: 0.0, m23: 0.0, m24: 0.0, m31: 0.0, m32: 0.0, m33: 0.0, m34: 0.0, m41: 0.0, m42: 0.0, m43: 0.0, m44: 0.0))


    override func viewDidLoad() {
        super.viewDidLoad()
        setup()

    }

    @IBAction func dropCow(sender: UIButton) {
        setUpCows()
    }
    func setup() {
        let sceneView = view as! SCNView



        sceneView.backgroundColor = UIColor.blackColor()

        setupScene()


        sceneView.scene = _scene

        //sceneView.scene?.physicsWorld.speed = CGFloat(2.0)

        sceneView.scene?.physicsWorld.gravity = SCNVector3Make(0, -400, 0)

        //      let bridge = PhysicsWorldBridge()
        //      bridge.physicsWorldSpeed(sceneView.scene, withSpeed: 2.0)
        //      bridge.physicsGravity(sceneView.scene, withGravity: SCNVector3Make(0, -70, 0))

        sceneView.delegate = self

        sceneView.jitteringEnabled = true

        sceneView.pointOfView = _cameraNode

        sceneView.showsStatistics = true
    }


    func setupScene() {
        _scene = SCNScene()
        setupEnviroment()
        setupInitial()
    }

    func setupEnviroment() {
        //create main camera
        _cameraNode = SCNNode()
        _cameraNode.position = SCNVector3Make(0, 0, 120)

        //create a node to manipulate the camera orientation
        _cameraHandle = SCNNode()
        _cameraHandle.position = SCNVector3Make(0, 60, 0)

        _cameraOrientation = SCNNode()

        _scene.rootNode.addChildNode(_cameraHandle)
        _cameraHandle.addChildNode(_cameraOrientation)
        _cameraOrientation.addChildNode(_cameraNode)

        _cameraNode.camera = SCNCamera()
        _cameraNode.camera!.zFar = 400

        if UIDevice.currentDevice().userInterfaceIdiom == UIUserInterfaceIdiom.Phone {
            _cameraNode.camera!.yFov = 55
        } else {
            _cameraNode.camera!.xFov = 75
        }

        _cameraHandleTranforms.insert(_cameraNode.transform, atIndex: 0)

        let position = SCNVector3Make(200, 0, 1000)

        _cameraNode.position = SCNVector3Make(200, -20, position.z+150)
        _cameraNode.eulerAngles = SCNVector3Make(CFloat(-M_PI_2)*0.06, 0, 0)

        //add an ambient light
        _ambientLightNode = SCNNode()
        _ambientLightNode.light = SCNLight()

        _ambientLightNode.light!.type = SCNLightTypeAmbient
        _ambientLightNode.light!.color = UIColor(white: 0.3, alpha: 1.0)
        _scene.rootNode.addChildNode(_ambientLightNode)

        //add a spot light to the scene
        _spotLightParentNode = SCNNode()
        _spotLightParentNode.position = SCNVector3Make(0, 90, 20)

        _spotLightNode = SCNNode()
        _spotLightNode.rotation = SCNVector4Make(1, 0, 0, CFloat(-M_PI_4))
        _spotLightNode.light = SCNLight()
        _spotLightNode.light!.type = SCNLightTypeSpot
        _spotLightNode.light!.color = UIColor(white: 1.0, alpha: 1.0)
        _spotLightNode.light!.castsShadow = true
        _spotLightNode.light!.shadowColor = UIColor(white: 0, alpha: 0.5)
        _spotLightNode.light!.zNear = 30
        _spotLightNode.light!.zFar = 800
        _spotLightNode.light!.shadowRadius = 1.0
        _spotLightNode.light!.spotInnerAngle = 15
        _spotLightNode.light!.spotOuterAngle = 70

        _cameraNode.addChildNode(_spotLightParentNode)

        print(_cameraNode.position)
        _spotLightParentNode.addChildNode(_spotLightNode)


        //floor
        let floor = SCNFloor()
        floor.reflectionFalloffEnd = 0
        floor.reflectivity = 0

        _floorNode = SCNNode()
        _floorNode.geometry = floor
        _floorNode.geometry!.firstMaterial!.diffuse.contents = "art.scnassets/textures/grass.jpg"
        _floorNode.geometry!.firstMaterial!.locksAmbientWithDiffuse = true
        _floorNode.geometry!.firstMaterial!.diffuse.wrapS = SCNWrapMode.Repeat
        _floorNode.geometry!.firstMaterial!.diffuse.wrapT = SCNWrapMode.Repeat
        _floorNode.geometry!.firstMaterial!.diffuse.mipFilter = SCNFilterMode.Linear

        _floorNode.physicsBody = SCNPhysicsBody(type: SCNPhysicsBodyType.Static, shape: nil)
        _floorNode.physicsBody!.restitution = 1.0

        _scene.rootNode.addChildNode(_floorNode)
    }

    func setUpCows() {

        let box = SCNBox(width: 10, height: 10, length: 10, chamferRadius: 0.0)
        _cowNode = SCNNode(geometry: box)

        let cowShape = SCNPhysicsShape(node: _cowNode!, options: nil)
        let cowBody = SCNPhysicsBody(type: .Dynamic, shape: cowShape)
        _cowNode?.physicsBody = cowBody

        _cowNode?.position = SCNVector3(200.0, 0.0, 200)

        let position = SCNVector3Make(200, 40, 1000)
        _cowNode.position = position
        _cowNode.position.y += CFloat(20)

        _cowNode.physicsBody!.friction = 0.3
        _cowNode.physicsBody!.restitution = 0.7
        _cowNode.physicsBody!.mass = 0.5
        _cowNode.physicsBody!.angularVelocity = SCNVector4(x: 5, y: 1, z: 1, w: 1)

        //print(cowNode)

        _scene.rootNode.addChildNode(_cowNode!)

    }

    func setupInitial() {
        //initial dark lighting
        _ambientLightNode.light!.color = UIColor.blackColor()
        _spotLightNode.light!.color = UIColor.blackColor()
        _spotLightNode.position = SCNVector3Make(50, 90, -50)
        _spotLightNode.eulerAngles = SCNVector3Make(CFloat(-M_PI_2)*0.75, CFloat(M_PI_4)*0.5, 0)

        //setUpCows()

        SCNTransaction.begin()
        SCNTransaction.setAnimationDuration(1.0)
        SCNTransaction.setCompletionBlock() {
            SCNTransaction.begin()
            SCNTransaction.setAnimationDuration(2.5)
            self._spotLightNode.light!.color = UIColor(white: 1, alpha: 1)
            SCNTransaction.commit()
        }

        _spotLightNode.light!.color = UIColor(white: 0.001, alpha: 1)
        SCNTransaction.commit()

    }

    func handleTap() {
        SCNTransaction.begin()
        SCNTransaction.setAnimationDuration(1.0)

        SCNTransaction.setCompletionBlock() {
            print("done")
        }

        _cameraNode.position.z -= 100

        SCNTransaction.commit()
    }


    override func shouldAutorotate() -> Bool {
        return true
    }

    override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
        if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
            return UIInterfaceOrientationMask.AllButUpsideDown
        } else {
            return UIInterfaceOrientationMask.All
        }
    }

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        /* Called when a touch begins */
        setUpCows()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Release any cached data, images, etc that aren't in use.
    }

}