[MACRO] AR-Kit Code Keep
2022. 11. 7. 02:40ใ์นดํ ๊ณ ๋ฆฌ ์์
1. UniverseSearchViewController+DataSource.swift
//
// UniverseSearchViewController+DataSource.swift
// Tars
//
// Created by ๊น์ํ on 2022/11/04.
//
import UIKit
extension UniverseSearchViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return planetList.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: SelectPlanetCollectionViewCell.identifier, for: indexPath) as? SelectPlanetCollectionViewCell
else { return UICollectionViewCell() }
// reusable cell init
cell.backgroundView = nil
cell.planetNameLabel.textColor = .white
let selectedPlanetName = planetList[indexPath.row].planetName
let selectedPlanetImage = planetList[indexPath.row].planetImage
cell.planetNameLabel.text = selectedPlanetName
cell.planetImageView.image = selectedPlanetImage
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard let cell = collectionView.cellForItem(at: indexPath) as? SelectPlanetCollectionViewCell else { return }
// dequeueReusableCell -> cellForItem ์ผ๋ก ๋ณ๊ฒฝํ๋ ์ ์ ์ฉ๋จ! :)
// ๋์ ์ฐจ์ด ์ ๋๋ก ์กฐ์ฌํด์ ์ ๋ฆฌํ๊ธฐ (cell์ ํน์ ํ์ง ๋ชปํ๋ค๋ ํฌ์ธํธ)
// let selectedPlanet = planetList[indexPath.row]
if cell.isSelected {
DispatchQueue.main.async {
cell.planetNameLabel.textColor = .black
cell.backgroundView = cell.planetBackgroundView
self.navigationController?.navigationItem.title = "์ฒ์ฒด ํ์ ์ค"
self.navigationController?.navigationBar.backgroundColor = .systemYellow
}
}
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
if let cell = collectionView.cellForItem(at: indexPath) as? SelectPlanetCollectionViewCell {
cell.planetNameLabel.textColor = .white
cell.backgroundView = nil
}
}
}
2. UniverseSearchViewController.swift
//
// UniverseSearchViewController.swift
// Tars
//
// Created by ๊น์ํ on 2022/11/02.
//
import UIKit
import SceneKit
import ARKit
class UniverseSearchViewController: UIViewController, ARSCNViewDelegate, LocationManagerDelegate {
public var guideCircleView = CustomCircleView()
public var selectedSquareView = CustomSquareView()
let contentsViewController = ContentsViewController()
var planetObjectList: [SCNNode] = []
let searchGuideLabel: UILabel = {
let label: UILabel = UILabel()
label.text = "๋น ๋ฅด๊ฒ ์ฒ์ฒด ์ฐพ๊ธฐ"
label.textColor = .white
label.textAlignment = .center
label.font = UIFont.systemFont(ofSize: 20, weight: .semibold)
return label
}()
public let selectPlanetCollectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = screenWidth * 0.05
layout.minimumInteritemSpacing = CGFloat(UInt16.max)
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.register(SelectPlanetCollectionViewCell.self,
forCellWithReuseIdentifier: SelectPlanetCollectionViewCell.identifier)
collectionView.contentInset = UIEdgeInsets(top: 0, left: screenWidth * 0.09, bottom: 0, right: screenWidth * 0.09)
collectionView.showsHorizontalScrollIndicator = true
collectionView.backgroundColor = .black
return collectionView
}()
/// ARKit ์ ์ฌ์ฉํ๊ธฐ ์ํ view ์ ์ธ
lazy var sceneView: ARSCNView = {
let sceneView = ARSCNView()
sceneView.delegate = self
return sceneView
}()
override func viewDidLoad() {
super.viewDidLoad()
selectPlanetCollectionView.delegate = self
selectPlanetCollectionView.dataSource = self
[guideCircleView, sceneView, selectedSquareView, searchGuideLabel, selectPlanetCollectionView].forEach { view.addSubview($0) }
sceneView.addSubview(guideCircleView)
configureConstraints()
selectedSquareView.isHidden = true
view.bringSubviewToFront(searchGuideLabel)
let locationManager = LocationManager.shared
locationManager.delegate = self
locationManager.updateLocation()
}
/// ํ์ฑ์ ๋ฆฌ์คํธ์ ์ ์ฅํ๊ธฐ ์ํ ํจ์
private func getPlanetNodeList(planets: [Body]) {
for planet in planets {
if planet.name != "Earth" && planet.name != "Pluto" {
let sphere = SCNSphere(radius: 0.2)
let sphereNode = SCNNode(geometry: sphere)
sphereNode.position = SCNVector3(planet.coordinate.x, planet.coordinate.y, planet.coordinate.z)
planetObjectList.append(sphereNode)
}
}
}
/// ํ์ฑ์ ๋ฐฐ์นํ๊ธฐ ์ํ ํจ์
private func setPlanetPosition(to scene: SCNScene?, planets: [Body]) {
for planet in planets {
if planet.name == "Earth" || planet.name == "Pluto" {
continue
} else {
let sphere = SCNSphere(radius: 0.2)
sphere.firstMaterial?.diffuse.contents = UIImage(named: planet.name + "_Map")
let sphereNode = SCNNode(geometry: sphere)
sphereNode.position = SCNVector3(planet.coordinate.x, planet.coordinate.y, planet.coordinate.z)
scene?.rootNode.addChildNode(sphereNode)
}
}
}
// TODO: ํ์ฑ ์ ํ ์, ๋ค๋น๊ฒ์ด์
ํจ๊ณผ ์ฝ์
// hit_test๋ก ํ์ฉ: vivi
private func configureConstraints() {
sceneView.anchor(top: view.topAnchor, leading: view.leadingAnchor, bottom: view.bottomAnchor, trailing: view.trailingAnchor)
selectedSquareView.centerX(inView: sceneView)
selectedSquareView.centerY(inView: sceneView)
guideCircleView.centerX(inView: view)
guideCircleView.anchor(top: view.topAnchor, paddingTop: screenHeight * 0.23)
searchGuideLabel.centerX(inView: view)
searchGuideLabel.anchor(top: view.topAnchor, paddingTop: screenHeight * 0.7)
selectPlanetCollectionView.anchor(top: view.topAnchor, paddingTop: screenHeight * 0.68)
selectPlanetCollectionView.setHeight(height: screenHeight * 0.35)
selectPlanetCollectionView.setWidth(width: screenWidth)
selectPlanetCollectionView.centerX(inView: view)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.isNavigationBarHidden = false
DispatchQueue.main.async {
self.navigationController?.navigationItem.title = "์ฐ์ฃผ ๋๋ฌ๋ณด๊ธฐ"
self.navigationController?.navigationBar.tintColor = .white
self.navigationController?.navigationBar.backgroundColor = .black
}
let configuration = ARWorldTrackingConfiguration()
configuration.worldAlignment = .gravityAndHeading
sceneView.session.run(configuration)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
sceneView.session.pause()
}
// MARK: - ARSCNViewDelegate
func session(_ session: ARSession, didFailWithError error: Error) {
// Present an error message to the user
}
func sessionWasInterrupted(_ session: ARSession) {
// Inform the user that the session has been interrupted, for example, by presenting an overlay
}
func sessionInterruptionEnded(_ session: ARSession) {
// Reset tracking and/or remove existing anchors if consistent tracking is required
}
// MARK: - LocationManagerDelegate
func didUpdateUserLocation() {
Task {
let bodies = try await AstronomyAPIManager().requestBodies()
setPlanetPosition(to: sceneView.scene, planets: bodies)
getPlanetNodeList(planets: bodies)
}
}
}
3. Hittest result
/// hitTest ๊ฐ์ฒด(ํ์ฑ ๋
ธ๋)๋ฅผ ์ธ์ํ๋ ํจ์
@objc func handleTap(sender: UITapGestureRecognizer) {
let sceneViewTappdeOn = sender.view as! SCNView
let touchCoordinates = sender.location(in: sceneViewTappdeOn)
let hitTest = sceneViewTappdeOn.hitTest(touchCoordinates)
if hitTest.isEmpty {
print("didn't touch anything")
} else {
let results = hitTest.first!
let geometry = results.node.geometry
print(geometry?.firstMaterial?.diffuse.contents)
let node = results.node
print(node)
}
}
# viewDidLoad ์ ๋ ์ค ์ถ๊ฐ (ํญ ์ ์ค์ณ, ์ฌ ๋ทฐ์ add)
override func viewDidLoad() {
super.viewDidLoad()
selectPlanetCollectionView.delegate = self
selectPlanetCollectionView.dataSource = self
[guideCircleView, sceneView, selectedSquareView, searchGuideLabel, selectPlanetCollectionView].forEach { view.addSubview($0) }
sceneView.addSubview(guideCircleView)
configureConstraints()
selectedSquareView.isHidden = true
view.bringSubviewToFront(searchGuideLabel)
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap))
self.sceneView.addGestureRecognizer(tapGestureRecognizer)
let locationManager = LocationManager.shared
locationManager.delegate = self
locationManager.updateLocation()
}
# ๊ฒฐ๊ณผ (print)
didn't touch anything
didn't touch anything
Optional(<UIImage:0x2830f0090 named(main: Venus_Map) {2048, 1024} renderingMode=automatic(original)>)
<SCNNode: 0x283ecda00 pos(3.323599 -3.629274 -0.884342) | geometry=<SCNSphere: 0x2839cf0c0 | radius=0.200> | no child>
Optional(<UIImage:0x2830df3c0 named(main: Sun_Map) {2048, 1024} renderingMode=automatic(original)>)
<SCNNode: 0x283ec8f00 pos(3.565236 -3.416369 -0.785825) | geometry=<SCNSphere: 0x2839ca150 | radius=0.200> | no child>
Optional(<UIImage:0x2830df210 named(main: Mercury_Map) {2048, 1024} renderingMode=automatic(original)>)
<SCNNode: 0x283ef0900 pos(3.637146 -3.337214 -0.796352) | geometry=<SCNSphere: 0x2839cebe0 | radius=0.200> | no child>
didn't touch anything