James Castrejon
James Castrejon

Reputation: 645

Coordinator is not working for UIViewRepresentable?

Maybe I don't understand UIViewRepresentable correctly but I thought this would work.

I'm trying to use two classes that are UIViewRepresentable to display my scnkit scenes in SwiftUI. I also use two coordinator methods for the classes, one each. The coordinator has access to the rendering and physicsWorld methods for the current scene.

The player spawns in the first scene and when contact is made with an enemy, it transitions into the second scene. Here is where the problem starts, it doesn't let the second coordinator handle the physicsWorld and rendering methods for the second class.

I believe it's because I'm still using the first class in swiftui and not the second even though the scene changes. Or in other words, I'm changing scenes but not the class being used.

The Question: How can I transition from the first class to the second and/or from the first scene to the other and still have the coordinator active for each.

Here is the First Class.

struct FirstClass : UIViewRepresentable {

    var view = SCNView()
    var scene = SCNScene(named: "First.scn")!

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    func makeUIView(context: Context) -> SCNView {
        scene.physicsWorld.contactDelegate = context.coordinator
        view.delegate = context.coordinator
        return view
    }

    ...

    /// Transitions into the second scene.
    func changeScenes() {
        controlManager.jumped = false
        let transition = SKTransition.fade(with: .black, duration: 0.5)
        let secondClass = SecondClass()
         view.present(secondClass.scene, with: transition, incomingPointOfView: nil)
    }
}

Here is the Second Class

struct SecondClass : UIViewRepresentable {

    var view = SCNView()
    var scene = SCNScene(named: "Second.scn")!

    func makeCoordinator() -> SecondCoordinator {
        SecondCoordinator(self)
    }

    func makeUIView(context: Context) -> SCNView {
        scene.physicsWorld.contactDelegate = context.coordinator
        view.delegate = context.coordinator
        return view
    }
}

Here is the SwiftUI Class

struct Game: View {

    var view = FirstClass()

    var body: some View {
        ZStack {
            view
            
            ...
        }
    }
}

Upvotes: 0

Views: 1043

Answers (2)

sergey mishunin
sergey mishunin

Reputation: 11

Coordinator in UIViewRepresentable is to be used like delegate. You are not only write:

func makeCoordinator() -> Coordinator {
    Coordinator(self)
}

Declare your Coordinator and make conformance you need. Don't forget to attach delegate in makeUIView:

myView.delegate = context.coordinator 

Upvotes: 0

Cristik
Cristik

Reputation: 32873

This part let secondClass = SecondClass() won't work, because SwiftUI is not aware about the instance of SecondClass, in order to properly manage its lifecycle. More, you don't seem to use view property of the SecondClass struct (btw, interesting name for a struct :) )

One solution is to manage both scenes within the same UIViewRepresentable, basically keeping the lifecycle management on the same side.

struct MyScene : UIViewRepresentable {

    var view = SCNView()
    var firstScene = SCNScene(named: "First.scn")!
    lazy var secondScene = SCNScene(named: "Second.scn")!

    ...

    /// Transitions into the second scene.
    func changeScenes() {
        controlManager.jumped = false
        let transition = SKTransition.fade(with: .black, duration: 0.5)
        view.present(secondScene, with: transition, incomingPointOfView: nil)
    }
}

Upvotes: 0

Related Questions