So I'm doing a simple game on swift 5 and I basically have a 3..2..1.. go timer to start the game and then a 3..2..1..stop timer to stop the game. And finally a function that displays the score. I need a way for each function call to wait for the timer to be done before the next one begins, any suggestions? Here's my code so far. (Also if you have any other suggestions on the app let me know as well, the end goal is to register how many taps of a button you can do in 3 seconds)
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)"
}
}
The approach shouldn't be that the function calls wait for the timer to get finished, rather the timers should call the functions when they finish.
So, you need to move below function calls out of viewDidLoad
and put them inside the Timer
blocks.
self.gameCountdown(seconds: seconds)
self.displayFinalScore()
Ie the function call self.gameCountdown(seconds: seconds)
will go inside the timer block started in startCountdown
. In that, when you are invalidating the timer when the seconds become 0, you call gameCountdown
.
Similarly, in the timer started in gameCountdown
, you call the self.displayFinalScore
when the seconds become 0.
Few other suggestions. You should avoid checking properties in tapMeButtonPressed
. You should rather disable and enable the tap me button instead. Ie enable it when you start the gameCountdown and disable it when it ends.
Similarly, you shouldn't need to check the state of the timers in displayFinalScore
. It should just do one thing ie display the final score.
Will save you a lot of headaches later:). My 2 cents.
You should think about the states your game could be in. It could be -
Each time your timer ticks you need to consider what action do you need to take and what state do you need to move to. You haven't said how long you want the game to last, but let's say it is 30 seconds.
When a new game is started, you are in the setup
state; The button is disabled (ie. it doesn't react to taps) and you set the score to 0. You move to the starting
state. In the starting
you show the countdown. After three seconds you enable the button and move into the running
state. Once you reach 27 seconds, you move into the ending
state and show the end count down Finally time is up and you move into the ended
state, disable the button and show the score.
You could code it something like this
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
}
}
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.