Confused with scene kit angles - iphone

I am using scene kit to make a fps controller and I found this sample code online. I understand everything but the second assignment of the impulse vector. Could someone go over what is going on in the line
impulse = SCNVector3(
x: impulse.x * cos(angle) - impulse.z * sin(angle),
y: 0,
z: impulse.x * -sin(angle) - impulse.z * cos(angle)
)
Thanks
func renderer(aRenderer: SCNSceneRenderer, updateAtTime time: NSTimeInterval) {
//get walk gesture translation
var translation = walkGesture.translationInView(self.view)
//create impulse vector for hero
let angle = heroNode.presentationNode().rotation.w * heroNode.presentationNode().rotation.y
var impulse = SCNVector3(x: max(-1, min(1, Float(translation.x) / 50)), y: 0, z: max(-1, min(1, Float(-translation.y) / 50)))
impulse = SCNVector3(
x: impulse.x * cos(angle) - impulse.z * sin(angle),
y: 0,
z: impulse.x * -sin(angle) - impulse.z * cos(angle)
)
heroNode.physicsBody?.applyForce(impulse, impulse: true)
}

Related

Move in the direction of the eulerAngle (with Swift and Scenekit)

I am developing an iPad spaceship (first person) game with 6 DOF (6 degrees of freedom) with SceneKit and the accelerometer. I have the accelerometer working, but how can I move the spaceship forward in the direction of the angle of the accelerometer (yaw, roll, pitch)? I use a button for the forward direction. I can't find it on google or something. I hope someone knows how to do this.
Here is the code, where cubeNode is a test (in the 3D game cubeNode is cameraNode).
func updateMotionControl() {
motion.getAccelerometerData(interval: 0.1) { (x,y,z) in
self.motionForce = SCNVector3(x: Float(x) * 0.05, y: Float(y) * 0.05,
z: Float(z) * 0.05)
}
let currentAttitude = motion.attitude
let roll = Float(currentAttitude.roll)
let pitch = Float(currentAttitude.pitch)
let yaw = Float(currentAttitude.yaw)
cubeNode.eulerAngles = SCNVector3(roll, yaw, pitch)
}
I have this code, but it still won't work, what is wrong?
func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
cameraNode.eulerAngles = SCNVector3Make(Float(rot.roll + M_PI/2) * 2, -Float(rot.yaw) * 3, -Float(rot.pitch * 5))
let z = cos(rot.pitch)*sin(rot.yaw)
let y = sin(rot.pitch)
let x = cos(rot.pitch)*cos(rot.yaw)
let view = SCNVector3(x: Float(x), y : Float(y), z : Float(z))
cameraNode.position = cameraNode.position + (view * 0.1)
//cameraNode.physicsBody?.velocity = -view
}
Here are the prints for a few x, y en z:
X:
0.996798277375072,
0.996753286621399,
0.996748721234948,
0.996776960253164,
0.996809519516764,
0.996816599311414,
0.996818969166521,
0.996777228814986
Z:
0.0683379467811582,
0.0678748719764882,
0.0678313394347644,
0.0683611603110574,
0.0686781724979699,
0.0684588783890975,
0.0461781969805951,
0.0478922538280758,
0.0485691959442941,
0.0482168862439498,
0.0474367474311863
Y:
0.0437050318386564,
0.0434850468949368,
0.0432268234343706,
0.0431581009944219,
0.0433707104009568,
0.0436728563252332,
0.044357103165837,
0.0449712895273139,
0.0364369979497931,
0.0353335950917769

How to align 2 SCNNode's together horizontally?

I'm trying to align two SCNNodes together but can't seem to figure out how. This is what I have right now:
cube.scale = SCNVector3(x: 0.1, y: 0.1, z: 0.1)
cube.position = SCNVector3(0, 3, -3)
cubeTwo.scale = SCNVector3(x: 0.15, y: 0.15, z: 0.15)
cubeTwo.position = SCNVector3(0.5, 3, -3)
cubeThree.scale = SCNVector3(x: 0.2, y: 0.2, z: 0.2)
cubeThree.position = SCNVector3(1, 3, -3)
How can I achieve this? Thank you!!
To align them horizontally, set the position Y values to be the same. X is left-right, Y is up-down, Z is near-far (until you start moving the camera around!).
parentNode.addChildNode(cube)
parentNode.addChildNode(cubeTwo)
parentNode.addChildNode(cubeThree)
func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
parentNode.position = self.getPositionRelativeToCameraView(distance: 1.0).position
}
func getPositionRelativeToCameraView(distance: Float) -> (position: SCNVector3, rotation: SCNVector4) {
var x = Float()
var y = Float()
var z = Float()
let cameraLocation = self.sceneView.pointOfView!.position //else { return (SCNVector3Zero) }
let rotation = self.sceneView.pointOfView!.rotation //else { return (SCNVector3Zero) }
let direction = calculateCameraDirection(cameraNode: rotation)
x = cameraLocation.x + distance * direction.x
y = cameraLocation.y + distance * direction.y
z = cameraLocation.z + distance * direction.z
let position = SCNVector3Make(x, y, z)
return (position, rotation)
}
func calculateCameraDirection(cameraNode: SCNVector4) -> SCNVector3 {
let x = -cameraNode.x
let y = -cameraNode.y
let z = -cameraNode.z
let w = cameraNode.w
let cameraRotationMatrix = GLKMatrix3Make(cos(w) + pow(x, 2) * (1 - cos(w)),
x * y * (1 - cos(w)) - z * sin(w),
x * z * (1 - cos(w)) + y*sin(w),
y*x*(1-cos(w)) + z*sin(w),
cos(w) + pow(y, 2) * (1 - cos(w)),
y*z*(1-cos(w)) - x*sin(w),
z*x*(1 - cos(w)) - y*sin(w),
z*y*(1 - cos(w)) + x*sin(w),
cos(w) + pow(z, 2) * ( 1 - cos(w)))
let cameraDirection = GLKMatrix3MultiplyVector3(cameraRotationMatrix, GLKVector3Make(0.0, 0.0, -1.0))
return SCNVector3FromGLKVector3(cameraDirection)
}

