How to use “*.scnp” file in SwiftUI for button click (iOS)?

风格不统一 提交于 2021-02-08 05:56:06

问题


I have "Explode.scnp" SceneKit file. It's already configured, the texture has been set.

How we can use it in SwiftUI? For example, after the button clicks the background will be animated once.

var body: some View {
    ZStack {
            VStack {
                Button(action: {
                  Particles()
                }) { 
                  Text("Animate")
                }
            }
     }
}

This code works for scn. but how to use it with scnp?

import SwiftUI
import SceneKit

struct ScenekitView : UIViewRepresentable {
    let scene = SCNScene(named: "art.scnassets/ship.scn")!

    func makeUIView(context: Context) -> SCNView {
        // create and add a camera to the scene
        let cameraNode = SCNNode()
        cameraNode.camera = SCNCamera()
        scene.rootNode.addChildNode(cameraNode)

        // place the camera
        cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)

        // create and add a light to the scene
        let lightNode = SCNNode()
        lightNode.light = SCNLight()
        lightNode.light!.type = .omni
        lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
        scene.rootNode.addChildNode(lightNode)

        // create and add an ambient light to the scene
        let ambientLightNode = SCNNode()
        ambientLightNode.light = SCNLight()
        ambientLightNode.light!.type = .ambient
        ambientLightNode.light!.color = UIColor.darkGray
        scene.rootNode.addChildNode(ambientLightNode)

        // retrieve the ship node
        let ship = scene.rootNode.childNode(withName: "ship", recursively: true)!

        // animate the 3d object
        ship.runAction(SCNAction.repeatForever(SCNAction.rotateBy(x: 0, y: 2, z: 0, duration: 1)))

        // retrieve the SCNView
        let scnView = SCNView()
        return scnView
    }

    func updateUIView(_ scnView: SCNView, context: Context) {
        scnView.scene = scene

        // allows the user to manipulate the camera
        scnView.allowsCameraControl = true

        // show statistics such as fps and timing information
        scnView.showsStatistics = true

        // configure the view
        scnView.backgroundColor = UIColor.black
    }
}

#if DEBUG
struct ScenekitView_Previews : PreviewProvider {
    static var previews: some View {
        ScenekitView()
    }
}
#endif

Moreover, Xcode version is 11.3.1. When I try to create a new file I have this:

And the extension is SKS... any ideas?

Reworked the code according to @Asperi version:

import SwiftUI
import SceneKit

struct ScenekitView : UIViewRepresentable {
    @Binding var exploding: Bool
    //let scene = SCNScene(named: "SceneKit.scnassets/Explode.scnp")!
    let scene = SCNScene(named: "SceneKit.scnassets/scene.scn")!

    func makeUIView(context: Context) -> SCNView {
        // create and add a camera to the scene
        let cameraNode = SCNNode()
        cameraNode.camera = SCNCamera()
        scene.rootNode.addChildNode(cameraNode)

        // place the camera
        cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)

        // create and add a light to the scene
        let lightNode = SCNNode()
        lightNode.light = SCNLight()
        lightNode.light!.type = .omni
        lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
        scene.rootNode.addChildNode(lightNode)

        // create and add an ambient light to the scene
        let ambientLightNode = SCNNode()
        ambientLightNode.light = SCNLight()
        ambientLightNode.light!.type = .ambient
        ambientLightNode.light!.color = UIColor.darkGray
        scene.rootNode.addChildNode(ambientLightNode)

        // retrieve the ship node
        let ship = scene.rootNode.childNode(withName: "blow", recursively: true)!

        // animate the 3d object
        ship.runAction(SCNAction.repeatForever(SCNAction.rotateBy(x: 0, y: 2, z: 0, duration: 1)))

        // retrieve the SCNView
        let scnView = SCNView()
        return scnView
    }

    func updateUIView(_ scnView: SCNView, context: Context) {
        scnView.scene = scene

        // allows the user to manipulate the camera
        scnView.allowsCameraControl = true

        // show statistics such as fps and timing information
        scnView.showsStatistics = true

        // configure the view
        scnView.backgroundColor = UIColor.black

        if exploding {
            if let scene = scene.rootNode.childNode(withName: "SceneKit.scnassets/scene", recursively: false),
                let particles = SCNParticleSystem(named: "SceneKit.scnassets/Explode", inDirectory: nil) {

                let node = SCNNode()
                node.addParticleSystem(particles)
                node.position = scene.position
                scnView.scene?.rootNode.addChildNode(node)
                scene.removeFromParentNode()
            }
        }
    }
}

Errors related to the path names ...

// retrieve the ship node

here. Tried .sks, .scnp ... any ideas?


回答1:


Here is modified code with demo. Tested with Xcode 11.4 / macOS 10.15.4

Note: as I don't know your project structure, all dependent resource files were added as Resources (not in Assets). Just in case.

