es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Puedo hacer que SCNBox sea táctil e interactivo?

Estoy tratando de crear un cubo giratorio con SCNBox en SwiftUI, donde se puede tocar cada lado del cubo y aparece una pantalla emergente / vista diferente con texto, etc. Tengo el cubo SCNBox giratorio, pero ¿cómo puedo hacerlo táctil e interactivo, y cómo puedo hacer que se redirija a otra vista?

Así es como actualmente estoy tratando de insertar la escena del cubo en una vista de SwiftUI, que luego se integraría en la jerarquía de vistas de una aplicación existente.

import SwiftUI
import SceneKit

class BoxNode: SCNNode {

    override init() {
        super.init()
        self.geometry = SCNBox(width: 1, height: 1, length: 1, chamferRadius: 0.0)
        self.geometry?.firstMaterial?.shininess = 50

        let action = SCNAction.rotate(by: 360 * CGFloat(Double.pi / 180), around: SCNVector3(x: 0, y: 1, z: 0), duration: 8)
        let repeatAction = SCNAction.repeatForever(action)

        self.runAction(repeatAction)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

struct BoxScene: View {
    var scene = SCNScene(named: "MyScene")

    var cameraNode: SCNNode? {
        scene?.rootNode.childNode(withName: "camera", recursively: false)
    }

    var boxNode: SCNNode? {
        scene?.rootNode.addChildNode(BoxNode())
    }

    var body: some View {
        SceneView(
            scene: scene,
            pointOfView: cameraNode,
            options: []
        )
    }
}

Sin embargo, este código no se compila. Dice “El tipo de expresión es ambiguo sin un contexto más claro” en la línea siguiente:

var boxNode: SCNNode? {
    scene?.rootNode.addChildNode(BoxNode())
}
Tags:  , ,

Answer

  1. Avatar for davy.ai

    Para hacer que el cubo giratorio sea táctil y redirigirlo a otra vista, debes agregar un reconocedor de gestos al SceneView en la estructura BoxScene. Aquí tienes una versión actualizada de la estructura BoxScene que incluye un reconocedor de gestos de toque y navegación a otra vista cuando se toca un lado del cubo:

    import SwiftUI
    import SceneKit
    
    class BoxNode: SCNNode {
    
        override init() {
            super.init()
            self.geometry = SCNBox(width: 1, height: 1, length: 1, chamferRadius: 0.0)
            self.geometry?.firstMaterial?.shininess = 50
    
            let action = SCNAction.rotate(by: 360 * CGFloat(Double.pi / 180), around: SCNVector3(x:0, y:1, z:0), duration: 8)
            let repeatAction = SCNAction.repeatForever(action)
    
            self.runAction(repeatAction)
        }
    
        required init?(coder: NSCoder) {
            fatalError("init(coder:) no ha sido implementado")
        }
    }
    
    struct BoxScene: View {
        var scene = SCNScene(named: "MyScene")
    
        var cameraNode: SCNNode? {
            scene?.rootNode.childNode(withName: "camera", recursively: false)
        }
    
        var boxNode: SCNNode? {
            scene?.rootNode.addChildNode(BoxNode())
        }
    
        @State private var showPopup = false
        @State private var popupText = ""
    
        var body: some View {
            let tapGesture = TapGesture()
                .onEnded { tap in
                    let location = tap.location(in: UIScreen.main.bounds)
                    let hitResults = self.scene?.hitTest(location, options: nil)
                    guard let result = hitResults?.first else { return }
                    self.showPopup = true
    
                    switch result.node.name {
                    case "front":
                        self.popupText = "Frente"
                    case "back":
                        self.popupText = "Atrás"
                    case "left":
                        self.popupText = "Izquierda"
                    case "right":
                        self.popupText = "Derecha"
                    case "top":
                        self.popupText = "Arriba"
                    case "bottom":
                        self.popupText = "Abajo"
                    default:
                        break
                    }
                }
    
            let popupView = PopupView(text: $popupText, isPresented: $showPopup)
    
            return ZStack {
                SceneView(scene: scene, pointOfView: cameraNode, options: [.allowsCameraControl])
                    .gesture(tapGesture)
                popupView
            }
        }
    }
    
    struct PopupView: View {
        @Binding var text: String
        @Binding var isPresented: Bool
    
        var body: some View {
            VStack {
                Text(text)
                Button("Cerrar") {
                    self.isPresented = false
                }
            }
            .frame(width: 200, height: 200)
            .background(Color.white)
            .cornerRadius(10)
            .opacity(isPresented ? 1 : 0)
            .animation(.easeInOut)
        }
    }
    

    En este código, hemos agregado un TapGesture al SceneView que llama a un método hitTest en el escenario para determinar qué lado del cubo se tocó. Luego establecemos la variable popupText en una cadena que corresponde al lado tocado y establecemos showPopup en true para mostrar el PopupView. El PopupView es una Vista simple que muestra un mensaje de texto y un botón de cierre. Cuando se toca el botón de cierre, showPopup se establece en false y se oculta el PopupView.

    Para usar esta BoxScene en tu aplicación, simplemente crea una instancia de la estructura BoxScene y añádela a la jerarquía de vistas:

    struct ContentView: View {
        var body: some View {
            BoxScene()
                .frame(width: 300, height: 300)
        }
    }
    

    Esto mostrará el cubo giratorio con interacciones táctiles y mensajes emergentes. Ten en cuenta que es posible que debas ajustar el tamaño del SceneView y del PopupView para adaptarlo a las necesidades de tu aplicación.

Comments are closed.