Swift 4: SKSpriteNode won't stop on a position - swift

Here i have a tank with bullets, when the user taps the screen, the tank fires, it's fine
but when the bullet comes out of the tank, it goes above the screen and it won't stop on the touch position
here's my code:
for touch in touches {
let location = touch.location(in: self)
let bullet = SKSpriteNode(imageNamed: "bullet4")
bullet.position = CGPoint(x: self.MainTank.position.x, y: self.MainTank.position.y + 10)
bullet.size = CGSize(width: 12, height: 20)
bullet.physicsBody = SKPhysicsBody(circleOfRadius: bullet.size.width / 2)
bullet.physicsBody?.affectedByGravity = false
bullet.physicsBody?.isDynamic = true // false stops the bullet on the tank
bullet.physicsBody?.allowsRotation = false
self.addChild(bullet)
var dx = CGFloat(location.x)
var dy = CGFloat(location.y)
let magnitude = sqrt(dx * dx + dy * dy)
dx /= magnitude
dy /= magnitude
let vector = CGVector(dx: 5.0 * dx, dy: 5.0 * dy)
bullet.physicsBody?.applyImpulse(vector)
}
i tried to set isDynamic to true, however this makes the bullet stop at the tanks position
Thanks

It probably moves outside of the screen because you multiply the vector by 5.0. I also wouldn't create your vector like that, as the division part with the magnitude isn't necessary. Try this instead:
let dx = location.x - bullet.position.x
let dy = location.y - bullet.position.y
let vector = CGVector(dx: dx, dy: dy)
bullet.run(SKAction.move(by: vector, duration: 1.0)) //choose your own duration of course

Related

swift shooting objects from circle shape

I have a circle in the middle and I need to fire bullets in direction opposite to where I touch and come out from the player, I wrote the following code but nothing happen
private func fire(position: CGPoint) {
let bullet = SKShapeNode(circleOfRadius: 2)
bullet.strokeColor = SKColor.darkGray
bullet.fillColor = SKColor.darkGray
bullet.physicsBody = SKPhysicsBody(circleOfRadius: 2)
let posX = (position.x) * -1
let posY = (position.y) * -1
let pos = CGPoint(x: posX, y: posY)
bullet.position = pos
bullet.physicsBody?.affectedByGravity = false
bullet.physicsBody?.isDynamic = false
bullet.physicsBody?.pinned = false
numberOfBullets += 1
bullet.name = String(numberOfBullets)
bullet.physicsBody?.collisionBitMask = bodyType.enemy.rawValue
bullet.physicsBody?.categoryBitMask = bodyType.bullet.rawValue
bullet.physicsBody?.contactTestBitMask = bodyType.enemy.rawValue
bullet.physicsBody?.usesPreciseCollisionDetection = true
world.addChild(bullet)
bulletForce(bullet: bullet, position: position)
}
private func bulletForce(bullet: SKShapeNode, position: CGPoint) {
let ddx = Double((bullet.position.x - position.x))
let ddy = Double((bullet.position.y - position.y))
let degree = atan2(ddy, ddx) * (180.0 / M_PI)
let magnitude = 900.0
let angle = degree
let dx = magnitude * cos(angle)
let dy = magnitude * sin(angle)
let vector = CGVector(dx: dx,dy: dy)
bullet.physicsBody?.applyForce(vector)
//bullet.run(fire, withKey: "firing\(bullet.name)")
}
EDIT ::
This solved the problem thanks to the aid from the accepted answer
let posX = (position.x) * -1
let posY = (position.y) * -1
let pos = CGPoint(x: posX, y: posY)
let theta = atan2((pos.y - player.position.y), (pos.x - player.position.x))
let dx = cos(theta) / 4
let dy = sin(theta) / 4
world.addChild(bullet)
let vector = CGVector(dx: dx, dy: dy)
bullet.physicsBody!.applyImpulse(vector)
where theta is the angle i want the bullet to go to and here it is
Note::
The player is in the middle ( circle ).
The posX and posY are the x and y coordinates where the user touched and they are multiplied by -1 to get the opposite direction where my bullet will be placed.
The angle theta is then calculated using the atan2 function that instead of positioning my bullet away from the player ( circle ), it will position it at the edge of circle.
Have you tried switching isDynamic from "false" to "true"? Also, try adding GCVector(dx: 1.0 * dx, dy: 1.0 * dy)

