我正在RealityKit中创建一个应用程序,它根据用户输入生成形状.例如,如果用户输入的半径为0.1米,形状(在我的例子中为球体)的半径将为0.1米,0.2、0.3等的逻辑相同.代码都可以工作,但我想让它在用户点击屏幕时显示球体.

以下是我为接受用户输入的页面编写的代码:

class UserInput: ObservableObject {
    @Published var score: Float = 0.0
}


struct PreviewView: View {
    @ObservedObject var input = UserInput()
    var body: some View {
        NavigationView {
            ZStack {
                Color.black
            
            VStack {
                Text("Change the radius of your AR sphere")
                    .foregroundColor(.white)
                Text("\(String(format: "%.1f", self.input.score)) meters")
                    .foregroundColor(.white)
                    .bold()
                    .font(.title)
                    .padding(10)
                Button(action: {self.input.score += 0.1})
                    {
                        Text("Increment by 0.1 meters")
                    }
                    .padding(10)
                
                Button(action: {self.input.score -= 0.1})
                    {
                        Text("Decrease by 0.1 meters")
                    }
                    .padding(10)
                NavigationLink(destination: Reality(input: self.input)) {
                    Text("View in AR")
                        .bold()
                        .padding(.top,30)
                }
            }
        }
        .ignoresSafeArea()
    }
}

以下是Reality ARView的代码:

struct Reality: UIViewRepresentable {
    @ObservedObject var input: UserInput
    func makeUIView(context: Context) -> ARView {
        let arView = ARView(frame: .zero)
        let model = ModelEntity(mesh: .generateSphere(radius: input.score))
        let anchor = AnchorEntity(plane: .horizontal)
        anchor.addChild(model)
        arView.scene.anchors.append(anchor)
        return arView
    }
    func updateUIView(_ uiView: ARView, context: Context) {}
}

当用户touch 屏幕时生成形状的例子有很多,这不是我的问题.我正在接受用户输入的事实使这一点变得困难.

以下是一些代码,它们可以执行我想要的操作,但不需要用户输入.它有一些内置的物理特性,我计划在用户输入开始工作后实现这些特性.

struct ARViewContainer: UIViewRepresentable {
    
    func makeUIView(context: Context) -> ARView {
        
        let arView = ARView(frame: .zero)
        
        let planeAnchorEntity = AnchorEntity(plane: .horizontal)
        let plane = ModelEntity(mesh: MeshResource.generatePlane(width: 1, depth: 1), materials: [SimpleMaterial(color: .white, isMetallic: true)])
        plane.physicsBody = PhysicsBodyComponent(massProperties: .init(mass: 1), material: .generate(friction: 1, restitution: 1), mode: .kinematic)
        plane.generateCollisionShapes(recursive: true)
        
        planeAnchorEntity.addChild(plane)
        arView.scene.anchors.append(planeAnchorEntity)
        
        arView.installGestures([.scale,.rotation], for: plane)
        arView.addGestureRecognizer(UITapGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.handleTap)))
        
        context.coordinator.view = arView
        
        return arView
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator()
    }
    
    func updateUIView(_ uiView: ARView, context: Context) {}
}

下面是生成我想要在大小上可调的框的协调器类:

class Coordinator {
    
    weak var view: ARView?
    
    @objc func handleTap(_ recognizer: UITapGestureRecognizer) {
        
        guard let view = view else { return }
        let location =  recognizer.location(in: view)
        
        let results = view.raycast(from: location, allowing: .estimatedPlane, alignment: .horizontal)
        
        if let result = results.first {
            
           let anchorEntity = AnchorEntity(raycastResult: result)
            let box = ModelEntity(mesh: MeshResource.generateBox(size: 0.3),materials: [SimpleMaterial(color: .black, isMetallic: true)])
            box.physicsBody = PhysicsBodyComponent(massProperties: .init(mass: 0.5), material: .generate(), mode: .dynamic)
            box.generateCollisionShapes(recursive: true)
            
            box.position = simd_make_float3(0,0.7,0)
            //static means body cannot be moved
            //dynamic means it can move
            //kinematic means user moved the object
            anchorEntity.addChild(box)
            view.scene.anchors.append(anchorEntity)
        }
    }
}