How to connect two SCNSpheres in 3D space using Bezier path in Swift?

I have the following code:
func createScene(){
count += 1
let sphereGeom = SCNSphere(radius: 1.5)
sphereGeom.firstMaterial?.diffuse.contents = UIColor.redColor()
let path = UIBezierPath()
path.moveToPoint(CGPoint(x: 0, y: 0))
let radius = 3.0
var radians = Double(0)
var yPosition = Float(5.4)
while count <= 20 {
if radians >= 2{
radians -= 2
}
let sphereNode = SCNNode(geometry: sphereGeom)
let angle = Double(radians * M_PI)
let xPosition = Float(radius * cos(angle))
let zPosition = Float(radius * sin(angle))
sphereNode.position = SCNVector3(xPosition, yPosition, zPosition)
let cgX = CGFloat(xPosition)
let cgY = CGFloat(yPosition)
path.addQuadCurveToPoint(CGPoint(x: cgX, y: cgY), controlPoint: CGPoint(x: (cgX / 2), y: (cgY / 2)))
path.addLineToPoint(CGPoint(x: (cgX - (cgX * 0.01)), y: cgY))
path.addQuadCurveToPoint(CGPoint(x: 1, y: 0), controlPoint: CGPoint(x: (cgX / 2), y: ((cgY / 2) - (cgY * 0.01))))
let shape = SCNShape(path: path, extrusionDepth: 3.0)
shape.firstMaterial?.diffuse.contents = UIColor.blueColor()
let shapeNode = SCNNode(geometry: shape)
shapeNode.eulerAngles.y = Float(-M_PI_4)
self.rootNode.addChildNode(shapeNode)
count += 1
radians += 0.5556
yPosition -= 1.35
self.rootNode.addChildNode(sphereNode)
}
I want to add a Bezier path connecting each sphere to the next one, creating a spiral going down the helix. For some reason, when I add this code, the shape doesn't even appear. But when I use larger x and y values, I see the path fine, but it is no way oriented to the size of the spheres. I don't understand why it disappears when I try to make it smaller.
Your SCNShape doesn't ever get extruded. Per Apple doc,
An extrusion depth of zero creates a flat, one-sided shape.
With larger X/Y values your flat shape happens to become visible. You can't build a 3D helix with SCNShape, though: the start and end planes of the extrusion are parallel.
You'll have to use custom geometry, or approximate your helix with a series of elongated SCNBox nodes. And I bet someone out there knows how to do this with a shader.

Rotating a CGPoint around another CGPoint

Okay so I want to rotate CGPoint(A) 50 degrees around CGPoint(B) is there a good way to do that?
CGPoint(A) = CGPoint(x: 50, y: 100)
CGPoint(B) = CGPoint(x: 50, y: 0)
Here's what I want to do:
This is really a maths question. In Swift, you want something like:
func rotatePoint(target: CGPoint, aroundOrigin origin: CGPoint, byDegrees: CGFloat) -> CGPoint {
let dx = target.x - origin.x
let dy = target.y - origin.y
let radius = sqrt(dx * dx + dy * dy)
let azimuth = atan2(dy, dx) // in radians
let newAzimuth = azimuth + byDegrees * CGFloat(M_PI / 180.0) // convert it to radians
let x = origin.x + radius * cos(newAzimuth)
let y = origin.y + radius * sin(newAzimuth)
return CGPoint(x: x, y: y)
}
There are lots of ways to simplify this, and it's a perfect case for an extension to CGPoint, but I've left it verbose for clarity.
public extension CGFloat {
///Returns radians if given degrees
var radians: CGFloat{return self * .pi / 180}
}
public extension CGPoint {
///Rotates point by given degrees
func rotate(origin: CGPoint? = CGPoint(x: 0.5, y: 0.5), _ byDegrees: CGFloat) -> CGPoint {
guard let origin = origin else {return self}
let rotationSin = sin(byDegrees.radians)
let rotationCos = cos(byDegrees.radians)
let x = (self.x * rotationCos - self.y * rotationSin) + origin.x
let y = (self.x * rotationSin + self.y * rotationCos) + origin.y
return CGPoint(x: x, y: y)
}
}
Usage
var myPoint = CGPoint(x: 40, y: 50).rotate(45)
var myPoint = CGPoint(x: 40, y: 50).rotate(origin: CGPoint(x: 0, y: 0), 45)

Need help incorporating randoms in Swift

I am trying to get my sprites on random positions on the screen but it says "CGFloat is not convertible to Double"
var randomNumber = arc4random()
bat1 = SKSpriteNode(imageNamed: "rsz_silverbat.png")
bat1.position = CGPoint(x: self.frame.size.width * 0.1, y: self.frame.size.height * randomNumber)
bat1.position = CGPoint(x: self.view.frame.size.width * CGFloat(0.1), y: self.view.frame.size.height * CGFloat(randomNumber))