Shooting bullets from SKSpriteNode

I try to build 2D - top down game, and I have player (SKSpriteNode) he can move and rotate, and I want to shoot two bullets from him.
I use this code to shoot:
func setBullet(player: Player, bullet: Int)
{
let weaponPosition = scene!.convertPoint(player.weapon.position, fromNode: player)
var xPos, yPos: CGFloat!
let sinus = sin(player.zRotation)
let cosinus = cos(player.zRotation)
if bullet == 1
{
xPos = converted.x - sinus * player.size.height / 2
yPos = converted.y + cosinus * player.size.height / 2
}
else if bullet == 2
{
xPos = weaponPosition.x - sinus * player.size.height / 2
yPos = weaponPosition.y + cosinus * player.size.height / 2
}
position = CGPoint(x: xPos, y: yPos)
physicsBody!.applyImpulse(CGVector(dx: -sinus * normalSpeed, dy: cosinus * normalSpeed))
}
But, i do not know how to correctly set the position...
I try to make something like this
(Green dots - this is a bullets). Can anyone help me please!
Shooting multiple bullets in the same direction is fairly straightforward. The key is to determine the bullets' initial positions and direction vectors when the character is rotated.
You can calculate a bullet's initial position within the scene by
let point = node.convertPoint(weapon.position, toNode: self)
where node is the character, weapon.position is non-rotated position of a gun, and self is the scene.
Typically, a bullet moves to the right, CGVector(dx:1, dy:0), or up, CGVector (dx:0, dy:1), when the character is not rotated. You can calculate the direction of the impulse to apply to the bullet's physics body by rotating the vector by the character's zRotation with
func rotate(vector:CGVector, angle:CGFloat) -> CGVector {
let rotatedX = vector.dx * cos(angle) - vector.dy * sin(angle)
let rotatedY = vector.dx * sin(angle) + vector.dy * cos(angle)
return CGVector(dx: rotatedX, dy: rotatedY)
}
Here's an example of how to shoot two bullets from a rotated character:
struct Weapon {
var position:CGPoint
}
class GameScene: SKScene {
let sprite = SKSpriteNode(imageNamed:"Spaceship")
let dualGuns = [Weapon(position: CGPoint(x: -15, y: 15)), Weapon(position: CGPoint(x: 15, y: 15))]
let singleGun = [Weapon(position: CGPoint(x: 0, y: 15))]
let numGuns = 1
// If your character faces up where zRotation == 0, offset by pi
let rotationOffset = CGFloat(M_PI_2)
override func didMoveToView(view: SKView) {
scaleMode = .ResizeFill
sprite.position = view.center
sprite.size = CGSizeMake(25, 25)
self.addChild(sprite)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
if let _ = touches.first {
let action = SKAction.rotateByAngle(CGFloat(M_PI_4/2), duration:1)
sprite.runAction(action) {
[weak self] in
if let scene = self {
switch (scene.numGuns) {
case 1:
for weapon in scene.singleGun {
scene.shoot(weapon: weapon, from: scene.sprite)
}
case 2:
for weapon in scene.dualGuns {
scene.shoot(weapon: weapon, from: scene.sprite)
}
default:
break
}
}
}
}
}
func shoot(weapon weapon:Weapon, from node:SKNode) {
// Convert the position from the character's coordinate system to scene coodinates
let converted = node.convertPoint(weapon.position, toNode: self)
// Determine the direction of the bullet based on the character's rotation
let vector = rotate(CGVector(dx: 0.25, dy: 0), angle:node.zRotation+rotationOffset)
// Create a bullet with a physics body
let bullet = SKSpriteNode(color: SKColor.blueColor(), size: CGSizeMake(4,4))
bullet.physicsBody = SKPhysicsBody(circleOfRadius: 2)
bullet.physicsBody?.affectedByGravity = false
bullet.position = CGPointMake(converted.x, converted.y)
addChild(bullet)
bullet.physicsBody?.applyImpulse(vector)
}
// Rotates a point (or vector) about the z-axis
func rotate(vector:CGVector, angle:CGFloat) -> CGVector {
let rotatedX = vector.dx * cos(angle) - vector.dy * sin(angle)
let rotatedY = vector.dx * sin(angle) + vector.dy * cos(angle)
return CGVector(dx: rotatedX, dy: rotatedY)
}
}
Suppose your player is a circle maked with SKShapeNode or SKSpriteNode.
Both of them have the frame property:
let f = player.frame
So, the first bullet can be in this position:
let firstBullet.position = CGPointMake(player.position.x-(f.width/2),player.position.y)
let secondBullet.position = CGPointMake(player.position.x+(f.width/2),player.position.y)
To know it during rotation do:
let firstBulletXPos = firstBullet.position.x - sinus * bullet.size.height / 2
let firstBulletYPos = firstBullet.position.y + cosinus * bullet.size.height / 2
let secondBulletXPos = secondBullet.position.x - sinus * bullet.size.height / 2
let secondBulletYPos = secondBullet.position.y + cosinus * bullet.size.height / 2

