在之前的學習中我們在空間中添加了3D模型,但在初始擺放后就無法再對其進行移動或做出修改。本節我們在??Day 5??顯示和隱藏的基礎上讓我們模型可以實現拖拽效果,同時對純色的立方體實現點擊隨機換色的功能。
首先是入口文件,無需做出改變,
import SwiftUI@main
struct visionOSDemoApp: App {var body: some Scene {WindowGroup() {ContentView()}ImmersiveSpace(id: "ImmersiveSpace") {ImmersiveView()}}
}
接著是??ViewModel.swift?
?文件,這里是核心邏輯:
import SwiftUI
import RealityKitclass 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?
??常量,用于設置一個包含多種顏色數組,以便進行隨機顏色修改。顏色是通過??SimpleMaterial?
??的??color?
??參數進行隨機更換(??randomElement?
??),然后賦值給??.materials?
??屬性,這部分邏輯位于??changeToRandomColor?
?中。
在??addCube?
??的邏輯中,我們還是常規地生成一個??entity?
?并返回。
接著來到??ImmersiveView?
?:
import SwiftUI
import RealityKitstruct ImmersiveView: View {@State var model = ViewModel()@State var cube = Entity()var body: some View {RealityView { content incontent.add(model.setupContentEntity())cube = model.addCube()}.gesture(DragGesture().targetedToEntity(cube).onChanged { value incube.position = value.convert(value.location3D, from: .local, to: cube.parent!)}).gesture(SpatialTapGesture().targetedToEntity(cube).onEnded { value inmodel.changeToRandomColor(entity: cube)})}
}
在這個視圖中我們聲明了??cube?
??變量,以便后續的拖拽和隨機顏色修改操作。所以在初始化視圖時將添加的立方體賦值給??cube?
??。然后分別通過??DragGesture?
??和??SpatialTapGesture?
?來實現拖拽和點擊的邏輯。
這里需要說明一個本例中生成的立方體在完成拖放,隱藏后再次展開后會生成一個新的供拖放和修改顏色的模型,這時老的模型就無法再進行拖放了。如果讀者只希望操作同一個模型,可以對??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 RealityKitstruct ContentView: View {@State var showImmsersiveSpace = false@Environment(\.openImmersiveSpace) var openImmersiveSpace@Environment(\.dismissImmersiveSpace) var dismissImmersiveSpacevar body: some View {NavigationStack {VStack {Toggle("Show ImmersiveSpace", isOn: $showImmsersiveSpace).toggleStyle(.button)}.padding()}.onChange(of: showImmsersiveSpace) { _, newValue inTask {if newValue {await openImmersiveSpace(id: "ImmersiveSpace")} else {await dismissImmersiveSpace()}}}}
}
運行應用點擊盒子會隨機改變顏色,拖拽盒子會跟隨鼠標的位置移動。
示例代碼:??GitHub倉庫?https://github.com/alanhou/ARDemo/tree/main/visionOS/Day6
其它相關內容請見??虛擬現實(VR)/增強現實(AR)&visionOS開發學習筆記?https://alanhou.org/augmented-reality/?