Search code examples
iosxcodesprite-kitscenekitjoystick

JoyStick only moves when Camera Controls = true Xcode, SWIFT, SpriteKit, SceneKit


Hey I have a 3D game thats not really a game yet. But it has a SceneKit 3D scene and a overlayskscene for the HUD/Controls. the "base" is the base of the joystick and the ball is the handle the problem is that the joystick does not move at all unless the scnView.allowsCameraControl = true. I find that weird. and this is my entire view controller code so nothings left out and if you want you can literally copy and paste it into Xcode to see what I'm talking about. Any help? Code:

   import iAd
   import UIKit
   import GameKit
   import SceneKit
   import StoreKit
   import SpriteKit
   import QuartzCore
   import Foundation
   import AVFoundation
   import AudioToolbox

 class GameViewController: UIViewController, ADBannerViewDelegate, SKPhysicsContactDelegate, SKSceneDelegate, SCNSceneRendererDelegate, SCNPhysicsContactDelegate{

var stickActive:Bool = false

let base = SKSpriteNode(imageNamed:"VirtualJoystickBase")
let ball = SKSpriteNode(imageNamed:"VirtualJoyStickHandle")
let ship = SKSpriteNode(imageNamed:"Ship")

var ButtonA = SKSpriteNode(imageNamed:"GreenAButton")
var ButtonO = SKSpriteNode(imageNamed:"CircleButton")
var ButtonY = SKSpriteNode(imageNamed:"YellowYButton")
var ButtonSquare = SKSpriteNode(imageNamed:"BlueSquareButton")

let FieldScene = SCNScene(named: "art.scnassets/TesingCampusField.dae")!

let GuyScene = SCNScene(named: "art.scnassets/Guy.dae")!

let overlayScene = SKScene(size: CGSizeMake(100, 100))
override func viewDidLoad() {
    super.viewDidLoad()

    let scnView = self.view as! SCNView
    scnView.overlaySKScene = overlayScene
    scnView.backgroundColor = UIColor.whiteColor()
    scnView.scene = FieldScene
    scnView.delegate = self
    scnView.overlaySKScene!.delegate = self
    scnView.overlaySKScene!.anchorPoint = CGPointMake(0, 0)
    scnView.overlaySKScene!.physicsWorld.contactDelegate = self
    scnView.overlaySKScene!.physicsWorld.gravity = CGVectorMake(0.0, 0.0)
    scnView.allowsCameraControl = true
    scnView.showsStatistics = false

    let Guy1: SCNNode = GuyScene.rootNode.childNodeWithName("Bob_014", recursively: true)!
    FieldScene.rootNode.addChildNode(Guy1)

    //----Positioning-the-Base-of-the-Joystick-----------
    base.size = CGSize(width: 14, height: 24)
    base.position = CGPointMake(15, 19)
    base.zPosition = 0
    overlayScene.addChild(base)
    //----Positing-the-Ball/Joystick-----------
    ball.size = CGSize(width: 10, height: 17)
    ball.position = base.position
    ball.zPosition = 1
    overlayScene.addChild(ball)
    //----A-Button--Creation -------------------
    ButtonA.size = CGSize(width: 6, height: 9)
    ButtonA.anchorPoint = CGPointMake(-13.3, -0.5)
    ButtonA.zPosition = 0
    overlayScene.addChild(ButtonA)
    //----B-Button--Creation -------------------
    ButtonO.size = CGSize(width: 6, height: 9)
    ButtonO.anchorPoint = CGPointMake(-14.4, -1.7)
    ButtonO.zPosition = 0
    overlayScene.addChild(ButtonO)
    //----C-Button--Creation -------------------
    ButtonSquare.size = CGSize(width: 6, height: 9)
    ButtonSquare.anchorPoint = CGPointMake(-12.2, -1.7)
    ButtonSquare.zPosition = 0
    overlayScene.addChild(ButtonSquare)
    //----C-Button--Creation -------------------
    ButtonY.size = CGSize(width: 6, height: 9)
    ButtonY.anchorPoint = CGPointMake(-13.3, -2.7)
    ButtonY.zPosition = 0
    overlayScene.addChild(ButtonY)


    //---Setting-Up-Ships-Position/PhysicsBody---------------------
    ship.position = CGPointMake(0, 100)
    ship.size = CGSize(width: 80, height: 80)
    ship.physicsBody?.dynamic = true
    ship.physicsBody?.allowsRotation = true
    ship.physicsBody?.affectedByGravity = true
    ship.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "Ship"), size: ship.size)
    ship.physicsBody!.friction = 0
    ship.physicsBody!.restitution = 0
    ship.physicsBody!.linearDamping = 0
    ship.physicsBody!.angularDamping = 0


    //--------------------------
    let cameraNode = SCNNode()
    cameraNode.camera = SCNCamera()
    GuyScene.rootNode.addChildNode(cameraNode)
    cameraNode.position = SCNVector3(x: 0, y: 5, z: 15)
    //-----------------------------------------------
    let lightNode = SCNNode()
    lightNode.light = SCNLight()
    lightNode.light!.type = SCNLightTypeOmni
    lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
    FieldScene.rootNode.addChildNode(lightNode)
    //-----------------------------------------------
    let ambientLightNode = SCNNode()
    ambientLightNode.light = SCNLight()
    ambientLightNode.light!.type = SCNLightTypeAmbient
    ambientLightNode.light!.color = UIColor.darkGrayColor()
    FieldScene.rootNode.addChildNode(ambientLightNode)
    //----------------------------------------------
}