how to spawn a SKnode on a loop that is in a different class - swift

I am creating a shooting game and i am trying to create a firing method but my current method only spawns one bullet at a time when clicked. I have my bullet defined as a SKnode subclass and calling it in my touches began method in my gameScene.swift. Here's how
class Bullet1: SKNode {
var Bullet1:SKSpriteNode = SKSpriteNode()
var Bullet1Animaton:SKAction?
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override init () {
super.init()
}
func createBullet1s (){
let wait:SKAction = SKAction.waitForDuration( CFTimeInterval(0.25))
let block:SKAction = SKAction.runBlock(createBullet1)
let seq2:SKAction = SKAction.sequence( [block, wait])
SKAction.repeatActionForever(seq2)
self.runAction(seq2, withKey:"droneAction")
}
func createBullet1() {
Bullet1 = SKSpriteNode(imageNamed: "bullet.png")
Bullet1.xScale = 0.5
Bullet1.yScale = 0.5
Bullet1.physicsBody = SKPhysicsBody(rectangleOfSize: Bullet1.size)
Bullet1.physicsBody?.categoryBitMask = PhysicsCategory.bullet1
Bullet1.physicsBody?.contactTestBitMask = PhysicsCategory.enemy1
Bullet1.physicsBody?.affectedByGravity = false
Bullet1.physicsBody?.dynamic = true
self.addChild(Bullet1)
self.name = "Bullet1"
}
}
class GameScene: SKScene, SKPhysicsContactDelegate {
override func touchesBegan(touches: Set<UITouch>, withEvent
event:UIEvent?) {
override func touchesBegan(touches: Set<UITouch>, withEvent
event:UIEvent?) {
for touch in touches {
let location = touch.locationInNode(self)
let node = nodeAtPoint(location)
if (CGRectContainsPoint(joystick.frame, location)) {
stickActive = true
fireWeapon = true
}else{
stickActive = false
}
if stickActive == true && fireWeapon == true{ if fireWeapon == false
{}
let bulletAction = SKAction.runBlock({
let v = CGVector(dx: location.x - self.joystickBase.position.x, dy:
location.y - self.joystickBase.position.y)
let angle = atan2(v.dy, v.dx) //where angle is defined "in radians"
let deg = angle * CGFloat(180 / M_PI)
print(deg + 180) // prints degree in debugging
self.hero.zRotation = angle - 1.57079633 //rotates with angle of joy
stic
let bullet1:Bullet1 = Bullet1()
bullet1.createBullet1()
bullet1.position = CGPoint (x: self.hero.position.x , y:
self.hero.position.y) // Bullet spawn # anchor point
let xDist:CGFloat = sin(angle - 1.5709633) * 35 //bullet spawn location
let yDist:CGFloat = cos(angle - 1.5709633) * 35 //bullet spawn location
bullet1.position = CGPointMake( self.hero.position.x - xDist,
self.hero.position.y + yDist) //spawning bullet # defined location
let xDistMove:CGFloat = sin(angle - 1.5709633) * 700 //Bullet max x
distance
let yDistMove:CGFloat = cos(angle - 1.5709633) * 700 //Bullet max y
distance
let bulletMovementY = SKAction.moveToY(self.hero.position.y +
yDistMove, duration: 1) //Bullet y speed
let bulletMovementX = SKAction.moveToX(self.hero.position.x -
xDistMove, duration: 1) //Bullet x speed
bullet1.runAction(bulletMovementY)
bullet1.runAction(bulletMovementX)
self.addChild(bullet1)
})
let wait = SKAction.waitForDuration(0.25)
let completeSequence = SKAction.sequence([bulletAction, wait])
let repeatShootingActionForever =
SKAction.repeatActionForever(completeSequence)
self.runAction(repeatShootingActionForever, withKey: "BulletAction")
}
override func touchesMoved(touches: Set<UITouch>, withEvent event:
UIEvent?) {
for touch in touches {
let location = touch.locationInNode(self
if (stickActive == true) {
let v = CGVector(dx: location.x - joystickBase.position.x, dy:
location.y - joystickBase.position.y)
let angle = atan2(v.dy, v.dx) //where angle is defined "in radians"
let deg = angle * CGFloat(180 / M_PI)
let length: CGFloat = joystickBase.frame.size.height / 2
print(deg + 180) // prints degree in debugging
joystick.position = location
hero.zRotation = angle - 1.57079633 //rotates with angle of joy stick
if (CGRectContainsPoint(joystickBase.frame, location)) {
}
override func touchesMoved(touches: Set<UITouch>, withEvent event:
UIEvent?) {
for touch in touches {
let location = touch.locationInNode(self)
if stickActive == true && fireWeapon == true{ if fireWeapon == false
{}
let v = CGVector(dx: location.x - joystickBase.position.x, dy:
location.y - joystickBase.position.y)
let angle = atan2(v.dy, v.dx) //where angle is defined "in radians"
let deg = angle * CGFloat(180 / M_PI)//converts radains to degrees and
generates a degree when touchesmove == true
let length: CGFloat = joystickBase.frame.size.height / 2 //sets maximum
distance for joystick ball
print(deg + 180) // prints degree in debugging
joystick.position = location
self.hero.zRotation = angle - 1.57079633 //rotates with
angle of joy stick
let xDist:CGFloat = sin(angle - 1.5709633) * 35 //bullet spawn location
let yDist:CGFloat = cos(angle - 1.5709633) * 35 //bullet spawn location
bullet1.position = CGPointMake( self.hero.position.x - xDist,
self.hero.position.y + yDist) //spawning bullet # defined location
let xDistMove:CGFloat = sin(angle - 1.5709633) * 700 //Bullet max x
distance
let yDistMove:CGFloat = cos(angle - 1.5709633) * 700 //Bullet max y
distance
let bulletMovementY = SKAction.moveToY(self.hero.position.y +
yDistMove, duration: 1) //Bullet y speed
let bulletMovemenX = SKAction.moveToX(self.hero.position.x - xDistMove,
duration: 1) //Bullet x speed
bullet1.runAction(bulletMovementY)
bullet1.runAction(bulletMovemenX)
}}
as you can see i need to call my bullet method in my touches began since the bullet spawn location is coordinated with a joystick. The current method only spawn 1 bullet when clicked instead of creating a new bullet every 0.25 seconds when the joystick is held down like i attempted in my createBullet1s method. If anyone can help me out i would be very grateful! thank you
if the values have to be new calculated for every bullet then something like this would be the way to go i guess (add self. before every node Name):
if stickActive == true && fireWeapon == true{ if fireWeapon == false
{}
let shootingAction = SKAction.runBlock({
let v = CGVector(dx: location.x - joystickBase.position.x, dy:
location.y - joystickBase.position.y)
let angle = atan2(v.dy, v.dx) //where angle is defined "in radians"
let deg = angle * CGFloat(180 / M_PI)//converts radains to degrees and
generates a degree when touchesmove == true
print(deg + 180)
let bullet1:Bullet1 = Bullet1()
self.bullet1.createBullet1s()
self.bullet1.position = CGPoint (x: self.hero.position.x , y: self.hero.position.y)
let xDist:CGFloat = sin(angle - 1.5709633) * 35
let yDist:CGFloat = cos(angle - 1.5709633) * 35
self.bullet1.position = CGPointMake(self.hero.position.x - xDist,self.hero.position.y + yDist)
let xDistMove:CGFloat = sin(angle - 1.5709633) * 700
let yDistMove:CGFloat = cos(angle - 1.5709633) * 700
let bulletMovementY = SKAction.moveToY(self.hero.position.y + yDistMove,
duration: 1)
let bulletMovemenX = SKAction.moveToX(self.hero.position.x - xDistMove,
duration: 1)
let wait:SKAction = SKAction.waitForDuration(CFTimeInterval(0.25))
self.addChild(self.bullet1)
let groupMovement = SKAction.group([bulletMovementY,bulletMovementX])
let removeNode = SKAction.removeFromParent()
let sequenceMovementWithWait = SKAction.sequence([wait,groupMovement,removeNode])
self.hero.runAction(sequenceMovementWithWait)
self.hero.zRotation = angle - 1.57079633
})
let repeatShootingActionForever = SKAction.repeatActionForever(shootingAction)
self.runAction(repeatShootingActionForever, withKey: "BulletAction"))
if the values can stay the same for each bullet maybe something like this would be enough:
let bulletAction = SKAction.runBlock({
self.addChild(self.bullet1)
let groupAction = SKAction([bulletMovementY,bulletMovementX])
let removeNode = SKAction.removeFromParent()
let finalSequenceWithWait = SKAction.sequence([wait,groupAction,removeNode])
self.bullet1.runAction(finalSequenceWithWait)
})
let repeatBulletActionForever = SKAction.repeatActionForever(bulletAction)
self.runAction(repeatBulletActionForever, withKey: "BulletAction")
For both ways i would say in TouchesEnded:
self.removeActionForKey("BulletAction")
Edit:
Okay .. You have a SKNode subclass where you add the bullets (SpriteNodes) to the SKNode. By the way - it's complicated because you gave the SpriteNodes and the SKNode the same name. However, the bullets (SpriteNodes) gets added to the SKNode and the SKNode gets added in the GameScene. Now we "spawn" and "remove" this SKNode in the gamescene, but we only add SpriteNodes to the SKNode and we don't remove them there.
Do you want multiple bullets at the same time to be visible in the GameScene? If you need only 1 bullet at a time visible (but repeated) i would say maybe it would help to remove the Bullet (SpriteNode) from your SKNode like we did in the GameScene.
Imagine that:
- GameScene creates a SKNode. (your class Bullet1)
- SKNode creates Child SpriteNode
- GameScene removes the SKNode.
- GameScene creates another SKNode. (again your class Bullet1)
- SKNode wants to create Child SpriteNode
-> Error: SpriteNode already exists.
So we need to edit your class.
//class Bullet1
func createBullet1() {
if Bullet1.parent == nil{
Bullet1 = SKSpriteNode(imageNamed: "bullet.png")
Bullet1.xScale = 0.5
Bullet1.yScale = 0.5
Bullet1.physicsBody = SKPhysicsBody(rectangleOfSize: Bullet1.size)
Bullet1.physicsBody?.categoryBitMask = PhysicsCategory.bullet1
Bullet1.physicsBody?.contactTestBitMask = PhysicsCategory.enemy1
Bullet1.physicsBody?.affectedByGravity = false
Bullet1.physicsBody?.dynamic = true
self.addChild(Bullet1)
self.name = "Bullet1"
}
else{
Bullet1.removeFromParent()
}
}
Oh, and we need to wait 0.25secs before adding a new SKNode so that the animation is done. In your GameScene edit this part:
let repeatShootingActionForever = SKAction.repeatActionForever(shootingAction)
self.runAction(repeatShootingActionForever, withKey: "BulletAction"))
to this:
let wait = SKAction.waitForDuration(0.25)
let runShootingAction = SKAction.runBlock(shootingAction)
let completeSequence = SKAction.sequence([wait,runShootingAction])
let repeatShootingActionForever = SKAction.repeatActionForever(completeSequence)
self.runAction(repeatShootingActionForever, withKey: "BulletAction"))
I bet there are better solutions for that, im not an expert in Swift, too. You have to test that .. sorry.
Another edit:
You did not tell which zRotation the bullet should have.
Try this (where you have bulletAction = SKAction.runBlock):
let bulletAction = SKAction.runBlock({
let v = CGVector(dx: location.x - self.joystickBase.position.x, dy: location.y - self.joystickBase.position.y)
let angle = atan2(v.dy, v.dx) //where angle is defined "in radians"
let deg = angle * CGFloat(180 / M_PI)//converts radains to degrees and generates a degree when touchesmove == true
print(deg + 180) // prints degree in debugging
let bullet1:Bullet1 = Bullet1()
bullet1.position = CGPoint (x: self.hero.position.x , y: self.hero.position.y) // Bullet spawn # anchor point
bullet1.zRotation = angle - 1.57079633 //rotates with angle of joy stick
let xDist:CGFloat = sin(angle - 1.5709633) * 35 //bullet spawn location
let yDist:CGFloat = cos(angle - 1.5709633) * 35 //bullet spawn location
bullet1.position = CGPointMake( self.hero.position.x - xDist, self.hero.position.y + yDist) //spawning bullet # defined location
bullet1.createBullet1()
let xDistMove:CGFloat = sin(angle - 1.5709633) * 700 //Bullet max x distance
let yDistMove:CGFloat = cos(angle - 1.5709633) * 700 //Bullet max y distance
let bulletMovementY = SKAction.moveToY(self.hero.position.y+yDistMove, duration: 1) //Bullet y speed
let bulletMovemenX = SKAction.moveToX(self.hero.position.x -xDistMove, duration: 1) //Bullet x speed
let wait:SKAction = SKAction.waitForDuration( CFTimeInterval(0.25))
// let bulletFire = SKAction.sequence([wait,bulletMovemenX, bulletMovementY])
self.addChild(bullet1)
bullet1.runAction(wait)
bullet1.runAction(bulletMovementY)
bullet1.runAction(bulletMovemenX)
self.hero.zRotation = angle - 1.57079633 //rotates with angle of joy stick
})
Last Edit:
I can't see in your updated method the bullet1.zRotation so i guess you want only the hero to Change the zRotation.
However, if the zRotation only changes in touchesBeganand not in touchesMoved i would say you should make angle a global variable which can be changed in both methods. Maybe this helps, because hero gets his zRotation depending on the value of angle (i think).
Make angle a global variable and add a variable which tells you if your touch is moved or not:
class GameScene: SKScene, SKPhysicsContactDelegate{
var angle = CGFloat() // It should be a CGFloat, right?
var touchesMovedOn = false
Edit this part from touchesBegan:
let bulletAction = SKAction.runBlock({
let v = CGVector(dx: location.x - self.joystickBase.position.x, dy: location.y - self.joystickBase.position.y)
let angle = atan2(v.dy, v.dx) //where angle is defined "in radians"
let deg = angle * CGFloat(180 / M_PI)
print(deg + 180) // prints degree in debugging
self.hero.zRotation = angle - 1.57079633 //rotates with angle of joystic
to this:
let bulletAction = SKAction.runBlock({
let v = CGVector(dx: location.x - self.joystickBase.position.x, dy: location.y - self.joystickBase.position.y)
if touchesMovedOn == false{
angle = atan2(v.dy, v.dx) //where angle is defined "in radians"
}
let deg = angle * CGFloat(180 / M_PI)
print(deg + 180) // prints degree in debugging
self.hero.zRotation = angle - 1.57079633 //rotates with angle of joystic
Edit this part from touchesMoved:
let v = CGVector(dx: location.x - joystickBase.position.x, dy: location.y - joystickBase.position.y)
let angle = atan2(v.dy, v.dx) //where angle is defined "in radians"
let deg = angle * CGFloat(180 / M_PI)//converts radains to degrees and generates a degree when touchesmove == true
let length: CGFloat = joystickBase.frame.size.height / 2 //sets Maximum distance for joystick ball
print(deg + 180) // prints degree in Debugging to this:
to this:
touchesMovedOn = true
let v = CGVector(dx: location.x - joystickBase.position.x, dy: location.y - joystickBase.position.y)
angle = atan2(v.dy, v.dx) //where angle is defined "in radians"
let deg = angle * CGFloat(180 / M_PI)//converts radains to degrees and generates a degree when touchesmove == true
let length: CGFloat = joystickBase.frame.size.height / 2 //sets Maximum distance for joystick ball
print(deg + 180) // prints degree in Debugging to this:
Add this line in touchesEnded
touchesMovedOn = false
If this not helps i really Need the Project as i would have to test it myself where the Problem is. So i hope it works now. Best luck ! And as i said, im sure there are better Solutions for this, so in the future you should look out to make the code better. ;-)

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.

(SWIFT) Sprite not giving me the correct zRotation value after being added

Details of program: by looking at this picture(http://i.stack.imgur.com/QOZ53.png), what I'm trying to do is have the spaceship circle the planet. I achieved this by making a line node and changes its anchor point to the top and then position it to the centre of the planet which then upon impact of the spaceship and planet, the line is angled towards the ship in which then the ship is removed from the view and added to the line node as a child and together they rotate around the planet, as the ship rotates around the the planet, the ship it self also rotates on the spot (hopefully that makes sense)
Problem: the problem is im not getting the correct zRotation value of the ship. Right now I got the code to draw another ship at the location where it was tapped and set the zRotation of that image to the zRotation of the ship but i keep getting different angles. (refer to picture). Is this because I have ship added to line node as a child? Im running a rotating animation on both the line and the ship. In the picture, the line is rotating around the planet counter clockwise dragging the ship along with it and the ship itself is also rotating counter clockwise on the spot. In the picture the left ship; the one that's touching the line is the one thats rotating, the ship on the right is just drawn to angle of the rotating ship but by looking at the picture you can see the angle of the ship is pretty opposite of the one on the left. Why is this so? what I noticed is that when the ship is at the bottom half of the planet, the angles are fine but when it comes to the top half, the angles are kinda opposite(refer to picture)
Picture
Console Log:
I'm Touched -
ship angle in degrees: 83.6418545381942
PLAYER POSITION X: 100.0 Y: 100.0
PLAYER ZROTATION: 1.45982575416565
WE'RE TOUCHING -
PLANET POSITION X*: 120.0 Y: 230.000015258789
PLAYER-SHIP POSITION X: 107.998710632324 Y: 171.783294677734
ANGLE OF LINE RADIANS*: -1.77409685090117 DEGRESS: -101.648262004087
PLAYER-SHIP ROTATION: 1.57079637050629
I'm Touched -
ship angle in degrees: 314.660859137531
TEMP POS X: 136.535125732422 Y: 287.094879150391
TEMP ZROTATION: 5.491868019104
PLAYER POSITION X: 136.535125732422 Y: 287.094879150391
PLAYER ZROTATION: 5.491868019104
Collision Code:
func didBeginContact(contact: SKPhysicsContact) {
if contact.bodyA.categoryBitMask == planetGroup || contact.bodyB.categoryBitMask == planetGroup {
print(" WE'RE TOUCHING ")
moving = true
touching = true
let degrees = 45.0
let radians = degrees * M_PI / 180.0
//rotate Line
var rotateLine = SKAction.rotateByAngle(CGFloat(radians), duration: 0.5)
var repeatLine = SKAction.repeatActionForever(rotateLine)
//rotates Ship
var rotateShip = SKAction.rotateByAngle(CGFloat(radians), duration: 0.4)
var repeatShip = SKAction.repeatActionForever(rotateShip)
playerShip.physicsBody?.velocity = CGVector(dx: 0, dy: 0)
planetNode = contact.bodyA.node as! SKSpriteNode
planetX = planetNode.position.x
planetY = planetNode.position.y
playerX = playerShip.position.x
playerY = playerShip.position.y
var angleOfAnchor = AngleBetweenPoints(planetNode.position, endPoint: playerShip.position)
var three60 = 360 * CGFloat(M_PI) / 180.0
var nintey = 90 * CGFloat(M_PI) / 180.0
var inDegree = angleOfAnchor * 180.0 / CGFloat(M_PI)
var shipPlanetDistance = SDistanceBetweenPoints(planetNode.position, p2: playerShip.position)
line = SKSpriteNode(color: UIColor.blackColor(), size: CGSize(width: 2, height: planetNode.size.height))
line.anchorPoint = CGPoint(x: 0.5, y: 1)
line.position = CGPoint(x: planetX, y: planetY)
line.zRotation = -(three60 - nintey - angleOfAnchor)
self.addChild(line)
tempShip = playerShip
playerShip.removeFromParent()
line.runAction(repeatLine, withKey: "rotateLine")
//playerShip.position = CGPoint(x: playerX, y: playerY)
line.addChild(playerShip)
playerShip.zRotation = (90 * CGFloat(M_PI) / 180.0)
playerShip.runAction(repeatShip, withKey: "rotateShip")
print("*PLANET POSITION* X: \(planetX) Y: \(planetY) \r *PLAYER-SHIP POSITION* X: \(playerX) Y: \(playerY) \r *ANGLE OF LINE* RADIANS: \(angleOfAnchor) DEGRESS: \(inDegree) *PLAYER-SHIP ROTATION: \(playerShip.zRotation)")
}
}
Screen Touch Code:
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
print(" I'm Touched ")
var radians:CGFloat = playerShip.zRotation
var degrees = radians * 180.0 / CGFloat(M_PI)
var dx = cos(radians)
var dy = sin(radians)
print(" ship angle in degrees: \(degrees) ")
var tempAngle = playerShip.zRotation
var shipPosition = convertPoint(playerShip.position, fromNode: line)
playerX = shipPosition.x
playerY = shipPosition.y
if startMove == true {
playerShip.removeActionForKey("rotateShip")
playerShip.physicsBody?.velocity = CGVector(dx: 100*dx, dy: 100*dy)// speed of direction
startMove = false
}
if moving == true{
//playerShip.removeActionForKey("rotateShip")
//playerShip.removeFromParent()
//self.addChild(playerShip)
var radians:CGFloat = playerShip.zRotation
var degrees = radians * 180.0 / CGFloat(M_PI)
var dx = cos(radians)
var dy = sin(radians)
print(" ship angle in degrees: \(degrees) ")
//playerShip.zRotation = tempShip.zRotation
//playerShip.position = CGPoint(x: playerX, y: playerY)
//playerShip.physicsBody?.velocity = CGVector(dx: 100*dx, dy: 100*dy)// speed of direction
// this is the ship that gets drawn
var temp = SKSpriteNode(imageNamed: "img/ship/2.png")
temp.position = CGPoint(x: playerX, y: playerY)
temp.zRotation = playerShip.zRotation
self.addChild(temp)
//moving = false
print("*TEMP POS* X: \(temp.position.x) Y: \(temp.position.y) *TEMP ZROTATION*: \(temp.zRotation)")
}
print("*PLAYER POSITION* X: \(playerX) Y: \(playerY) *PLAYER ZROTATION: \(playerShip.zRotation)")
}
I managed to solve this problem, I added the line.zrotation with the playerShip.zrotation and it ended up working perfectly