Hunter Hunter - 3 months ago 19
Swift Question

How to call a function that is defined in a different view controller?

I'm trying to call the function called "kick". Inside it is a CAAnimation that I am playing on this man I made. So usually I would just call the function in the same view controller as it was made in. But because I have a HUD/overlay scene the displays over my 3D game. And the HUD/overlayscene is made in a different view controller specifically just to set up the HUD I can't get the HUD view controller to Recognize any functions from the Main View Controller.

MainViewController:

Code:

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

var HUDView: HUD!

required init?(coder: NSCoder) {
super.init(coder: coder)
}

override func viewDidLoad() {
super.viewDidLoad()

//-----Scene-Setup----------
let scnView = self.view as! SCNView
scnView.scene = FieldScene
scnView.playing = true
scnView.loops = true
self.HUDView = HUD(size: CGSizeMake(100, 100))
scnView.overlaySKScene = self.HUDView
scnView.delegate = self
scnView.overlaySKScene!.delegate = self
scnView.overlaySKScene!.userInteractionEnabled = true
scnView.backgroundColor = UIColor.whiteColor()
scnView.allowsCameraControl = true
scnView.showsStatistics = false

let GuyScene = SCNScene(named: "art.scnassets/The1.dae")
let Guy: SCNNode = GuyScene!.rootNode.childNodeWithName("Armature", recursively: true)!
let GuyBody: SCNNode = GuyScene!.rootNode.childNodeWithName("Cube", recursively: true)!
//----Giveing it a physics---------
let collisionCapsuleRadius2 = CGFloat(0.1)
let collisionCapsuleHeight2 = CGFloat(0.1)
Guy.position = SCNVector3(x: -30.0, y: 30.0, z: 0.0)
Guy.scale = SCNVector3Make(50, 50, 50)
Guy.rotation = SCNVector4Make(0, 1, 0, 1 )
Guy.physicsBody = SCNPhysicsBody(type: .Dynamic, shape:SCNPhysicsShape(geometry: SCNCapsule(capRadius: collisionCapsuleRadius2, height: collisionCapsuleHeight2), options:nil))
Guy.physicsBody?.affectedByGravity = true
Guy.physicsBody?.friction = 0 //
Guy.physicsBody?.restitution = 1 //bounceness of the object
Guy.physicsBody?.angularDamping = 1 // rotationess
Guy.physicsBody?.mass = 1
Guy.physicsBody?.rollingFriction = 0
scnView.scene!.rootNode.addChildNode(Guy)
scnView.scene!.rootNode.addChildNode(GuyBody)
}

//Ok Kick function gets declared right here


func Kick() {
//-----Animate-Guy-----Working-Perfectly-----------
let KickAnimation = CAAnimation.animationWithSceneNamed("art.scnassets/The1Anima.dae")!
Guy.addAnimation(KickAnimation, forKey: "Go")
Guy.removeAnimationForKey("Go", fadeOutDuration: 3.0)
}


}

extension CAAnimation {
class func animationWithSceneNamed(name: String) -> CAAnimation? {
var animation: CAAnimation?
if let scene = SCNScene(named: name) {
scene.rootNode.enumerateChildNodesUsingBlock({ (child, stop) in
if child.animationKeys.count > 0 {
animation = child.animationForKey(child.animationKeys.first!)
stop.initialize(true)
}
})
}
return animation
}
}



//Ok Below is my HUD/Overlayscene which holds the button that i would like call the function in.


extension GameViewController {
// was never used
}

class HUD: SKScene {
//-----------------Controller-Buttons----------------------
var ButtonA = SKSpriteNode(imageNamed:"EnhancedAButton")

override init(size: CGSize) {
super.init(size: size)

//----A-Button--Creation -------------------
ButtonA.size = CGSize(width: 7, height: 11)
ButtonA.anchorPoint = CGPointMake(-11.35, -0.6)
ButtonA.zPosition = 0
ButtonA.alpha = 0.45
self.addChild(ButtonA)
}

required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}


//Ok here is the function I need to put "Kick()" inside it but when I do it doenst recognize it because the function wasnt declared in this view controller


func AButtonPressed() {

}

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
super.touchesBegan(touches, withEvent: event)
for touch: AnyObject in touches {
let location1 = touch.locationInNode(self)
if self.nodeAtPoint(location1) == self.ButtonA {
AButtonPressed()
print("AButtonPressed")
}
}
}
}


enter image description here

enter image description here

Answer

This is practically the best way to handle this. Other methods are messy while this is the most decoupled natural way to handle it. If you have any questions, let me know.

extension GameViewController: GameDelegate {
    func Kick() {
        //-----Animate-Guy-----Working-Perfectly-----------
        let KickAnimation = CAAnimation.animationWithSceneNamed("art.scnassets/The1Anima.dae")!
        Guy.addAnimation(KickAnimation, forKey: "Go")
        Guy.removeAnimationForKey("Go", fadeOutDuration: 3.0)
    }
}

protocol GameDelegate {
    func Kick()
}

class HUD: SKScene {

    var delegate: GameDelegate?

    override init(size: CGSize) {
        super.init(size: size)

        //this calls Kick anywhere in the HUD class
        delegate?.Kick()


        //----A-Button--Creation -------------------
        ButtonA.size = CGSize(width: 7, height: 11)
        ButtonA.anchorPoint = CGPointMake(-11.35, -0.6)
        ButtonA.zPosition = 0
        ButtonA.alpha = 0.45
        self.addChild(ButtonA)
    }
}

after the line that is inside of GameViewController's viewDidLoad()

//below this line
self.HUDView = HUD(size: CGSizeMake(100, 100))
//add in 
self.HUDView.delegate = self

After all of this, is added in, you can delete the copy of Kick that is not in the extension. Both controllers can access the function.