Swift Issue with SCNSceneRenderer ---Trouble getting protocol to work

214 views Asked by At

I'm working to implement a Zig Zag game and following a set of instructions from an on-line course. I have a swift UIViewController, and I am trying now to use also SCNSceneRenderer (to do the game logic of keeping the game character on the zig-zag path). The code looks like this:

import UIKit
import QuartzCore
import SceneKit

class GameViewController: UIViewController, SCNSceneRenderer{

    let scene = SCNScene()
    let cameraNode = SCNNode()

    var person = SCNNode()

    let firstBox = SCNNode()

    var goingLeft = Bool()

    var tempBox = SCNNode()
    var boxNumber = Int()
    var prevBoxNumber = Int()

    override func viewDidLoad() {
        print("Yes -- view did load")
        self.createScene()
    }

    func renderer(render: SCNSceneRenderer, updateAtTime time: TimeInterval){

        let deleteBox = self.scene.rootNode.childNode(withName: "\(prevBoxNumber)", recursively: true )

        if (deleteBox?.position.x)! > (person.position.x + 1) || (deleteBox?.position.z)! > (person.position.z + 1) {
            prevBoxNumber += 1
            deleteBox?.removeFromParentNode()

            createBox()
        }   
    }

    func createBox(){
        tempBox = SCNNode(geometry: firstBox.geometry)
        let prevBox = scene.rootNode.childNode(withName: "\(boxNumber)", recursively: true )

        boxNumber += 1
        tempBox.name = "\(boxNumber)"

        let randomNumber = arc4random() % 2
        switch randomNumber {
        case 0:
            tempBox.position = SCNVector3Make((prevBox?.position.x)! - firstBox.scale.x, (prevBox?.position.y)!, (prevBox?.position.z)!)
           break

        case 1:
            tempBox.position = SCNVector3Make((prevBox?.position.x)! , (prevBox?.position.y)!, (prevBox?.position.z)! - firstBox.scale.z)
            break

        default:
           break
        }

        self.scene.rootNode.addChildNode(tempBox)

    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

        if goingLeft == false  {
            person.removeAllActions()
            person.runAction(SCNAction.repeatForever(SCNAction.move(by: SCNVector3Make(-100, 0, 0), duration: 20)))
            goingLeft = true

        } else {
            person.removeAllActions()
            person.runAction(SCNAction.repeatForever(SCNAction.move(by: SCNVector3Make(0, 0, -100), duration: 20)))
            goingLeft = false    
    }

        print("boxNumber is \(boxNumber)")
    }




    func createScene(){
        boxNumber = 0
        prevBoxNumber = 0

        self.view.backgroundColor = UIColor.orange
        let sceneView = self.view as! SCNView
        sceneView.delegate = self
        sceneView.scene = scene

        //Create Person
        let personGeo = SCNSphere(radius: 0.2)
        person = SCNNode (geometry : personGeo)
        let personMat = SCNMaterial()
        personMat.diffuse.contents = UIColor.red
        personGeo.materials = [personMat]
        person.position = SCNVector3Make(0, 1.1, 0)
        scene.rootNode.addChildNode(person)


        //Create Camera
        cameraNode.camera = SCNCamera()
        cameraNode.camera?.usesOrthographicProjection = true
        cameraNode.camera?.orthographicScale = 3
        cameraNode.position = SCNVector3Make(20,20,20)
        cameraNode.eulerAngles = SCNVector3Make(-45,45,0)
        //let constraint = SCNLookAtConstraint(target: firstBox)
        let constraint = SCNLookAtConstraint(target: person)
        constraint.isGimbalLockEnabled = true
        self.cameraNode.constraints = [constraint]
        scene.rootNode.addChildNode(cameraNode)
        person.addChildNode(cameraNode)


        //Create Box
        let firstBoxGeo = SCNBox(width: 1.0, height: 1.5, length: 1.0, chamferRadius: 0)
        firstBox.geometry = firstBoxGeo
        let boxMaterial = SCNMaterial()
        boxMaterial.diffuse.contents = UIColor(red: 0.2, green: 0.8, blue: 0.9, alpha: 1.0)
        firstBoxGeo.materials = [boxMaterial]
        firstBox.position = SCNVector3Make(0,0,0)
        scene.rootNode.addChildNode(firstBox)
        firstBox.name = "\(boxNumber)"


        for _ in 0...6{
            createBox()
        }

        //Create light
        let light = SCNNode()
        light.light = SCNLight()
        light.light?.type = SCNLight.LightType.directional
        light.eulerAngles = SCNVector3Make(-45, 45, 0)
        scene.rootNode.addChildNode(light)

        //Create light2
        let light2 = SCNNode()
        light2.light = SCNLight()
        light2.light?.type = SCNLight.LightType.directional
        light2.eulerAngles = SCNVector3Make(45, 45, 0)
        scene.rootNode.addChildNode(light2)  

    }

}

When I added SCNSceneRenderer I get the following error:

"Type 'GameViewController' cannot conform to protocol 'SCNSceneRenderer' because it has requirements that cannot be satisfied"

Since my GameViewController isn't recognized as a SCNSceneRenderer, I also get an error at this line:

sceneView.delegate = self 

the error is "Cannot assign value of type 'GameViewController' to type 'SCNSceneRendererDelegate'

I'm new to swift programming, but this seems like I am trying to implement an interface like in Java, I've been looking at the Swift documentation but don't see what I need to do to make my class be functional as an SCNSceneRenderer. I would appreciate help to solve this problem. Thanks!

0

There are 0 answers