Search code examples
iosxcodenstimernstimeinterval

Using Decreasing Variable as NSTimeInterval in swift


I am trying to decrease a Double variable by 0.05 every second to speed up the function spawnEnemy() but I cannot find a way that works well. So, I am trying to pretty much "spawn" more enemies(UIButtons) in a shorter amount of time. Any help would be great and very appreciated. Thank you! My code below compiles fine but does not speed up the NSTimer controlling the function spawnEnemy()

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var scoreLabel: UILabel!

    var points: Int = 0

    func randomPoint() -> CGPoint {
        let randomPoint: CGPoint = CGPoint(x:CGFloat(arc4random()%320),y:CGFloat(568-arc4random()%390))
        return randomPoint
    }

    func randomColor() -> UIColor {
        let red = CGFloat(drand48())
        let green = CGFloat(drand48())
        let blue = CGFloat(drand48())
        return UIColor(red: red, green: green, blue: blue, alpha: 1.0)
    }

    func spawnEnemy() {
        let enemy: UIButton = UIButton(frame: CGRect(x: 160, y: 160, width: 100, height: 100))
        enemy.backgroundColor = randomColor()
        enemy.center = randomPoint()
        enemy.addTarget(self, action: Selector("buttonPushed:"), forControlEvents: UIControlEvents.TouchUpInside)
        self.view.addSubview(enemy)
    }

    func buttonPushed(sender : UIButton) {
        if sender.frame.height < 50 || sender.frame.width < 50 {
            sender.frame = CGRectMake(sender.frame.origin.x, sender.frame.origin.y, 50, 50)
            sender.backgroundColor = randomColor()
            sender.center = randomPoint()
            return
        }
        sender.backgroundColor = UIColor.blackColor()
        points = points + 1
        scoreLabel.textAlignment = .Center
        scoreLabel.text = "\(points)"
        scoreLabel.backgroundColor = UIColor.blackColor()
    }
    func decreaseDouble() -> Double {
        var num: Double = 2.0
        num = num - 0.05
        return num
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        NSTimer.scheduledTimerWithTimeInterval(decreaseDouble(), target: self, selector: Selector("spawnEnemy"), userInfo: nil, repeats: true)

        NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("decreaseDouble"), userInfo: nil, repeats: false)

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()

    }

}

Below is my new code. Any finals things or should this work? I also added a while statement so you can only receive points while the enemy is not black,otherwise you could just keep clicking on wherever enemies have been spawned(but were clicked) and keep getting points. However, now when i run the application two enemies are already spawned but i can still click on them(only being allowed to get two points)

    import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var scoreLabel: UILabel!

    var points: Int = 0

    func randomPoint() -> CGPoint {
        let randomPoint: CGPoint = CGPoint(x:CGFloat(arc4random()%320),y:CGFloat(568-arc4random()%390))
        return randomPoint
    }

    func randomColor() -> UIColor {
        let red = CGFloat(drand48())
        let green = CGFloat(drand48())
        let blue = CGFloat(drand48())
        return UIColor(red: red, green: green, blue: blue, alpha: 1.0)
    }

    func spawnEnemy() {
        let enemy: UIButton = UIButton(frame: CGRect(x: 160, y: 160, width: 100, height: 100))
        enemy.backgroundColor = randomColor()
        enemy.center = randomPoint()
        enemy.addTarget(self, action: Selector("buttonPushed:"), forControlEvents: UIControlEvents.TouchUpInside)
        self.view.addSubview(enemy)
    }

    func buttonPushed(sender : UIButton) {
        if sender.frame.height < 50 || sender.frame.width < 50 {
            sender.frame = CGRectMake(sender.frame.origin.x, sender.frame.origin.y, 50, 50)
            sender.backgroundColor = randomColor()
            sender.center = randomPoint()
            return
        }
        while sender.backgroundColor != UIColor.blackColor() {
            points = points + 1
            scoreLabel.textAlignment = .Center
            scoreLabel.text = "\(points)"
            scoreLabel.backgroundColor = UIColor.blackColor()
            sender.backgroundColor = UIColor.blackColor()
        }
        delayTime -= 0.05
    }

    var delayTime: Double = 2.0


    override func viewDidLoad() {
        super.viewDidLoad()

        delayTime = 2.0

        NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: Selector("spawnEnemy"), userInfo: nil, repeats: false)

        NSTimer.scheduledTimerWithTimeInterval(delayTime, target: self, selector: Selector("spawnEnemy"), userInfo: nil, repeats: true)

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()

    }

Solution

  • You have the right idea. I would use the repeating timer as a 'tick' and then keep two properties - One is the tick count and the other is the tick count before a new enemy is spawned. By decreasing the latter you can speed up the rate of spawning.

    Something like this

    import UIKit
    
    class ViewController: UIViewController {
    
        @IBOutlet weak var scoreLabel: UILabel!
    
        var points: Int = 0
    
        var tickCount=0    
    
        var spawnRate=100   // Spawn every 10 seconds to start with
    
        var spawnTimer:NSTimer!
    
         override func viewDidLoad() {
            super.viewDidLoad()
    
            self.tickCount=self.spawnRate
    
            self.spawnTimer=NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: Selector("tick"), userInfo: nil, repeats: true)
    
        }
    
        func tick() {
           if (--tickCount == 0) {
              self.spawnEnemy()
              self.spawnRate=spawnRate - 2  // Change this to determine how quickly the spawn rate increases
              self.tickCount=self.spawnRate
           }
        }
    

    You can modify the tick rate and tick decrement amounts as required to give you the range you are after