cubescene: < /p>
Код: Выделить всё
import SwiftUI
import SceneKit
class CuboScene: SCNScene, ObservableObject {
override init() {
super.init()
rootNode.eulerAngles = SCNVector3(0, 0, 0) // Ensure rootNode is not rotated
rootNode.position = SCNVector3(0, 0, 0) // Ensure rootNode is at the origin
rootNode.scale = SCNVector3(1, 1, 1) // Ensure no unexpected scaling
configureLights()
createRubikCube()
}
private func createRubikCube() {
let size: CGFloat = 0.8
let spacing: CGFloat = 0.78
for x in -1...1 {
for y in -1...1 {
for z in -1...1 {
let cubelet = SCNBox(width: size, height: size, length: size, chamferRadius: 0.10)
let cubeletNode = SCNNode(geometry: cubelet)
cubeletNode.position = SCNVector3(Float(x) * Float(spacing),
Float(y) * Float(spacing),
Float(z) * Float(spacing))
cubeletNode.eulerAngles = SCNVector3(0, 0, 0)
cubelet.materials = getFaceMaterial(x: x, y: y, z: z)
rootNode.addChildNode(cubeletNode)
}
}
}
}
private func getFaceMaterial(x: Int, y: Int, z: Int) -> [SCNMaterial] {
let colors: [UIColor] = [
(z == 1) ? .green : .black, // Front face (+Z)
(x == 1) ? .red : .black, // Right face (+X)
(z == -1) ? .blue : .black, // Back face (-Z)
(x == -1) ? .orange : .black, // Left face (-X)
(y == 1) ? .white : .black, // Top face (+Y)
(y == -1) ? .yellow : .black // Bottom face (-Y)
]
return colors.map { createMaterial(color: $0) }
}
private func createMaterial(color: UIColor) -> SCNMaterial {
let material = SCNMaterial()
material.diffuse.contents = color.withAlphaComponent(1.0)
material.specular.contents = UIColor.white
material.shininess = 100
material.lightingModel = .phong
return material
}
private func configureLights() {
// Ambient light for base illumination
let ambientLight = SCNLight()
ambientLight.type = .ambient
ambientLight.intensity = 500
let ambientLightNode = SCNNode()
ambientLightNode.light = ambientLight
rootNode.addChildNode(ambientLightNode)
// Array of positions and directions for the 6 lights
let positions: [(SCNVector3, SCNVector3)] = [
(SCNVector3(0, 10, 0), SCNVector3(0, -1, 0)), // Top
(SCNVector3(0, -10, 0), SCNVector3(0, 1, 0)), // Bottom
(SCNVector3(10, 0, 0), SCNVector3(-1, 0, 0)), // Right
(SCNVector3(-10, 0, 0), SCNVector3(1, 0, 0)), // Left
(SCNVector3(0, 0, 10), SCNVector3(0, 0, -1)), // Front
(SCNVector3(0, 0, -10), SCNVector3(0, 0, 1)) // Back
]
for (position, direction) in positions {
let light = SCNLight()
light.type = .directional
light.intensity = 1000
light.color = UIColor.white
let lightNode = SCNNode()
lightNode.light = light
lightNode.position = position
lightNode.eulerAngles = SCNVector3(
atan2(direction.y, direction.z),
atan2(direction.x, direction.z),
0)
rootNode.addChildNode(lightNode)
}
}
func rotateLayer(cubelets: [SCNNode], axis: SCNVector3, angle: CGFloat) {
let tempNode = SCNNode()
var originalMaterials: [SCNNode: [SCNMaterial]] = [:]
var originalPositions: [SCNNode: SCNVector3] = [:]
var originalEulerAngles: [SCNNode: SCNVector3] = [:]
for cubelet in cubelets {
if let geometry = cubelet.geometry as? SCNBox {
originalMaterials[cubelet] = geometry.materials
}
originalPositions[cubelet] = cubelet.position
originalEulerAngles[cubelet] = cubelet.eulerAngles
cubelet.removeFromParentNode()
tempNode.addChildNode(cubelet)
}
rootNode.addChildNode(tempNode)
let rotationAction = SCNAction.rotate(by: angle, around: axis, duration: 0.2)
tempNode.runAction(rotationAction) {
for cubelet in cubelets {
let worldPosition = cubelet.worldPosition
tempNode.removeFromParentNode()
let localPosition = self.rootNode.convertPosition(worldPosition, from: nil)
cubelet.position = localPosition
if eje.x != 0 {
cubelet.eulerAngles = SCNVector3(cubelet.eulerAngles.x + Float(angle), cubelet.eulerAngles.y, cubelet.eulerAngles.z)
} else if eje.y != 0 {
cubelet.eulerAngles = SCNVector3(cubelet.eulerAngles.x, cubelet.eulerAngles.y + Float(angle), cubelet.eulerAngles.z)
} else if eje.z != 0 {
cubelet.eulerAngles = SCNVector3(cubelet.eulerAngles.x, cubelet.eulerAngles.y, cubelet.eulerAngles.z + Float(angle))
}
if let geometry = cubelet.geometry as? SCNBox {
geometry.materials = originalMaterials[cubelet] ?? geometry.materials
}
self.rootNode.addChildNode(cubelet)
}
tempNode.removeFromParentNode()
}
}
func rotateTopLayer() {
let axis = SCNVector3(x: 0, y: 1, z: 0)
let angle: CGFloat = .pi / 2
let topCubelets = rootNode.childNodes.filter { node in
abs(node.position.y - 0.78) < 0.01
}
rotateLayer(cubelets: topCubelets, axis: axis, angle: angle)
}
func rotateBottomLayer() {
let axis = SCNVector3(x: 0, y: 1, z: 0)
let angle: CGFloat = -.pi / 2
let bottomCubelets = rootNode.childNodes.filter { node in
abs(node.position.y + 0.78) < 0.01
}
rotateLayer(cubelets: bottomCubelets, axis: axis, angle: angle)
}
func rotateRightLayer() {
let axis = SCNVector3(x: 1, y: 0, z: 0)
let angle: CGFloat = .pi / 2
let rightCubelets = rootNode.childNodes.filter { node in
abs(node.position.x - 0.78) < 0.02
}
rotateLayer(cubelets: rightCubelets, axis: axis, angle: angle)
}
func rotateLeftLayer() {
let axis = SCNVector3(x: 1, y: 0, z: 0)
let angle: CGFloat = -.pi / 2
let leftCubelets = rootNode.childNodes.filter { node in
abs(node.position.x + 0.78) < 0.02
}
rotateLayer(cubelets: leftCubelets, axis: axis, angle: angle)
}
func rotateFrontLayer() {
let axis = SCNVector3(x: 0, y: 0, z: 1)
let angle: CGFloat = .pi / 2
let frontCubelets = rootNode.childNodes.filter { node in
abs(node.position.z - 0.78) < 0.01
}
rotateLayer(cubelets: frontCubelets, axis: axis, angle: angle)
}
func rotateBackLayer() {
let axis = SCNVector3(x: 0, y: 0, z: 1)
let angle: CGFloat = -.pi / 2
let backCubelets = rootNode.childNodes.filter { node in
abs(node.position.z + 0.78) < 0.01
}
rotateLayer(cubelets: backCubelets, axis: axis, angle: angle)
}
required init(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
< /code>
changekitview: < /p>
import SwiftUI
import SceneKit
struct SceneKitView: UIViewRepresentable {
@ObservedObject var cubeScene: CuboScene
func makeUIView(context: Context) -> SCNView {
let view = SCNView()
view.scene = cubeScene
view.allowsCameraControl = true
view.autoenablesDefaultLighting = true
view.backgroundColor = .gray
// Configure an initial camera
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(x: 5, y: 5, z: 5) // Diagonal position to see all faces
cameraNode.look(at: SCNVector3(0, 0, 0)) // Point to the cube's center
view.pointOfView = cameraNode
return view
}
func updateUIView(_ uiView: SCNView, context: Context) {
uiView.scene = cubeScene
}
}
#Preview {
SceneKitView(cubeScene: CuboScene()) // Or RubikCubeScene if preferred
}
< /code>
contenview: < /p>
import SwiftUI
struct ContentView: View {
@StateObject private var cubeScene = CuboScene() // Or use RubikCubeScene if preferred
var body: some View {
VStack {
SceneKitView(cubeScene: cubeScene)
.frame(height: 400)
.ignoresSafeArea()
}
Button("Rotate Top Layer") {
cubeScene.rotateTopLayer()
}
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
Button("Rotate Right Layer") {
cubeScene.rotateRightLayer()
}
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
Button("Rotate Left Layer") {
cubeScene.rotateLeftLayer()
}
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
Button("Rotate Bottom Layer") {
cubeScene.rotateBottomLayer()
}
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
Button("Rotate Front Layer") {
cubeScene.rotateFrontLayer()
}
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
Button("Rotate Back Layer") {
cubeScene.rotateBackLayer()
}
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
}
}
#Preview {
ContentView()
}
https://www.youtube.com/shorts/7q8xcdjdoce
Подробнее здесь: https://stackoverflow.com/questions/794 ... -rubik-s-c