1

I'm making an AR app where I place nodes all over the room until they're 25 and at the same time the player has to destroy those objects. I wanna track the time elapsed since the first node was created until the last node was destroyed. I'm using Date() to know the time interval between those two events but I keep getting that error. I don't know if I'm doing it the right way, if there's a better way to do it I'll be so grateful to know or if it needs to be a little bit different please let me know. Thanks in advance for your help :)

import SpriteKit
import ARKit
import GameplayKit

class Scene: SKScene {
    
    let remainingTargetLabel = SKLabelNode()
    var timer : Timer?
    var targetsCreated = 0
    var text = "left"
    var targetCount = 0 {
        didSet {
            remainingTargetLabel.text = "\(targetCount) "
        }
    }
    var startingTime : Date?
    var endingTime : Date?
    
    override func didMove(to view: SKView) {
        remainingTargetLabel.fontSize = 30
        remainingTargetLabel.fontName = "Helvetica Neue"
        remainingTargetLabel.color = .white
        remainingTargetLabel.position = CGPoint(x: 0, y: view.frame.midY-50)
        addChild(remainingTargetLabel)
        
        targetCount = 0
        timer = Timer.scheduledTimer(withTimeInterval: 3.0, repeats: true,
                                     block: { (timer) in
                                        self.createTarget()
                                    }
        )
    }
    
    override func update(_ currentTime: TimeInterval) {

    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let touch = touches.first else {return}
        let location = touch.location(in: self)
        let node = nodes(at: location)
        
        if let sprite = node.first {
        let scaleOut = SKAction.scale(to: 3, duration: 0.4)
        let fadeOut = SKAction.fadeOut(withDuration: 0.4)
            let remove = SKAction.removeFromParent()
        let group = SKAction.group([scaleOut, fadeOut])
        let sequence = SKAction.sequence([group, remove])
            sprite.run(sequence)
            targetCount -= 1
            if targetsCreated == 1 {
                startingTime = Date()
            }
            if targetsCreated == 25 && targetCount == 0 {
                endingTime = Date()
                gameOver()
            }
    }
}

    func createTarget() {
        if targetsCreated == 25 {
            timer?.invalidate()
            timer = nil
            return
        }
        targetsCreated += 1
        targetCount += 1
        
        guard let sceneView = self.view as? ARSKView else { return }
        
        let random = GKRandomSource.sharedRandom()
        
       
        let rotateX = simd_float4x4(SCNMatrix4MakeRotation(2.0 * Float.pi * random.nextUniform(), 1, 0, 0))
        
        let rotateY = simd_float4x4(SCNMatrix4MakeRotation(2.0 * Float.pi * random.nextUniform(), 0, 1, 0))
        
        let rotation = simd_mul(rotateX, rotateY)
        
        var translation = matrix_identity_float4x4
        translation.columns.3.z = -1.5

        let anchor = ARAnchor(transform: finalTransformation)
        
        
        sceneView.session.add(anchor: anchor)
    }
    
   func gameOver () {
        remainingTargetLabel.removeFromParent()
        
        let gameOverImage = SKSpriteNode(imageNamed: "gameover")
        addChild(gameOverImage)
    let timeTaken = endingTime?.timeIntervalSince(startingTime!)
        let timeTakenLabel = SKLabelNode(text: "Time taken: \(String(timeTaken!))")
        timeTakenLabel.fontName = "Helvetica Neue"
        timeTakenLabel.fontSize = 50
        timeTakenLabel.color = .white
        timeTakenLabel.position = CGPoint(x: 0, y: -(view?.frame.midY)!+50)
       addChild(timeTakenLabel)
    }
}
sandra
  • 11
  • 1
  • 3
  • 1
    You never set starting time and then you force unwrap it. – Paulw11 Apr 06 '21 at 21:43
  • I set it at the end of the touchesBegan function because I want to know the time elapsed, but I don't know if I did it right. So sorry if it's something obvious but I'm kinda new to this – sandra Apr 06 '21 at 22:01
  • Get rid of all of the force unwraps - use conditional unwraps and check for `nil`; what line is it crashing on? What if the timer has fired twice or more before the first touch? Then you will never assign a starting time. A safer approach is to set the start time in touches began if it is currently nil. – Paulw11 Apr 06 '21 at 23:07

0 Answers0