visionOS空间计算实战开发教程Day 6 拖拽和点击

简介: 在之前的学习中我们在空间中添加了3D模型,但在初始摆放后就无法再对其进行移动或做出修改。本节我们在Day 5显示和隐藏的基础上让我们模型可以实现拖拽效果,同时对纯色的立方体实现点击随机换色的功能。

在之前的学习中我们在空间中添加了3D模型,但在初始摆放后就无法再对其进行移动或做出修改。本节我们在Day 5显示和隐藏的基础上让我们模型可以实现拖拽效果,同时对纯色的立方体实现点击随机换色的功能。

首先是入口文件,无需做出改变,

import SwiftUI
@main
struct visionOSDemoApp: App {
    var body: some Scene {
        WindowGroup() {
            ContentView()
        }
        ImmersiveSpace(id: "ImmersiveSpace") {
            ImmersiveView()
        }
    }
}

接着是ViewModel.swift文件,这里是核心逻辑:

import SwiftUI
import RealityKit
class ViewModel: ObservableObject {
    private var contentEntity = Entity()
    private let colors: [SimpleMaterial.Color] = [.gray, .red, .orange, .yellow, .green, .blue, .purple, .systemPink]
    func setupContentEntity() -> Entity {
        return contentEntity
    }
    func addCube() -> Entity {
        let entity = ModelEntity(
            mesh: .generateBox(size: 0.5, cornerRadius: 0),
            materials: [SimpleMaterial(color: .red, isMetallic: false)],
            collisionShape: .generateBox(size: SIMD3<Float>(repeating: 0.5)),
            mass: 0.0
        )
        entity.components.set(InputTargetComponent(allowedInputTypes: .indirect))
        entity.position = SIMD3(x: 0, y: 1, z: -2)
        contentEntity.addChild(entity)
        return entity
    }
    func changeToRandomColor(entity: Entity) {
        guard let _entity = entity as? ModelEntity else { return }
        _entity.model?.materials = [SimpleMaterial(color: colors.randomElement()!, isMetallic: false)]
    }
}

这里增加了一个colors常量,用于设置一个包含多种颜色数组,以便进行随机颜色修改。颜色是通过SimpleMaterialcolor参数进行随机更换(randomElement),然后赋值给.materials属性,这部分逻辑位于changeToRandomColor中。

addCube的逻辑中,我们还是常规地生成一个entity并返回。

接着来到ImmersiveView

import SwiftUI
import RealityKit
struct ImmersiveView: View {
    @State var model = ViewModel()
    @State var cube = Entity()
    var body: some View {
        RealityView { content in
            content.add(model.setupContentEntity())
            cube = model.addCube()
        }
        .gesture(
            DragGesture()
                .targetedToEntity(cube)
                .onChanged { value in
                    cube.position = value.convert(value.location3D, from: .local, to: cube.parent!)
                }
        )
        .gesture(
            SpatialTapGesture()
                .targetedToEntity(cube)
                .onEnded { value in
                    model.changeToRandomColor(entity: cube)
                }
        )
    }
}

在这个视图中我们声明了cube变量,以便后续的拖拽和随机颜色修改操作。所以在初始化视图时将添加的立方体赋值给cube。然后分别通过DragGestureSpatialTapGesture来实现拖拽和点击的逻辑。

这里需要说明一个本例中生成的立方体在完成拖放,隐藏后再次展开后会生成一个新的供拖放和修改颜色的模型,这时老的模型就无法再进行拖放了。如果读者只希望操作同一个模型,可以对addCube添加了一个name参数,并添加一个getTargetEntity方法来获取该对象,当然也可以通过预设名称来切换不同的模型进行操作,示例修改如下:

