1

I am in the process of writing a Simon style memory game, the phase of the game where the program shows the user the current list of stuff to remember seems to run instantly.

The idea is to step through the list (in the code I have placed 1 of each item as debug data) and change the colour on screen for a set period then move to the next.

I thought using for each item in memory array and then call a simple procedure to check which one it is and then change colour for a set period then back to original.

The code I have added here will work if I put breaks in between the test change colour (grey) and the original colour. But for some reason the timer does not seem too work.

Any ideas ?

import UIKit
import Foundation

var gameisrunning = false
var playererror = false
var memoryArray = [Int]()
var currentScore = 0

var timer = NSTimer()

class ViewController: UIViewController {

    @IBAction func startGameButton(sender: UIButton) {

        if gameisrunning == false {

            gameisrunning = true
            memoryArray.append(1) //for debug
            memoryArray.append(2) //for debug
            memoryArray.append(3) //for debug
            memoryArray.append(4) //for debug
            print(memoryArray) //for debug
            gameStart()

        } else {


        }

    }


    //these are to be implemented once i get the showing sequence sorted.

    @IBAction func redButton(sender: UIButton) {

    }

    @IBAction func greenButton(sender: UIButton) {

    }

    @IBAction func yellowButton(sender: UIButton) {

    }

    @IBAction func blueButton(sender: UIButton) {

    }

    @IBOutlet weak var redLabel: UILabel!
    @IBOutlet weak var greenLabel: UILabel!
    @IBOutlet weak var yellowLabel: UILabel!
    @IBOutlet weak var blueLabel: UILabel!
    @IBOutlet weak var scoreLabel: UILabel!

    func addAnotherItemToMemory () {

        // adds another item to the memory

        memoryArray.append(Int(arc4random_uniform(4)+1))
    }

    func gameStart () {

        // main body of game
        showPlayerTheMemory()
    }


    func showPlayerTheMemory () {

        // go through list and highlight the colors one at a time

        for eachItem in memoryArray {
            self.showColor(eachItem)
        }
    }


    func pauseForAWhile(length: Double) {

        timer = NSTimer.scheduledTimerWithTimeInterval(length, target:self, selector: nil , userInfo: nil, repeats: false)
        timer.invalidate()

    }