func YButtonPressed() {
    let YButtonPressed = SKTexture(imageNamed: "YellowYButtonPressed")
    let OrignalButtonY = SKTexture(imageNamed:"YellowYButton")
    let YButtonPressedAnimation = SKAction.animateWithTextures([YButtonPressed, OrignalButtonY], timePerFrame: 0.2)
    let RunYButtonPressedAnimation = SKAction.repeatAction(YButtonPressedAnimation, count: 1)
    ButtonY.runAction(RunYButtonPressedAnimation)

}
func OButtonPressed() {
    let OButtonPressed = SKTexture(imageNamed: "CircleButtonPressed")
    let OrignalButtonO = SKTexture(imageNamed:"CircleButton")
    let OButtonPressedAnimation = SKAction.animateWithTextures([OButtonPressed, OrignalButtonO], timePerFrame: 0.2)
    let RunOButtonPressedAnimation = SKAction.repeatAction(OButtonPressedAnimation, count: 1)
    ButtonO.runAction(RunOButtonPressedAnimation)

}
func SquareButtonPressed() {
    let SquareButtonPressed = SKTexture(imageNamed: "BlueSquareButtonPressed")
    let OrignalButtonSquare = SKTexture(imageNamed:"BlueSquareButton")
    let SquareButtonPressedAnimation = SKAction.animateWithTextures([SquareButtonPressed, OrignalButtonSquare], timePerFrame: 0.2)
    let RunSquareButtonPressedAnimation = SKAction.repeatAction(SquareButtonPressedAnimation, count: 1)
    ButtonSquare.runAction(RunSquareButtonPressedAnimation)

}
func AButtonPressed() {
    let AButtonPressed = SKTexture(imageNamed: "GreenAButtonPressed")
    let OrignalButtonA = SKTexture(imageNamed:"GreenAButton")
    let AButtonPressedAnimation = SKAction.animateWithTextures([AButtonPressed, OrignalButtonA], timePerFrame: 0.2)
    let RunAButtonPressedAnimation = SKAction.repeatAction(AButtonPressedAnimation, count: 1)
    ButtonA.runAction(RunAButtonPressedAnimation)

}

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    /* Called when a touch begins */
    for touch: AnyObject in touches  {
        let location = touch.locationInNode(self.overlayScene)
        if (CGRectContainsPoint(base.frame, location)) {
            print("stickActive = true")
            stickActive = true
        } else {
            print("stickActive = false")
            stickActive = false
        }
    }
    for touch: AnyObject in touches {
        let location1 = touch.locationInNode(self.overlayScene)
        if self.overlayScene.nodeAtPoint(location1) == self.ButtonA {
            AButtonPressed()
            print("AButtonPressed")
        }
    }
    for touch: AnyObject in touches {
        let location2 = touch.locationInNode(self.overlayScene)
        if self.overlayScene.nodeAtPoint(location2) == self.ButtonO {
            OButtonPressed()
            print("OButtonPressed")
        }
    }
    for touch: AnyObject in touches {
        let location3 = touch.locationInNode(self.overlayScene)
        if self.overlayScene.nodeAtPoint(location3) == self.ButtonY {
            YButtonPressed()
            print("YButtonPressed")
        }
    }
    for touch: AnyObject in touches {
        let location4 = touch.locationInNode(self.overlayScene)
        if self.overlayScene.nodeAtPoint(location4) == self.ButtonSquare {
            SquareButtonPressed()
            print("SquarButtonPressed")
        }
    }

}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {

    for touch: AnyObject in touches  {
        let location = touch.locationInNode(self.overlayScene)
        if self.overlayScene.nodeAtPoint(location) == self.ball {

        if (stickActive == true) {
            let v = CGVector(dx: location.x - base.position.x, dy: location.y - base.position.y)
            let angle = atan2(v.dy, v.dx)
            //println( deg + 180)
            let length:CGFloat = base.frame.size.height / 2
            let xDist:CGFloat = sin(angle - 1.57879633) * length
            let yDist:CGFloat = cos(angle - 1.57879633) * length

            if (CGRectContainsPoint(base.frame, location)) {
                ball.position = location

            } else {
                ball.position = CGPointMake( base.position.x - xDist, base.position.y + yDist)
            }

            ship.zRotation = angle - 1.57879633
            let calcRotation : Float = Float(angle - 1.57879633) + Float(M_PI_2);
            let intensity : CGFloat = 200.0 // put your value
            let xVelocity = intensity * CGFloat(cosf(calcRotation))
            let yVelocity = intensity * CGFloat(sinf(calcRotation))
            let vector : CGVector = CGVectorMake(xVelocity, yVelocity)
            //Apply force to spaceship
            ship.physicsBody?.applyForce(vector)
        // ends stackActive
        }
     }
   }
}

override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
    for touch: AnyObject in touches  {
        let location = touch.locationInNode(self.overlayScene)
        if self.overlayScene.nodeAtPoint(location) == self.ball {

    if (stickActive == true) {

        let move:SKAction = SKAction.moveTo(base.position, duration: 0.05)
        move.timingMode = .EaseOut

        ball.runAction(move)
   }
  }
 }
}
   //====================================================================
override func shouldAutorotate() -> Bool {
    return true
}
   //====================================================================
override func prefersStatusBarHidden() -> Bool {
    return true
}
   //====================================================================
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
        return .AllButUpsideDown
    } else {
        return .All
    }
}
   //====================================================================
override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Release any cached data, images, etc that aren't in use.
}

}

Solution

  • there's an issue in SceneKit where the SpriteKit overlay isn't automatically redrawn when changes are made in the 2D scene but the 3D scene is left untouched. In other words, the 2D overlay is only redrawn when the 3D view needs to be redrawn.

    You can set the playing property of the SCNView to YES to fix this. Alternatively you can call -setNeedsDisplay whenever you make a change to the overlay scene.