我试着将这两个项目融合成我想要的,但我得到了各种各样的错误,我不知道如何修复,当我try 新的东西时,出现了一堆其他错误.我认为这可以归结为@ObservedObject,以及我有多个类/ struct 将我的项目与用户输入进行比较的事实.用户输入将进入协调器类,但最终是ARViewContainer实际呈现视图.

如果有人能帮我,我将不胜感激.

推荐答案

要增加/减小球体的半径,然后通过点击定位球体,请使用以下代码.

现在,有了工作按钮和协调器,实现光线投射将容易得多.

import SwiftUI
import RealityKit

struct ContentView : View {
    var body: some View {
        PrevView().ignoresSafeArea()
    }
}

Reality个视点.

struct Reality: UIViewRepresentable {
    
    @Binding var input: Float
    let arView = ARView(frame: .zero)

    class ARCoordinator: NSObject {
        var manager: Reality
        
        init(_ manager: Reality) {
            self.manager = manager
            super.init()

            let recognizer = UITapGestureRecognizer(target: self,
                                                    action: #selector(tapped))
            manager.arView.addGestureRecognizer(recognizer)
        }
                                        
        @objc func tapped(_ recognizer: UITapGestureRecognizer) {

            if manager.arView.scene.anchors.isEmpty {
                let model = ModelEntity(mesh: .generateSphere(radius: 
                                                               manager.input))
                let anchor = AnchorEntity(world: [0, 0,-2])
                // later use AnchorEntity(world: result.worldTransform)
                anchor.addChild(model)
                manager.arView.scene.anchors.append(anchor)
            }
        }
    }
    func makeCoordinator() -> ARCoordinator { ARCoordinator(self) }
    func makeUIView(context: Context) -> ARView { return arView }
    func updateUIView(_ uiView: ARView, context: Context) { }
}

PrevView个视点.

struct PrevView: View {

    @State private var input: Float = 0.0

    var body: some View {
        NavigationView {
            ZStack {
                Color.black 
                VStack {
                    Text("\(String(format: "%.1f", input)) meters")
                        .foregroundColor(.yellow)
                    HStack {
                        Spacer()
                        Button(action: { $input.wrappedValue -= Float(0.1) }) {
                            Text("Decrease").foregroundColor(.red)
                        }
                        Spacer()
                        Button(action: { $input.wrappedValue += Float(0.1) }) {
                            Text("Increase").foregroundColor(.red)
                        }
                        Spacer()
                    }
                    NavigationLink(destination: Reality(input: $input)
                                                          .ignoresSafeArea()) {
                        Text("View in AR")
                    }
                }
            }.ignoresSafeArea()
        }
    }
}

Swift相关问答推荐

自定义完整屏幕封面动画

SWIFT中MAP的静态方法包装器

如何在自定义视图中读取修改符子元素?

按SWIFT中每个ID的最大值进行筛选/排序

如何使用AsyncTimerSequence获取初始时钟,然后在指定的时间间隔内开始迭代?

如何将新事例添加到枚举中?

UIView.convert(_ point:to:)的意外行为

SwiftUI路径平滑连接两条线

除法中如果除以完全因数需要更长时间吗?

设备上ScrollView为什么会将内容高度更改为随机值,而在预览上不会? - 优化后的标题:设备上ScrollView内容高度随机变化问题解决

自定义碰撞形状出现在错误的位置

SwiftUI 分段 Select 器的问题

SwiftUI Preview 不适用于 Core Data

AES 加密和解密

从 NSData 对象在 Swift 中创建一个数组

在 UItextfield 的右视图上添加一个按钮,文本不应与按钮重叠

两个 Date 对象之间的所有日期 (Swift)

在 Swift 中指定 UITextField 的边框半径

迭代 Firebase 中的子快照

Swift 中的单元测试致命错误