旋转后努力沿着轴移动节点(Swift | ARKit | SceneKit)

时间:2017-07-20 05:06:53

标签: ios swift 3d scenekit arkit

正如标题所述,在我旋转我的船舶节点之后,我想要“go”按钮使船舶在旋转后沿着它现在面向的方向行进。目前,按下“go”按钮会使船继续沿着世界的z轴移动,而不是船舶朝向的方向(显然因为我没有任何代码,否则告诉它)。

我尝试过使用worldTransformconvertPosition:toNode:但目前没有运气。

在ViewController中:

let ship = SpaceShip();
    let SHIP_SPEED: Float = 3.00;
    let scene = SCNScene();


    var timer = Timer();

    var upPressed = false;
    var rightPressed = false;
    var downPressed = false;
    var leftPressed = false;
    var goPressed = false;
    var stopPressed = false;
    var firePressed = false;

    //initial angles for rotating ship
    //if ship is flipping upside down, it is because of these
   /* var xAngle: SCNMatrix4?
    var yAngle: SCNMatrix4?
    var zAngle: SCNMatrix4? */

    @IBOutlet weak var sceneView: ARSCNView!

    @IBAction func upBtnDown(_ sender: Any) {
        upPressed = true;
    }
    @IBAction func upBtnUp(_ sender: Any) {
        upPressed = false;
        ship.rotateShip(ship.getNode(), x: 180, y: 0, z: 180);
    }

    @IBAction func rightBtnDown(_ sender: Any) {
        rightPressed = true;

    }

    @IBAction func rightBtnUp(_ sender: Any) {
        rightPressed = false;
        ship.rotateShip(ship.getNode(), x: 180, y: 0, z: 180);
    }

    @IBAction func downBtnDown(_ sender: Any) {
        downPressed = true;
    }

    @IBAction func downBtnUp(_ sender: Any) {
        downPressed = false;
        ship.rotateShip(ship.getNode(), x: 180, y: 0, z: 180);
    }

    @IBAction func leftBtnDown(_ sender: Any) {
        leftPressed = true;

    }

    @IBAction func leftBtnUp(_ sender: Any) {
        leftPressed = false;
        //ship.rotateShip(ship.getNode(), x: 180, y: 0, z: 180);
    }

    @IBAction func goBtnDown(_ sender: Any) {

        goPressed = true;
    }

    @IBAction func goBtnUp(_ sender: Any) {
        goPressed = false;
    }

    @IBAction func stopBtnDown(_ sender: Any) {
        stopPressed = true;
    }

    @IBAction func stopBtnUp(_ sender: Any) {
        stopPressed = false;
    }


    @IBAction func fireBtnDown(_ sender: Any) {
        firePressed = true;
    }

    @IBAction func fireBtnUp(_ sender: Any) {
        firePressed = false;
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        //set scene from storyboard to scene variable
        sceneView.scene = scene;
        sceneView.scene.physicsWorld.contactDelegate = self;
        sceneView.delegate = self;

    }

    override func viewWillAppear(_ animated: Bool) {

        super.viewWillAppear(animated);

        let configuration = ARWorldTrackingSessionConfiguration();

        sceneView.session.run(configuration);

        addShip();

    }

    func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {

        ship.physicsBody?.velocity = SCNVector3(0,0,0);

        if(upPressed == true) {
            ship.physicsBody?.velocity.y = SHIP_SPEED;
            ship.rotateShip(ship.getNode(), x: 170, y: 0, z: 180);
        } else if (rightPressed == true) {
            ship.physicsBody?.velocity.x = SHIP_SPEED;
            ship.rotateShip(ship.getNode(), x: 180, y: 0, z: 170);
        } else if (downPressed == true) {
            ship.physicsBody?.velocity.y = -SHIP_SPEED;
            ship.rotateShip(ship.getNode(), x: 190, y: 0, z: 180);
        } else if (leftPressed == true) {
            //ship.physicsBody?.velocity.x = -SHIP_SPEED;
           ship.rotateShip(ship.getNode(), x: 180, y: 15, z: 190);
            print(ship.getNode().rotation);

        } else if (goPressed == true) {
            ship.physicsBody?.velocity.z = -SHIP_SPEED;
        } else if (stopPressed == true) {
            ship.physicsBody?.velocity.z = SHIP_SPEED;
        }

    }

    func getZForwards(node: SCNNode) -> SCNVector3{
        return SCNVector3(node.worldTransform.m31, node.worldTransform.m32, node.worldTransform.m33);
    }

    func addShip() {
        ship.loadModel();

        ship.position = SCNVector3(0, 0, -2);

        sceneView.scene.rootNode.addChildNode(ship);
    }

    func degToRad(deg: Float) -> Float{
        return deg / 180 * Float(M_PI)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

在SpaceShip()中:

class SpaceShip: SCNNode {

    var node = SCNNode();

    func loadModel() {
        guard let virtualObjectScene = SCNScene(named: "art.scnassets/ship.scn") else {return};

        let wrapperNode = SCNNode();

        for child in virtualObjectScene.rootNode.childNodes {
            wrapperNode.addChildNode(child);
        }

        node = wrapperNode.childNodes[0];
        let shape = SCNPhysicsShape(node: node, options: nil);
        self.physicsBody = SCNPhysicsBody(type: .dynamic, shape: shape);
        self.physicsBody?.isAffectedByGravity = false;

        rotateShip(node, x: 180, y: 0, z: 180);

        self.addChildNode(wrapperNode);
    }

    func getNode() -> SCNNode {
        return node;
    }

    func rotateShip(_ node: SCNNode, x: Float, y: Float, z: Float){
        //original angles
        let xAngle = SCNMatrix4MakeRotation(degToRad(deg: x), 1, 0, 0);
        let yAngle = SCNMatrix4MakeRotation(degToRad(deg: y), 0, 1, 0);
        let zAngle = SCNMatrix4MakeRotation(degToRad(deg: z), 0, 0, 1);


        let rotationMatrix = SCNMatrix4Mult(SCNMatrix4Mult(xAngle, yAngle), zAngle);

        node.pivot = SCNMatrix4Mult(rotationMatrix, node.transform);
    }

    func degToRad(deg: Float) -> Float{
        return deg / 180 * Float(M_PI)
    }

}

谢谢

1 个答案:

答案 0 :(得分:0)

transfomPosition无效,因为它会转换某个位置,但您不希望这样,您想要转换方向。这也是SCNVector3,但完全不同,因为您只需要应用旋转,而不是翻译

使用transformVector或直接使用worldFront,这是iOS 11中的新功能。