【问题标题】:Creating a stopwatch in swift快速创建秒表
【发布时间】:2017-06-24 00:55:21
【问题描述】:

我已尝试搜索其他答案,但找不到适用于我的场景的答案。我正在快速编写游戏,并想创建一个秒表来确定玩家玩了多长时间。当用户触地时,秒表将启动,当某个动作发生时,计时器停止并重置。我想使用分钟、秒、毫秒(即 00:00.00)。

目前,时间函数是有效的。它不是从 0 开始,而是从当前秒数开始(我知道那是我开始的时候,但我不知道如何从 0 开始)。它也只在我触摸屏幕时更新,我需要它从 00:00.00 开始计数并自行更新,直到触发取消操作。

感谢您的宝贵时间。

这是我目前所拥有的:

class GameScene: SKScene {

var activeTimer = SKLabelNode()
//var bestTime = SKLabelNode()

var startTime = TimeInterval()
//var currentTime = TimeInterval()
//var countingTime = TimeInterval()
var updateTimerAction = SKAction()


override func didMove(to view: SKView) {

    activeTimer = self.childNode(withName: "active_timer") as! SKLabelNode
    //bestTime = self.childNode(withName: "best_time") as! SKLabelNode

    startTime = TimeInterval(Calendar.current.component(.second, from:Date()))
    updateTimerAction = SKAction.sequence([SKAction.run(updateTimer), SKAction.wait(forDuration: 1.0)])
}


func startGame() {
    // Other code
    startGameTimer()
}

func resetGame() {
    // Other code
    stopGameTimer()
}

func startGameTimer() {
    run(SKAction.repeatForever(updateTimerAction), withKey: "timer")
}

func updateTimer() {
    activeTimer.text = stringFromTimeInterval(interval: startTime) as String
}

func stringFromTimeInterval(interval: TimeInterval) -> NSString {

    let ti = NSInteger(interval)

    let ms = Int((interval.truncatingRemainder(dividingBy: 1)) * 1000)

    let seconds = ti % 60
    let minutes = (ti / 60) % 60

    return NSString(format: "%0.2d:%0.2d.%0.2d",minutes,seconds,ms)
}


func stopGameTimer() {
    removeAction(forKey: "timer")
}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

    startGame()

    for touch in touches {
        // other code
    }
}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {

    for touch in touches {
        // other code
    }
}


override func update(_ currentTime: TimeInterval) {

    updateTimer()

    if <action>  {
        // stop timer and reset game
        resetGame()
    }
}