    func showColor(buttonItem: Int) {

        //check to see which color, change to grey (test color) and back to original after a set time.

        if buttonItem == 1  {

            self.redLabel.backgroundColor = UIColor.grayColor()
            pauseForAWhile(2)
            self.redLabel.backgroundColor = UIColor.redColor()
            print(buttonItem) //for debug

        } else if buttonItem == 2 {

            self.greenLabel.backgroundColor = UIColor.grayColor()
            pauseForAWhile(2)
            greenLabel.backgroundColor = UIColor.greenColor()
            print(buttonItem) //for debug

        } else if buttonItem == 3 {

            self.yellowLabel.backgroundColor = UIColor.grayColor()
            pauseForAWhile(2)
            yellowLabel.backgroundColor = UIColor.yellowColor()
            print(buttonItem) //for debug

        } else if buttonItem == 4 {

            self.blueLabel.backgroundColor = UIColor.grayColor()
            pauseForAWhile(2)
            blueLabel.backgroundColor = UIColor.blueColor()
            print(buttonItem) //for debug

        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

New relevant code changed to :

func colorChange (){

    self.redLabel.backgroundColor = UIColor.redColor()
    self.blueLabel.backgroundColor = UIColor.blueColor()
    self.yellowLabel.backgroundColor = UIColor.yellowColor()
    self.greenLabel.backgroundColor = UIColor.greenColor()
}

func showColor(buttonItem: Int, length: Double) {

    //check to see which color, change to grey (test color) and back to original after a set time.

    if buttonItem == 1  {

        self.redLabel.backgroundColor = UIColor.grayColor()
        timer = NSTimer.scheduledTimerWithTimeInterval(length, target:self, selector: ("colorChange") , userInfo: nil, repeats: false)
        print(buttonItem) //for debug

    } else if buttonItem == 2 {

        self.greenLabel.backgroundColor = UIColor.grayColor()
        timer = NSTimer.scheduledTimerWithTimeInterval(length, target:self, selector: ("colorChange") , userInfo: nil, repeats: false)
        print(buttonItem) //for debug

    } else if buttonItem == 3 {

        self.yellowLabel.backgroundColor = UIColor.grayColor()
        timer = NSTimer.scheduledTimerWithTimeInterval(length, target:self, selector: ("colorChange") , userInfo: nil, repeats: false)
        print(buttonItem) //for debug

    } else if buttonItem == 4 {

        self.blueLabel.backgroundColor = UIColor.grayColor()
        timer = NSTimer.scheduledTimerWithTimeInterval(length, target:self, selector: ("colorChange") , userInfo: nil, repeats: false)
        print(buttonItem) //for debug

    }
}

I have been scratching head all day trying to solve this issue which is baffling me. I have copied the new latest code in below, please discard code above.

I have four labels coloured red blue green and yellow. The array which has test data of 4 3 2 1 inside needs to step through each item - change the colour of the label for x secs then return it to normal colour. I have tried NSTimer, I have tried the current delay as in the code attached. Am I missing something as to where I place the code - should it be under viewdidload ??? I have tried for loops and the current code example shows switch in case it acted differently - it didnt !!

What happens basically is simultaneously all labels go grey (test colour right now) and then all go original colour after the x sec delay.

I need some help before I go insane. I honestly know it is something basic but I just cannot figure it out.

import UIKit
import Foundation

var gameisrunning = false
var playererror = false
var memoryArray = [Int]()
var currentScore = 0

class ViewController: UIViewController {

    @IBAction func startGameButton(sender: UIButton) {

        if gameisrunning == false {

            gameisrunning = true
            memoryArray.append(4) //for debug
            memoryArray.append(3) //for debug
            memoryArray.append(2) //for debug
            memoryArray.append(1) //for debug
            print(memoryArray) //for debug
            gameStart()

        } else {

        }
    }


    //these are to be implemented once i get the showing sequence sorted.

    @IBAction func redButton(sender: UIButton) {
    }
    @IBAction func greenButton(sender: UIButton) {
    }
    @IBAction func yellowButton(sender: UIButton) {
    }
    @IBAction func blueButton(sender: UIButton) {
    }

    @IBOutlet weak var redLabel: UILabel!
    @IBOutlet weak var greenLabel: UILabel!
    @IBOutlet weak var yellowLabel: UILabel!
    @IBOutlet weak var blueLabel: UILabel!
    @IBOutlet weak var scoreLabel: UILabel!

    func addAnotherItemToMemory () {
        // adds another item to the memory
        memoryArray.append(Int(arc4random_uniform(4)+1))
    }

    func gameStart () {
        // main body of game
        showPlayerTheMemory()
    }

    func delayProg (){
        //attempt 100093287492 to get a delay in program
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2.0 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) { () -> Void in
            self.blueLabel.backgroundColor = UIColor.blueColor()
            self.yellowLabel.backgroundColor = UIColor.yellowColor()
            self.greenLabel.backgroundColor = UIColor.greenColor()
            self.redLabel.backgroundColor = UIColor.redColor()

        }
    }

    func showPlayerTheMemory () {

        // go through list and highlight the colors one at a time

        for var i=0; i <= memoryArray.count-1; i++ {
            self.showColor(memoryArray[i])
        }
    }


    func showColor(buttonItem: Int) {

        //check to see which color, change to grey (test color) and back to original after a set time.

        switch (buttonItem) {

        case 1:
            self.redLabel.backgroundColor = UIColor.grayColor()
            delayProg()
            print(buttonItem) //for debug
        case 2:
            self.greenLabel.backgroundColor = UIColor.grayColor()
            delayProg()
            print(buttonItem) //for debug
        case 3:
            self.yellowLabel.backgroundColor = UIColor.grayColor()
            delayProg()
            print(buttonItem) //for debug
        case 4:
            self.blueLabel.backgroundColor = UIColor.grayColor()
            delayProg()
            print(buttonItem) //for debug
        default:
            print("error")
        }
    }


    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}
Ermiar
  • 1,078
  • 13
  • 20
  • 2
    You're creating the timer in `pauseForAWhile` and invalidate it in the next line. That cannot work. – vadian Feb 01 '16 at 14:14
  • Do i have to use the timer.invalidate or will the timer expire on its own ? Have I actually asked the timer to do anything or have I just declared it ? Sorry if these sound daft questions. – Stuck Beginner Feb 01 '16 at 14:17
  • The reason your code seems to run too quickly is because, like @vadian stated, you invalidate your timer immediately after starting it. You need to change the 'selector' to whatever function you want to call when the timer's time interval is reached. Then you have to move the 'timer.invalidate' line into that new function , this way the timer only invalidates once its selector is called after the correct period of time – MikeG Feb 01 '16 at 14:18
  • I can post an example below as an answer if you would like a visual aid – MikeG Feb 01 '16 at 14:19
  • That would be great, any help is very much appreciated. :) – Stuck Beginner Feb 01 '16 at 14:21
  • A timer is supposed to call a method (the `selector` parameter) in a class (the `target` parameter) once or multiple times (the `repeats` parameter) after a specific amount of time (the `interval` parameter). If `repeats` is `false` then the timer invalidates automatically. In your implementation the timer does nothing even after deleting the `invalidate` line. Read the documentation and the programming guide about `NSTimer` – vadian Feb 01 '16 at 14:21
  • http://stackoverflow.com/questions/35122809/changing-scenes-with-sprite-kit-after-a-certain-time-in-swift/35123014#35123014. ... This link is an example I posted yesterday that has just what your looking for – MikeG Feb 01 '16 at 14:22
  • First of all I am really thankful of the speed of the replies. I tried what you suggested @MikeG and added the selector and changed code around a bit to refresh all colors to original after the period. You can see a change now but it still does them all at the same time where as I was hoping to go Red - Grey - Red, Green - Grey - Green...., Blue - Grey - Blue. They all go grey then all colours go back to original !!! Am I using the correct method for what i want to achieve ? Added edited code above – Stuck Beginner Feb 01 '16 at 14:32
  • I do not see where you specified `length` which you use as your interval. This may be causing that problem. – MikeG Feb 01 '16 at 14:41

1 Answers1

1

Here is an example of proper implementation of NSTimer()

var myTimer = NSTimer()

func startTimer() {
    myTimer = NSTimer.scheduledTimerWithTimeInterval(10, target: self, selector: "myFunction", userInfo: nil, repeats: true)
}

func myFunction() {
myTimer.invalidate()
    //do other stuff
}
//the selector is "myFunction", this will be the name of the function that you wish to call every time the timer reaches its specified intervl
//the interval in this case is 10 seconds. In my experience NSTimer is good down to the second but is not precise enough beyond that
//repeats: true ... this will tell the timer to repeat its action consistently firing the selector each time the given time interval is reached. If repeat is set to false then the timer only fires once
//use myTimer.invalidate to stop the timer and to stop calling the selector.

be sure to invalidate your timer or set repeats: false to make sure it doesn't go forever. Make sure your selector is spelled exactly the same as your function. if your function is func myFunction() then the selector should be "myFunction". Make sure you specify a valid time interval, which is taken as seconds.

MikeG
  • 3,745
  • 1
  • 29
  • 51