等待 Swift 个计时器完成
Wait for Swift timers to finish
所以我在 swift 5 上做一个简单的游戏,我基本上有一个 3..2..1.. 开始游戏的计时器,然后是一个 3..2..1 ..停止计时器停止游戏。最后是显示分数的函数。我需要一种方法让每个函数调用在下一个函数开始之前等待计时器完成,有什么建议吗?到目前为止,这是我的代码。 (此外,如果您对应用程序有任何其他建议,也请告诉我,最终目标是注册您可以在 3 秒内点击多少次按钮)
var seconds = 3 //Starting seconds
var countDownTimer = Timer()
var gameTimer = Timer()
var numberOfTaps = 0
override func viewDidLoad() {
super.viewDidLoad()
self.startCountdown(seconds: seconds)
self.gameCountdown(seconds: seconds)
self.displayFinalScore()
}
func startCountdown(seconds: Int) {
countDownTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] timer in
self?.seconds -= 1
if self?.seconds == 0 {
self?.countdownLabel.text = "Go!"
timer.invalidate()
} else if let seconds = self?.seconds {
self?.countdownLabel.text = "\(seconds)"
}
}
}
func gameCountdown(seconds: Int) {
gameTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] timer in
self?.seconds -= 1
if self?.seconds == 0 {
self?.countdownLabel.text = "Stop!"
timer.invalidate()
} else if let seconds = self?.seconds {
self?.countdownLabel.text = "\(seconds)"
}
}
}
deinit {
// ViewController going away. Kill the timer.
countDownTimer.invalidate()
}
@IBOutlet weak var countdownLabel: UILabel!
@IBAction func tapMeButtonPressed(_ sender: UIButton) {
if gameTimer.isValid {
numberOfTaps += 1
}
}
func displayFinalScore() {
if !gameTimer.isValid && !countDownTimer.isValid {
countdownLabel.text = "\(numberOfTaps)"
}
}
方法不应该是函数调用 wait 让定时器完成,而是定时器应该调用函数当他们完成时。
因此,您需要将 viewDidLoad
的函数调用 out 移至 inside Timer
]块。
self.gameCountdown(seconds: seconds)
self.displayFinalScore()
即函数调用 self.gameCountdown(seconds: seconds)
将进入在 startCountdown
中启动的计时器块内。在那里,当你在秒数变为 0 时使计时器无效时,你调用 gameCountdown
.
同样,在 gameCountdown
开始的计时器中,当秒数变为 0 时调用 self.displayFinalScore
。
很少有其他建议。您应该避免检查 tapMeButtonPressed
中的属性。
您应该禁用并启用点击我按钮。 IE。当你开始 gameCountdown 时启用它并在它结束时禁用它。
同样,您不需要检查 displayFinalScore
中计时器的状态。它应该只做一件事,即显示最终得分。
以后会让你省去很多麻烦:)。我的 2 美分。
您应该考虑您的游戏可能处于的状态。它可能是 -
- 设置 - 建立游戏
- 开始 - 前三秒
- 运行 - 在前三秒之后但在结束之前
- 结尾 - 最后三秒
- 结束 - 时间到了。
每次你的计时器计时时,你都需要考虑你需要采取什么行动以及你需要进入什么状态。你没有说你希望游戏持续多长时间,但假设是 30 秒。
开始新游戏时,您处于setup
状态;该按钮被禁用(即它不会对点击做出反应)并且您将分数设置为 0。您移动到 starting
状态。
在 starting
中显示倒计时。三秒钟后,您启用该按钮并进入 running
状态。
达到 27 秒后,您将进入 ending
状态并显示结束倒计时
最后时间到了,您进入 ended
状态,禁用按钮并显示分数。
你可以这样编码
enum GameState {
case setup
case starting
case running
case ending
case ended
}
class ViewController: UIViewController {
@IBOutlet weak var startButton: UIButton!
@IBOutlet weak var tapButton: UIButton!
@IBOutlet weak var countdownLabel: UILabel!
var gameState = GameState.ended
var gameTimer:Timer?
var numberOfTaps = 0
var gameStartTime = Date.distantPast
let GAMEDURATION: TimeInterval = 30
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
@IBAction func startButtonTapped(_ sender: UIButton) {
self.startGame()
}
@IBAction func tapMeButtonPressed(_ sender: UIButton) {
self.numberOfTaps += 1
}
func startGame() {
self.gameState = .setup
self.gameTimer = Timer.scheduledTimer(withTimeInterval:0.1, repeats: true) { timer in
let elapsedTime = -self.gameStartTime.timeIntervalSinceNow
let timeRemaining = self.GAMEDURATION-elapsedTime
switch self.gameState {
case .setup:
self.gameStartTime = Date()
self.tapButton.isEnabled = false
self.startButton.isEnabled = false
self.numberOfTaps = 0
self.gameState = .starting
case .starting:
if elapsedTime > 2.5 {
self.gameState = .running
self.tapButton.isEnabled = true
self.countdownLabel.text = "Go!"
} else {
let countdown = Int(3-round(elapsedTime))
self.countdownLabel.text = "\(countdown)"
}
case .running:
if timeRemaining < 4 {
self.gameState = .ending
}
case .ending:
let countdown = Int(timeRemaining)
self.countdownLabel.text = "\(countdown)"
if timeRemaining < 1 {
self.countdownLabel.text = "Stop"
self.gameState = .ended
self.tapButton.isEnabled = false
}
case .ended:
if timeRemaining <= 0 {
self.countdownLabel.text = "You tapped the button \(self.numberOfTaps) times"
self.startButton.isEnabled = true
self.gameTimer?.invalidate()
self.gameTimer = nil
}
}
}
}
}
所以我在 swift 5 上做一个简单的游戏,我基本上有一个 3..2..1.. 开始游戏的计时器,然后是一个 3..2..1 ..停止计时器停止游戏。最后是显示分数的函数。我需要一种方法让每个函数调用在下一个函数开始之前等待计时器完成,有什么建议吗?到目前为止,这是我的代码。 (此外,如果您对应用程序有任何其他建议,也请告诉我,最终目标是注册您可以在 3 秒内点击多少次按钮)
var seconds = 3 //Starting seconds
var countDownTimer = Timer()
var gameTimer = Timer()
var numberOfTaps = 0
override func viewDidLoad() {
super.viewDidLoad()
self.startCountdown(seconds: seconds)
self.gameCountdown(seconds: seconds)
self.displayFinalScore()
}
func startCountdown(seconds: Int) {
countDownTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] timer in
self?.seconds -= 1
if self?.seconds == 0 {
self?.countdownLabel.text = "Go!"
timer.invalidate()
} else if let seconds = self?.seconds {
self?.countdownLabel.text = "\(seconds)"
}
}
}
func gameCountdown(seconds: Int) {
gameTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] timer in
self?.seconds -= 1
if self?.seconds == 0 {
self?.countdownLabel.text = "Stop!"
timer.invalidate()
} else if let seconds = self?.seconds {
self?.countdownLabel.text = "\(seconds)"
}
}
}
deinit {
// ViewController going away. Kill the timer.
countDownTimer.invalidate()
}
@IBOutlet weak var countdownLabel: UILabel!
@IBAction func tapMeButtonPressed(_ sender: UIButton) {
if gameTimer.isValid {
numberOfTaps += 1
}
}
func displayFinalScore() {
if !gameTimer.isValid && !countDownTimer.isValid {
countdownLabel.text = "\(numberOfTaps)"
}
}
方法不应该是函数调用 wait 让定时器完成,而是定时器应该调用函数当他们完成时。
因此,您需要将 viewDidLoad
的函数调用 out 移至 inside Timer
]块。
self.gameCountdown(seconds: seconds)
self.displayFinalScore()
即函数调用 self.gameCountdown(seconds: seconds)
将进入在 startCountdown
中启动的计时器块内。在那里,当你在秒数变为 0 时使计时器无效时,你调用 gameCountdown
.
同样,在 gameCountdown
开始的计时器中,当秒数变为 0 时调用 self.displayFinalScore
。
很少有其他建议。您应该避免检查 tapMeButtonPressed
中的属性。
您应该禁用并启用点击我按钮。 IE。当你开始 gameCountdown 时启用它并在它结束时禁用它。
同样,您不需要检查 displayFinalScore
中计时器的状态。它应该只做一件事,即显示最终得分。
以后会让你省去很多麻烦:)。我的 2 美分。
您应该考虑您的游戏可能处于的状态。它可能是 -
- 设置 - 建立游戏
- 开始 - 前三秒
- 运行 - 在前三秒之后但在结束之前
- 结尾 - 最后三秒
- 结束 - 时间到了。
每次你的计时器计时时,你都需要考虑你需要采取什么行动以及你需要进入什么状态。你没有说你希望游戏持续多长时间,但假设是 30 秒。
开始新游戏时,您处于setup
状态;该按钮被禁用(即它不会对点击做出反应)并且您将分数设置为 0。您移动到 starting
状态。
在 starting
中显示倒计时。三秒钟后,您启用该按钮并进入 running
状态。
达到 27 秒后,您将进入 ending
状态并显示结束倒计时
最后时间到了,您进入 ended
状态,禁用按钮并显示分数。
你可以这样编码
enum GameState {
case setup
case starting
case running
case ending
case ended
}
class ViewController: UIViewController {
@IBOutlet weak var startButton: UIButton!
@IBOutlet weak var tapButton: UIButton!
@IBOutlet weak var countdownLabel: UILabel!
var gameState = GameState.ended
var gameTimer:Timer?
var numberOfTaps = 0
var gameStartTime = Date.distantPast
let GAMEDURATION: TimeInterval = 30
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
@IBAction func startButtonTapped(_ sender: UIButton) {
self.startGame()
}
@IBAction func tapMeButtonPressed(_ sender: UIButton) {
self.numberOfTaps += 1
}
func startGame() {
self.gameState = .setup
self.gameTimer = Timer.scheduledTimer(withTimeInterval:0.1, repeats: true) { timer in
let elapsedTime = -self.gameStartTime.timeIntervalSinceNow
let timeRemaining = self.GAMEDURATION-elapsedTime
switch self.gameState {
case .setup:
self.gameStartTime = Date()
self.tapButton.isEnabled = false
self.startButton.isEnabled = false
self.numberOfTaps = 0
self.gameState = .starting
case .starting:
if elapsedTime > 2.5 {
self.gameState = .running
self.tapButton.isEnabled = true
self.countdownLabel.text = "Go!"
} else {
let countdown = Int(3-round(elapsedTime))
self.countdownLabel.text = "\(countdown)"
}
case .running:
if timeRemaining < 4 {
self.gameState = .ending
}
case .ending:
let countdown = Int(timeRemaining)
self.countdownLabel.text = "\(countdown)"
if timeRemaining < 1 {
self.countdownLabel.text = "Stop"
self.gameState = .ended
self.tapButton.isEnabled = false
}
case .ended:
if timeRemaining <= 0 {
self.countdownLabel.text = "You tapped the button \(self.numberOfTaps) times"
self.startButton.isEnabled = true
self.gameTimer?.invalidate()
self.gameTimer = nil
}
}
}
}
}