【问题讨论】:

    标签: swift timer sprite-kit


    【解决方案1】:

    与其使用 TimeInterval 对象,不如使用 Timer 对象,该对象调用一个函数,该函数在每 1 秒后相应地从 0 开始递增标签(或内部变量)的值(或者可以变得更小) )。而要停止时钟,只需调用 Timer 对象的 invalidate 函数。 查看文档了解更多信息:https://developer.apple.com/documentation/foundation/timer

    【讨论】:

    • 我的印象是根据这个问题HERE
    • 这是正确的,虽然Timer 可以并且适用于简单的游戏,但最终会导致SpriteKit出现一些问题。最好为此使用 SKAction.wait 等
    • @Fluidity 我不认为这就是他所说的。他告诉我们应该使用 Timer 对象。你说我们不应该使用 Timer 对象。我说我不在 SKScene 中使用 Timer 对象。
    • @ElTomato 它相信您在 SKScene 中不使用 Timer 对象是正确的,但您会改用什么?
    • 您可以使用 SKAction(等待、序列、重复)创建倒数或倒数计时器。
    【解决方案2】:

    以下代码行来自我大约 3 周前提交给 Mac App Store 的实际 macOS 游戏。它将一个数字倒数到 0。在您的情况下,更改

    self.currentSeconds -= 1
    

    self.currentSeconds += 1
    

    timeBackNode 是一个空节点,其中包含 SKLabelNode 对象 timeNode0 和 timeNode1。所以在游戏以didMove开始时创建它。

    var currentSeconds = Int() // currentSeconds
    var timeNode0 = SKLabelNode() // timeNode0
    var timeNode1 = SKLabelNode() // timeNode1
    func setupTimeGoal() {
        enumerateChildNodes(withName: "//TimerBack", using: { timeBackNode, _ in
            let goal = self.timeDict["num"] as! Int
            self.currentSeconds = goal // In your case, goal is 0 since you are going to count up.
            self.timeNode0 = SKLabelNode(fontNamed: "Your font's font name")
            self.timeNode0.text = self.makeTimeWithSeconds(secs: goal)
            self.timeNode0.fontSize = 26
            self.timeNode0.fontColor = SKColor.black
            self.timeNode0.horizontalAlignmentMode = .center
            self.timeNode0.position = CGPoint(x: 1, y: -22)
            timeBackNode.addChild(self.timeNode0)
    
            self.timeNode1 = SKLabelNode(fontNamed: "Your font's font name")
            self.timeNode1.text = self.makeTimeWithSeconds(secs: goal) // this function translate a counting number into a time code like 00:00:00
            self.timeNode1.fontSize = 26
            self.timeNode1.fontColor = SKColor.cyan
            self.timeNode1.horizontalAlignmentMode = .center
            self.timeNode1.position = CGPoint(x: 0, y: -23)
            timeBackNode.addChild(self.timeNode1)
        })
    }
    
    func repeatTime() {
        let waitAction = SKAction.wait(forDuration: 1.0)
        let completionAction = SKAction.run {
            if self.currentSeconds == 0 && self.gameState == .playing {
                self.removeAction(forKey: "RepeatTime")
                self.proceedLoss()
                return
            }
            self.currentSeconds -= 1
            self.timeNode0.text = self.makeTimeWithSeconds(secs: self.currentSeconds)
            self.timeNode1.text = self.makeTimeWithSeconds(secs: self.currentSeconds)
        }
        let seqAction = SKAction.sequence([waitAction, completionAction])
        let repeatAction = SKAction.repeatForever(seqAction)
        self.run(repeatAction, withKey: "RepeatTime")
    }
    

    【讨论】:

      【解决方案3】:

      这就是我最终要做的。虽然 El Tomato 的答案似乎有效,但鉴于我的代码设置,我走了一条不同的路线。在与其他一些朋友交谈后,由于我的应用程序的设计,我选择使用计时器。如果我碰巧在使用 Timer 对象时遇到任何问题,我会更新这个问题。

      下面的代码将在触摸时开始,以格式更新:“00:00.00”并在触发动作时停止。该时间将暂停,直到再次触摸,然后计时器将从零开始。

      class GameScene: SKScene {
      
      var seconds = 0
      var timer = Timer()
      var timeStarted = Bool()
      var activeTimer = SKLabelNode()
      //var bestTime = SKLabelNode()
      
      override func didMove(to view: SKView) {
      
          activeTimer = self.childNode(withName: "active_timer") as! SKLabelNode
          //bestTime = self.childNode(withName: "best_time") as! SKLabelNode
          timeStarted = false
      
      }
      
      func startGame() {
      
          startGameTimer()
          timeStarted = true
      }
      
      func resetGame() {
      
          timeStarted = false
          stopGameTimer()
          seconds = 0
      }
      
      func startGameTimer() {
          timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(updateTimer)), userInfo: nil, repeats: true)
      }
      
      func updateTimer() {
          seconds += 1
          activeTimer.text = timeString(time: TimeInterval(seconds))
      }
      
      func timeString(time:TimeInterval) -> String {
          let hours = Int(time) / 3600
          let minutes = Int(time) / 60 % 60
          let seconds = Int(time) % 60
          return String(format:"%02i:%02i.%02i", hours, minutes, seconds)
      }
      
      
      func stopGameTimer() {
          timer.invalidate()
          removeAction(forKey: "timer")
      }
      
      override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
      
          if !timeStarted {
              startGame()
          }
      
          for touch in touches {
              // other code
          }
      }
      
      override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
      
          for touch in touches {
              // other code
          }
      }
      
      
      override func update(_ currentTime: TimeInterval) {
      
          if timeStarted {
              updateTimer()
          }
      
          if <action>  {
          // stop timer and reset game
          resetGame()
          }
      }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-10-13
        • 2015-06-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多