struct DemoSceneKitParticles: View {
    @State private var exploding = false
    var body: some View {
        VStack {
            ScenekitView(exploding: $exploding)
            Button("BOOM") { self.exploding = true }
        }
    }
}

struct ScenekitView : NSViewRepresentable {
    @Binding var exploding: Bool
    let scene = SCNScene(named: "ship.scn")!

    func makeNSView(context: NSViewRepresentableContext<ScenekitView>) -> SCNView {
        // create and add a camera to the scene
        let cameraNode = SCNNode()
        cameraNode.camera = SCNCamera()
        scene.rootNode.addChildNode(cameraNode)

        // place the camera
        cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)

        // create and add a light to the scene
        let lightNode = SCNNode()
        lightNode.light = SCNLight()
        lightNode.light!.type = .omni
        lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
        scene.rootNode.addChildNode(lightNode)

        // create and add an ambient light to the scene
        let ambientLightNode = SCNNode()
        ambientLightNode.light = SCNLight()
        ambientLightNode.light!.type = .ambient
        ambientLightNode.light!.color = NSColor.darkGray
        scene.rootNode.addChildNode(ambientLightNode)

        // retrieve the ship node
        let ship = scene.rootNode.childNode(withName: "ship", recursively: true)!

        // animate the 3d object
        ship.runAction(SCNAction.repeatForever(SCNAction.rotateBy(x: 0, y: 2, z: 0, duration: 1)))

        // retrieve the SCNView
        let scnView = SCNView()
        return scnView
    }

    func updateNSView(_ scnView: SCNView, context: Context) {
        scnView.scene = scene

        // allows the user to manipulate the camera
        scnView.allowsCameraControl = true

        // show statistics such as fps and timing information
        scnView.showsStatistics = true

        // configure the view
        scnView.backgroundColor = NSColor.black

        if exploding {
            if let ship = scene.rootNode.childNode(withName: "ship", recursively: true),
                let particles = SCNParticleSystem(named: "Explosion", inDirectory: nil) {

                let node = SCNNode()
                node.addParticleSystem(particles)
                node.position = ship.position
                scnView.scene?.rootNode.addChildNode(node)
                ship.removeFromParentNode()
            }
        }
    }
}

Update: variant for iOS

Tested with Xcode 11.4 / iOS 13.4

Full module code (resource files as before at top level)

import SwiftUI
import SceneKit

struct DemoSceneKitParticles: View {
    @State private var exploding = false
    var body: some View {
        VStack {
            ScenekitView(exploding: $exploding)
            Button("BOOM") { self.exploding = true }
        }
    }
}

struct ScenekitView : UIViewRepresentable {
    @Binding var exploding: Bool
    let scene = SCNScene(named: "ship.scn")!

    func makeUIView(context: Context) -> SCNView {
        // create and add a camera to the scene
        let cameraNode = SCNNode()
        cameraNode.camera = SCNCamera()
        scene.rootNode.addChildNode(cameraNode)

        // place the camera
        cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)

        // create and add a light to the scene
        let lightNode = SCNNode()
        lightNode.light = SCNLight()
        lightNode.light!.type = .omni
        lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
        scene.rootNode.addChildNode(lightNode)

        // create and add an ambient light to the scene
        let ambientLightNode = SCNNode()
        ambientLightNode.light = SCNLight()
        ambientLightNode.light!.type = .ambient
        ambientLightNode.light!.color = UIColor.darkGray
        scene.rootNode.addChildNode(ambientLightNode)

        // retrieve the ship node
        let ship = scene.rootNode.childNode(withName: "ship", recursively: true)!

        // animate the 3d object
        ship.runAction(SCNAction.repeatForever(SCNAction.rotateBy(x: 0, y: 2, z: 0, duration: 1)))

        // retrieve the SCNView
        let scnView = SCNView()
        return scnView
    }

    func updateUIView(_ scnView: SCNView, context: Context) {
        scnView.scene = scene

        // allows the user to manipulate the camera
        scnView.allowsCameraControl = true

        // show statistics such as fps and timing information
        scnView.showsStatistics = true

        // configure the view
        scnView.backgroundColor = UIColor.black

        if exploding {
            if let ship = scene.rootNode.childNode(withName: "ship", recursively: true),
                let particles = SCNParticleSystem(named: "Explosion", inDirectory: nil) {

                let node = SCNNode()
                node.addParticleSystem(particles)
                node.position = ship.position
                scnView.scene?.rootNode.addChildNode(node)
                ship.removeFromParentNode()
            }
        }
    }
}

struct DemeSKParticles_Previews: PreviewProvider {
    static var previews: some View {
        DemoSceneKitParticles()
    }
}


来源:https://stackoverflow.com/questions/62046891/how-to-use-scnp-file-in-swiftui-for-button-click-ios

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!