func getTargeEntity(name: String) -> Entity? {
        return contentEntity.children.first { $0.name == name }
    }
    func addCube(name: String) -> Entity {
        if let entity = getTargeEntity(name: name) {
            return entity
        }
...
        entity.name = name
...

对应的ImmersiveView也要修改为类似cube = model.addCube("Cube1")

ContentView.swift的代码与Day 5一致:

import SwiftUI
import RealityKit
struct ContentView: View {
    @State var showImmsersiveSpace = false
    @Environment(\.openImmersiveSpace) var openImmersiveSpace
    @Environment(\.dismissImmersiveSpace) var dismissImmersiveSpace
    var body: some View {
        NavigationStack {
            VStack {
                Toggle("Show ImmersiveSpace", isOn: $showImmsersiveSpace)
                    .toggleStyle(.button)
            }
            .padding()
        }
        .onChange(of: showImmsersiveSpace) { _, newValue in
            Task {
                if newValue {
                    await openImmersiveSpace(id: "ImmersiveSpace")
                } else {
                    await dismissImmersiveSpace()
                }
            }
        }
    }
}

运行应用点击盒子会随机改变颜色,拖拽盒子会跟随鼠标的位置移动。

示例代码:GitHub仓库

其它相关内容请见虚拟现实(VR)/增强现实(AR)&visionOS开发学习笔记

相关文章
|
负载均衡 前端开发 应用服务中间件
Nginx的作用是什么?有什么用?
Nginx (engine x) 是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP服务器。Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Rambler.ru站点(俄文:Рамблер)开发的。由于其非常好用,渐渐被越来越多的人所接受。俄罗斯人的编程能力确实厉害。
497 0
|
消息中间件 分布式计算 大数据
【大数据技术Hadoop+Spark】Flume、Kafka的简介及安装(图文解释 超详细)
【大数据技术Hadoop+Spark】Flume、Kafka的简介及安装(图文解释 超详细)
796 0
|
JavaScript Java 关系型数据库
Springboot+vue的网上图书商城管理系统(有报告)。(购书➕借阅)Javaee项目,springboot vue前后端分离项目。
Springboot+vue的网上图书商城管理系统(有报告)。(购书➕借阅)Javaee项目,springboot vue前后端分离项目。
|
机器学习/深度学习 并行计算 PyTorch
优化技巧与策略:提高 PyTorch 模型训练效率
【8月更文第29天】在深度学习领域中,PyTorch 是一个非常流行的框架,被广泛应用于各种机器学习任务中。然而,随着模型复杂度的增加以及数据集规模的增长,如何有效地训练这些模型成为了一个重要的问题。本文将介绍一系列优化技巧和策略,帮助提高 PyTorch 模型训练的效率。
955 0
|
数据采集 监控 搜索推荐
使用 Python 爬虫进行网站流量分析:Referer 头的利用
使用 Python 爬虫进行网站流量分析:Referer 头的利用
|
SQL 资源调度 Java
mybatis-plus代码生成器的UI界面使用非常方便
mybatis-plus代码生成器的UI界面使用非常方便
270 0
|
机器学习/深度学习 自然语言处理 TensorFlow
使用Python实现深度学习模型:BERT模型教程
使用Python实现深度学习模型:BERT模型教程
1243 0
|
存储 缓存 NoSQL
软件体系结构 - 缓存技术(4)Redis分布式存储
【4月更文挑战第20天】软件体系结构 - 缓存技术(4)Redis分布式存储
203 12
【Echarts】Echarts 柱形图实现从右向左滚动
【Echarts】Echarts 柱形图实现从右向左滚动
398 0
|
测试技术 Swift 数据安全/隐私保护
【Swift开发专栏】Swift中的代码重构与模块化
【4月更文挑战第30天】本文探讨了Swift中代码重构和模块化的重要性,旨在提升项目质量。重构改善代码内部结构,提高可读性与可维护性,而模块化降低系统复杂性,增强代码复用。文章围绕代码重构的基本概念、模块化设计原则及Swift特性在两者中的应用展开,强调协议扩展、泛型、SPM和访问控制在实现重构和模块化中的作用。掌握这些技巧对构建高效、可扩展的Swift软件至关重要。
186 2