SceneKit physics add velocity in local space

2019-05-25 09:13发布

问题:

I am trying to manipulate the player node using physicsBody.velocity by adding or subtracting velocity to the axis for different directions. The problem is that I'm having trouble finding the method for applying that to local space or at least applying the velocity in relation to the direction the object is facing. In other words, it works fine if I have not rotated the object's node. If I do it will still add the velocity to the unrotated space. I know there is a way to add velocity to the current SCNVector3, but I cannot figure it out.

if isZThrustPositive {
        if let velocity = self.physicsBody?.velocity {
            if velocity.z * 100 <= 8000 {
                thrustDirection = SCNVector3(
                    x: velocity.x,
                    y: velocity.y,
                    z: velocity.z + kPlayerShipMainThrust)
                self.physicsBody?.velocity = thrustDirection
            }
        }
    }

I am also trying to rotate the node using angularVelocity in a similar fashion. That works fine as long as the node has not moved or rotated. If it has, it seems to be using world space as well.

if isYRotatingPositive {
        if let angularVel = self.physicsBody?.angularVelocity {
            self.physicsBody?.angularVelocity = SCNVector4(
                x: angularVel.x,
                y: angularVel.y + kPlayerShipRotationSpeed,
                z: angularVel.z,
                w: angularVel.w + kPlayerShipRotationMagnitude)
        }
    }

After the physics are simulated, I am updating the node's position and rotation. I have also tried convertPosition, but could not figure out a way to make this work. (I got some really crazy results with this). Any help is much appreciated.

UPDATE I got the playerShip object to add velocity in the proper directions when it is rotated, but I am still unable to perform multiple rotations without it not turning in the correct direction. For the ship velocity I did this:

if isXThrustPositive {
        thrustDirection = self.convertPosition(SCNVector3(x: kPlayerShipMainThrust, y: 0.0, z: 0.0), toNode: self.parentNode!)
        thrustDirection.x = thrustDirection.x - self.position.x
        thrustDirection.y = thrustDirection.y - self.position.y
        thrustDirection.z = thrustDirection.z - self.position.z
        self.physicsBody?.applyForce(thrustDirection, impulse: true)
    }

When trying to use a similar method for rotation (I know it would be doomed), the resulting SCNVector3 is just a position, not the direction the node is currently facing. Is there any information on convertTransform and how I might use that?

回答1:

As it turns out, I had to get the proper position from the rootNode of the scene to perform a proper rotation based on the current orientation of the SCNNode.

xAxis = self.convertPosition(SCNVector3Make(1.0, 0.0, 0.0), toNode: self.parentNode!)
yAxis = self.convertPosition(SCNVector3Make(0.0, 1.0, 0.0), toNode: self.parentNode!)
zAxis = self.convertPosition(SCNVector3Make(0.0, 0.0, 1.0), toNode: self.parentNode!)
if isXRotatingPositive {
    self.physicsBody?.applyTorque(
        SCNVector4(
            x: sin(kPlayerShipRotationSpeed/2.0) * (xAxis.x - self.position.x),
            y: sin(kPlayerShipRotationSpeed/2.0) * (xAxis.y - self.position.y),
            z: sin(kPlayerShipRotationSpeed/2.0) * (xAxis.z - self.position.z),
            w: cos(kPlayerShipRotationSpeed/2.0) * kPlayerShipRotationMagnitude),
        impulse: true)
    }

Then I just used the standard quaternion rotation formula to get the rotation based on the new axes from the current position. I hope this helps someone else (and that more information on SceneKit is forthcoming) If any SceneKit experts want to comment on this or offer suggestions, they are much appreciated. :)