I cant move scn node forward in back

I’m having trouble moving the sun node forward and back in my code. I made a GIF showing what’s happening—you can see the arrow indicating the intended direction. Not sure if I need to disable one axis to allow the other. The gif is below. Don’t know what to do next.

Screen Recording 2025-07-23 at 11.24.12 PM

import UIKit import SceneKit;import CoreData

class one: UIViewController {


var boxAdd = UIButton()

var onOfSwitch = UISwitch()
var scnView = SCNView()

var cameraNode = SCNNode()
var selectedNode: SCNNode?



var   sHLabel = UILabel()



var pinchGesture: UIPinchGestureRecognizer?

var DragLabel = UILabel()

var panGesture: UIPanGestureRecognizer?

var originalMaterials: [SCNMaterial]?


override func viewDidLoad() {
    super.viewDidLoad()

    
    [boxAdd, onOfSwitch, scnView,sHLabel,DragLabel,].forEach {
        view.addSubview($0)
        $0.translatesAutoresizingMaskIntoConstraints = false
        $0.layer.borderWidth = 1
        $0.backgroundColor = UIColor(
            red: .random(in: 0.5...0.7),
            green: .random(in: 0.0...1),
            blue: .random(in: 0.3...0.5),
            alpha: 1
        )
        if let button = $0 as? UIButton {
            button.setTitleColor(.black, for: .normal)
        }
    }
  
    NSLayoutConstraint.activate([
    
        
        
        
        scnView.topAnchor.constraint(equalTo: view.topAnchor),
        scnView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.55),
        scnView.widthAnchor.constraint(equalTo: view.widthAnchor),
        scnView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
        
        
    
        
       
        
     
        
        
        
   
        
        
        
    
        
        
        sHLabel.topAnchor.constraint(equalTo: scnView.bottomAnchor),
        sHLabel.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.04),
        sHLabel.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 1/5),
        sHLabel.leadingAnchor.constraint(equalTo: scnView.trailingAnchor),
        
        
        boxAdd.topAnchor.constraint(equalTo: scnView.bottomAnchor),
        boxAdd.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.10),
        boxAdd.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 1/3),
        boxAdd.leadingAnchor.constraint(equalTo: view.leadingAnchor),
        
     
        DragLabel.topAnchor.constraint(equalTo: scnView.bottomAnchor),
        DragLabel.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.05),
        DragLabel.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 1/3),
        DragLabel.leadingAnchor.constraint(equalTo: boxAdd.trailingAnchor),
        
        onOfSwitch.topAnchor.constraint(equalTo: DragLabel.bottomAnchor),
        onOfSwitch.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.05),
        onOfSwitch.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 1/6),
        onOfSwitch.leadingAnchor.constraint(equalTo: boxAdd.trailingAnchor),
        
        
       
    ])
    
 
    
    
    DragLabel.text = "Drag to Rotate"
    let scene = SCNScene()
    scnView.scene = scene
    scnView.backgroundColor = .gray
    
    
    DragLabel.textAlignment = .center
    setupCamera()
    setupLight()
    
    boxAdd.setTitle("Box", for: .normal)
    boxAdd.addTarget(self, action: #selector(addBox2), for: .touchUpInside)
  
    
    onOfSwitch.addTarget(self, action: #selector(toggleCameraControl), for: .valueChanged)
    onOfSwitch.isOn = true
    scnView.allowsCameraControl = true
    

   
    
    sHLabel.text = "Height"
    
    
    sHLabel.textAlignment = .center
  
  
   
    
   
    
    
    onOfSwitch.isOn = false
    
 
 
    
    
    
    //2

    
 
    
   
    let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
    scnView.addGestureRecognizer(tapGesture)
    
    //3
    
    let rotationGesture = UIRotationGestureRecognizer(target: self, action: #selector(handleRotation(_:)))
    scnView.addGestureRecognizer(rotationGesture)
    

}







@objc func clearM() {
    scnView.scene?.rootNode.childNodes.forEach { node in
        // Keep camera and light nodes
        if node != cameraNode && node.light == nil {
            node.removeFromParentNode()
        }
    }
    selectedNode = nil
}



@objc func depthTextChanged(_ sender: UITextField) {
    guard let currentView = selectedNode else { return }
    guard let text = sender.text, let newDepth = Float(text) else { return }
    
    if let box = currentView.geometry as? SCNBox {
        box.length = CGFloat(newDepth)
        applyTextAsTexture55(to: box, width: 3, height: 7, depth: newDepth)
    } else if let cylinder = currentView.geometry as? SCNCylinder {
        // Treat "depth" as diameter here
        cylinder.radius = CGFloat(newDepth / 2)
        applyTextAsTextureToCylinder(cylinder, width: newDepth, height: 7)
    }
}


@objc func heightTextChanged(_ sender: UITextField) {
    guard let currentView = selectedNode else { return }
    guard let text = sender.text, let newHeight = Float(text) else { return }
    
    if let box = currentView.geometry as? SCNBox {
        box.height = CGFloat(newHeight)
        applyTextAsTexture55(to: box, width: 3, height: newHeight, depth: 5)
    } else if let cylinder = currentView.geometry as? SCNCylinder {
        cylinder.height = CGFloat(newHeight)
        applyTextAsTextureToCylinder(cylinder, width: 3, height: newHeight)
    }
}

@objc func widthTextChanged(_ sender: UITextField) {
    guard let currentView = selectedNode else { return }
    guard let text = sender.text, let newWidth = Float(text) else { return }
    
    if let box = currentView.geometry as? SCNBox {
        box.width = CGFloat(newWidth)
        applyTextAsTexture55(to: box, width: newWidth, height: 5, depth: 7)
    } else if let cylinder = currentView.geometry as? SCNCylinder {
        cylinder.radius = CGFloat(newWidth / 2)
        applyTextAsTextureToCylinder(cylinder, width: newWidth, height: 7)
    }
}

@objc func handleTap(_ gesture: UITapGestureRecognizer) {
    let location = gesture.location(in: scnView)
    let hitResults = scnView.hitTest(location, options: nil)
    if let result = hitResults.first {
        selectedNode = result.node
        print("Selected a node: \(selectedNode!)")
    } else {
        selectedNode = nil
        print("No node selected.")
    }
}

func setupCamera() {
    cameraNode = SCNNode()
    cameraNode.camera = SCNCamera()
    cameraNode.position = SCNVector3(0, 0, 10)
    scnView.scene?.rootNode.addChildNode(cameraNode)
    
    // Set the camera as the active point of view
    scnView.pointOfView = cameraNode
}


func setupLight() {
    let lightNode = SCNNode()
    lightNode.light = SCNLight()
    lightNode.light?.type = .omni
    lightNode.position = SCNVector3(0, 10, 10)
    scnView.scene?.rootNode.addChildNode(lightNode)
    
    let ambientLight = SCNNode()
    ambientLight.light = SCNLight()
    ambientLight.light?.type = .ambient
    ambientLight.light?.color = UIColor.darkGray
    scnView.scene?.rootNode.addChildNode(ambientLight)
}
@objc func toggleCameraControl() {
    if onOfSwitch.isOn {
        scnView.allowsCameraControl = true
        
        // Remove pan and pinch gestures
        if let pan = panGesture {
            scnView.removeGestureRecognizer(pan)
            panGesture = nil
        }
        if let pinch = pinchGesture {
            scnView.removeGestureRecognizer(pinch)
            pinchGesture = nil
        }
    } else {
        scnView.allowsCameraControl = false
        
        if panGesture == nil {
            let pan = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
            scnView.addGestureRecognizer(pan)
            panGesture = pan
        }
        
        if pinchGesture == nil {
            let pinch = UIPinchGestureRecognizer(target: self, action: #selector(handlePinch(_:)))
            scnView.addGestureRecognizer(pinch)
            pinchGesture = pinch
        }
    }
}
@objc func handlePinch(_ gesture: UIPinchGestureRecognizer) {
    guard let camera = scnView.pointOfView else { return }
    
    if gesture.state == .changed {
        let scale = Float(gesture.scale)
        var position = camera.position
        position.z /= scale  // Zoom in or out
        position.z = max(min(position.z, 100), 1)  // Clamp zoom
        camera.position = position
        gesture.scale = 1
    }
}









@objc func handlePan(_ gesture: UIPanGestureRecognizer) {
    let location = gesture.location(in: scnView)
    
    switch gesture.state {
    case .began:
        let hitResults = scnView.hitTest(location, options: nil)
        if let hitNode = hitResults.first?.node,
           let geometry = hitNode.geometry,
           geometry is SCNBox || geometry is SCNCylinder {
            
            selectedNode = hitNode
            
            
        }
        
    case .changed:
        guard let selectedNode = selectedNode else { return }
        let translation = gesture.translation(in: scnView)
        let deltaX = Float(translation.x) * 0.01
        let deltaY = Float(-translation.y) * 0.01
        selectedNode.position.x += deltaX
        selectedNode.position.y += deltaY
        gesture.setTranslation(.zero, in: scnView)
        
    default:
        break
    }
}






@objc func handleRotation(_ gesture: UIRotationGestureRecognizer) {
    
    
    guard let node = selectedNode else { return }
    if gesture.state == .changed {
        node.eulerAngles.y += Float(gesture.rotation)
        gesture.rotation = 0
    }
    
    
    
}
func createCylinder(radius: CGFloat, height: CGFloat) -> SCNNode {
    let cylinder = SCNCylinder(radius: radius, height: height)
    cylinder.firstMaterial?.diffuse.contents = UIColor.lightGray
    cylinder.firstMaterial?.isDoubleSided = true
    cylinder.radialSegmentCount = 20  // Boxier look
    
    let node = SCNNode(geometry: cylinder)
    node.position = SCNVector3(0, 0, 0)
    return node
}

func applyTextAsTextureToCylinder(_ cylinder: SCNCylinder, width: Float, height: Float) {
    let sideImage = drawCylinderHeightLabel(height: height)
    
    
    let topImage = drawCylinderTopWidthLabel(width: width)
    
    let sideMaterial = SCNMaterial()
    sideMaterial.diffuse.contents = sideImage
    sideMaterial.isDoubleSided = true
    
    let topMaterial = SCNMaterial()
    topMaterial.diffuse.contents = topImage
    topMaterial.isDoubleSided = true
    
    let blankMaterial = SCNMaterial()
    blankMaterial.diffuse.contents = UIColor.lightGray
    
    cylinder.materials = [
        sideMaterial, // side
        topMaterial,  // top
        blankMaterial // bottom (optional)
    ]
}


func drawCylinderHeightLabel(height: Float) -> UIImage {
    let size = CGSize(width: 256, height: 512)
    UIGraphicsBeginImageContextWithOptions(size, false, 0)
    guard let context = UIGraphicsGetCurrentContext() else { return UIImage() }

    UIColor.white.setFill()
    context.fill(CGRect(origin: .zero, size: size))

    let width = Float(3)
    let aspectRatio = width / height
    let heightText = "height: \(Int(height * 1))"

    // New: Reasonable bounds for font size
    let baseFontSize: CGFloat = 32
    let minFontSize: CGFloat = 14
    let maxFontSize: CGFloat = 36

    var fontSize: CGFloat
    if aspectRatio > 3 {
        print("a")
     //   fontSize = max(minFontSize, baseFontSize * CGFloat((height / width)) * 8)
        
        fontSize = max(minFontSize, baseFontSize * CGFloat((height / width)) * 180)
    } else {
        
        print("b")
        fontSize = max(minFontSize, baseFontSize * CGFloat((height / width)) * 2.5)
    }
    fontSize = min(fontSize, maxFontSize)

    let font = UIFont.systemFont(ofSize: fontSize)
    let attributes: [NSAttributedString.Key: Any] = [
        .font: font,
        .foregroundColor: UIColor.black
    ]

    if aspectRatio > 3 {
        
        print("1")
        // Wide, flat cylinder – draw horizontal centered
        let textSize = (heightText as NSString).size(withAttributes: attributes)
        let rect = CGRect(
            x: (size.width - textSize.width) / 2 ,
            y: (size.height - textSize.height) / 2,
            width: textSize.width,
            height: textSize.height * 20
        )
        (heightText as NSString).draw(in: rect, withAttributes: attributes)
    } else {
        print("2")
        // Taller cylinder – draw vertically rotated
        context.saveGState()
        context.translateBy(x: size.width / 2, y: size.height / 2)
        context.rotate(by: -.pi / 2)

        let rect = CGRect(x: -128, y: -20, width: 256, height: 40)
        (heightText as NSString).draw(in: rect, withAttributes: attributes)

        context.restoreGState()
    }

    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return image ?? UIImage()
}

func drawCylinderTopWidthLabel(width: Float) -> UIImage {
    let size = CGSize(width: 256, height: 256)
    UIGraphicsBeginImageContextWithOptions(size, false, 0)
    guard let context = UIGraphicsGetCurrentContext() else { return UIImage() }
    
    // Fill background
    UIColor.white.setFill()
    context.fill(CGRect(origin: .zero, size: size))
    
    // Text attributes
    let font = UIFont.systemFont(ofSize: 28, weight: .bold)
    let attributes: [NSAttributedString.Key: Any] = [
        .font: font,
        .foregroundColor: UIColor.black
    ]
    
    let widthText = "width: \(Int(width * 1))"
    let textSize = (widthText as NSString).size(withAttributes: attributes)
    
    // Move to center, flip horizontally
    context.translateBy(x: size.width / 2, y: size.height / 2)
    context.scaleBy(x: -1.0, y: 1.0)  // 🔁 Horizontal mirror
    
    context.rotate(by: (3 * .pi) / 2)  // 180 degrees
    
    // Draw centered mirrored text
    let rect = CGRect(
        x: -textSize.width / 2,
        y: -textSize.height / 2,
        width: textSize.width,
        height: textSize.height
    )
    
    (widthText as NSString).draw(in: rect, withAttributes: attributes)
    
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return image ?? UIImage()
}

@objc func addBox2() {


    let width = 3
    let height = 2
    let depth = 5
    
    let box = SCNBox(
        width: CGFloat(width),
        height: CGFloat(height),
        length: CGFloat(depth),
        chamferRadius: 0.1
    )
    
    applyTextAsTexture55(to: box, width: Float(width), height: Float(height), depth: Float(depth))
    
    let boxNode = SCNNode(geometry: box)
    boxNode.position = SCNVector3(0, 0, 0)
    scnView.scene?.rootNode.addChildNode(boxNode)
    selectedNode = boxNode
    selectedNode = boxNode
    originalMaterials = box.materials.map { $0.copy() as! SCNMaterial }
}
func drawTopWithDepth(depth: Float) -> UIImage {
    let size = CGSize(width: 256, height: 256)
    UIGraphicsBeginImageContextWithOptions(size, false, 0)
    guard let context = UIGraphicsGetCurrentContext() else { return UIImage() }
    
    UIColor.white.setFill()
    context.fill(CGRect(origin: .zero, size: size))
    
    let font = UIFont.systemFont(ofSize: 28)
    let attributes: [NSAttributedString.Key: Any] = [
        .font: font,
        .foregroundColor: UIColor.black
    ]
    
    let depthText = "depth: \(Int(depth * 1))"
    
    // Rotate and place on bottom right corner of top face
    context.saveGState()
    context.translateBy(x: size.width - 40, y: size.height - 20)
    context.rotate(by: -.pi / 2)
    
    let rect = CGRect(x: 0, y: 0, width: 200, height: 40)
    (depthText as NSString).draw(in: rect, withAttributes: attributes)
    
    context.restoreGState()
    
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return image ?? UIImage()
}

func applyTextAsTexture55(to box: SCNBox, width: Float, height: Float, depth: Float) {
    let blankMaterial = SCNMaterial()
    blankMaterial.diffuse.contents = UIColor.lightGray
    blankMaterial.isDoubleSided = true
    
    // Front face: width + height
    
    let frontMaterial = SCNMaterial()
  
    frontMaterial.isDoubleSided = true
    
    // Top face: depth
    let topImage = drawTopWithDepth(depth: depth)
    
    let topMaterial = SCNMaterial()
    topMaterial.diffuse.contents = topImage
    topMaterial.isDoubleSided = true
    
    box.materials = [
        frontMaterial,     // front
        blankMaterial,     // right
        blankMaterial,     // back
        blankMaterial,     // left
        topMaterial,       // top
        blankMaterial      // bottom
    ]
}



@objc func updateBoxSize() {
    guard let selectedNode = selectedNode else { return }
    
    let width = 3
    let height = 7
    let depth = 5
    
    if let box = selectedNode.geometry as? SCNBox {
        box.width = CGFloat(width)
        box.height = CGFloat(height)
        box.length = CGFloat(depth)
        applyTextAsTexture55(to: box, width: Float(width), height: Float(height), depth: Float(depth))
    } else if let cylinder = selectedNode.geometry as? SCNCylinder {
        cylinder.radius = CGFloat(width / 2) // radius = width / 2 for diameter control
        cylinder.height = CGFloat(height)
        applyTextAsTextureToCylinder(cylinder, width: Float(width), height: Float(height))
        
    }
}

Hello!
The “sun node” not moving in the intended direction is likely a coordinate system issue. Your code might be moving the object along the world’s Z-axis, while you expect it to move along its own local Z-axis. To fix this, check your movement function to ensure it’s set to move in local space. Additionally, print the object’s transform values and use your engine’s debug tools to visualize its local axes to confirm that your code’s movement aligns with the object’s orientation.