Does anyone know how to make buttons change colors in swift? I have rectangle shaped buttons with text inside and a hollow background and I want the hollow space to change colors every 3 seconds or so. Can anyone help, I would greatly appreciate it!
Can you try
var counter = 0
var pageChangeTimer: Timer?
let colors = [UIColor.red,UIColor.green,,,,,,,,,] //,,,, set more
pageChangeTimer = Timer.scheduledTimer( withTimeInterval: 3.0 , repeats: true) { [weak self] timer in
if counter == colors.count {
counter = 0
}
self.btn.backgroundColor = colors[counter]
counter += 1
}
Extending #Sh_Khan's answer by generating random colors instead of an array of colors. I hope this helps:
Generating random colors
var counter = 0
var pageChangeTimer: Timer?
pageChangeTimer = Timer.scheduledTimer( withTimeInterval: 3.0 , repeats: true) { [weak self] timer in
if counter == colors.count {
counter = 0
}
self.btn.backgroundColor = colors[counter]
counter += 1
}
func getRandomColor() -> UIColor{
//Generate between 0 to 1
let red:CGFloat = CGFloat(drand48())
let green:CGFloat = CGFloat(drand48())
let blue:CGFloat = CGFloat(drand48())
return UIColor(red:red, green: green, blue: blue, alpha: 1.0)
}
Try this
var net = Bool()
override func viewDidLoad() {
super.viewDidLoad()
net = true
var timer = Timer.scheduledTimer(timeInterval: 0.3, target: self, selector: #selector(self.update), userInfo: nil, repeats: true)
}
// update method
#objc func update() {
// Something cool
if net == true {
// changebtn is the outlet of UIButton
changebtn.backgroundColor = UIColor.blue
net = false
}else{
changebtn.backgroundColor = UIColor.black
net = true
}
}
Related
If anyone wants to try this code you can just c+p the file and it will run
I actually have 2 problems in the code below.
1- I have a Timer and a CABasicAnimation that both run when a longPressGesture is triggered. The timer is 15 secs and I decided to use it to just time the animation once I noticed the issue. What's happening is the animation finishes before the timer does. The animation will close/reach its endpoint around 1 sec before the timer finishes AND before CATransaction.setCompletionBlock() and animationDidStop(_:finished) are called. Basically the animation finishes too early.
2- If I take my finger off of the button, the longPressGesture's .cancelled/.ended are called and I pause the timer in invalidateTimer via pauseShapeLayerAnimation(). That was the only way I found to actually stop the animation. When I long press the button again, I restart the timer and animation from the beginning. The issue is because pauseShapeLayerAnimation() is also called when the timer stops (goes to 15secs) CATransaction.setCompletionBlock() are never animationDidStop(_:finished) called. They are only called once I put my finger back on the button.
UPDATE I fixed the second issue by just checking if seconds are != 0 in the invalidateTimer function
import UIKit
class ViewController: UIViewController {
//MARK:- UIElements
fileprivate lazy var roundButton: UIButton = {
let button = UIButton(type: .system)
button.translatesAutoresizingMaskIntoConstraints = false
button.backgroundColor = UIColor.blue
return button
}()
fileprivate lazy var timerLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.monospacedDigitSystemFont(ofSize: 22, weight: .medium)
label.textColor = UIColor.black
label.text = initialStrForTimerLabel
label.textAlignment = .center
return label
}()
fileprivate lazy var box: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .brown
return view
}()
//MARK:- Properties
fileprivate let shapeLayer = CAShapeLayer()
fileprivate let bgShapeLayer = CAShapeLayer()
fileprivate var basicAnimation: CABasicAnimation!
fileprivate var maxTimeInSecs = 15
fileprivate lazy var seconds = maxTimeInSecs
fileprivate var milliseconds = 0
fileprivate lazy var timerStr = initialStrForTimerLabel
fileprivate lazy var initialStrForTimerLabel = "\(maxTimeInSecs).0"
fileprivate weak var timer: Timer?
//MARK:- View Controller Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
setAnchors()
setGestures()
}
fileprivate var wereCAShapeLayersAdded = false
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if !wereCAShapeLayersAdded {
wereCAShapeLayersAdded = true
roundButton.layer.cornerRadius = roundButton.frame.width / 2
addBothCAShapeLayersToRoundButton()
}
}
//MARK:- Animation Methods
fileprivate func addBothCAShapeLayersToRoundButton() {
bgShapeLayer.frame = box.bounds
bgShapeLayer.path = UIBezierPath(rect: box.bounds).cgPath
bgShapeLayer.strokeColor = UIColor.lightGray.cgColor
bgShapeLayer.fillColor = UIColor.clear.cgColor
bgShapeLayer.lineWidth = 6
box.layer.addSublayer(bgShapeLayer)
box.layer.insertSublayer(bgShapeLayer, at: 0)
shapeLayer.frame = box.bounds
shapeLayer.path = UIBezierPath(rect: box.bounds).cgPath
shapeLayer.strokeColor = UIColor.red.cgColor
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.lineWidth = 6
shapeLayer.lineCap = .round
shapeLayer.strokeEnd = 0
box.layer.addSublayer(shapeLayer)
}
fileprivate var isBasicAnimationAnimating = false
fileprivate func addProgressAnimation() {
CATransaction.begin()
basicAnimation = CABasicAnimation(keyPath: "strokeEnd")
removeAnimation()
if shapeLayer.timeOffset > 0.0 {
shapeLayer.speed = 1.0
shapeLayer.timeOffset = 0.0
}
basicAnimation.delegate = self
basicAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
basicAnimation.fromValue = 0
basicAnimation.toValue = 1
basicAnimation.duration = CFTimeInterval(seconds)
basicAnimation.fillMode = CAMediaTimingFillMode.forwards
basicAnimation.isRemovedOnCompletion = false
CATransaction.setCompletionBlock {
print("CATransaction completion called\n")
}
shapeLayer.add(basicAnimation, forKey: "myAnimation")
CATransaction.commit()
}
fileprivate func removeAnimation() {
shapeLayer.removeAnimation(forKey: "myAnimation")
}
fileprivate func pauseShapeLayerAnimation() {
let pausedTime = shapeLayer.convertTime(CACurrentMediaTime(), from: nil)
shapeLayer.speed = 0.0
shapeLayer.timeOffset = pausedTime
print("animation has paused/stopped\n")
}
//MARK:- Anchors
fileprivate func setAnchors() {
view.addSubview(box)
view.addSubview(roundButton)
view.addSubview(timerLabel)
box.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 3).isActive = true
box.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 3).isActive = true
box.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -3).isActive = true
box.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -3).isActive = true
roundButton.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 0).isActive = true
roundButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
roundButton.widthAnchor.constraint(equalToConstant: 75).isActive = true
roundButton.heightAnchor.constraint(equalToConstant: 75).isActive = true
timerLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10).isActive = true
timerLabel.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
timerLabel.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
}
}
//MARK:- CAAnimationDelegate
extension ViewController: CAAnimationDelegate {
func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
print("***** animation done *****\n")
}
}
//MARK:- Timer Methods
extension ViewController {
fileprivate func startTimer() {
timer?.invalidate()
timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true, block: { [weak self] _ in
self?.timerIsRunning()
})
}
#objc fileprivate func timerIsRunning() {
updateTimerLabel()
if !isBasicAnimationAnimating {
isBasicAnimationAnimating = true
addProgressAnimation()
}
milliseconds -= 1
if milliseconds < 0 {
milliseconds = 9
if seconds != 0 {
seconds -= 1
} else {
invalidateTimer()
print("timer done\n")
}
}
if milliseconds == 0 {
milliseconds = 0
}
}
fileprivate func updateTimerLabel() {
let millisecStr = "\(milliseconds)"
let secondsStr = seconds > 9 ? "\(seconds)" : "0\(seconds)"
timerLabel.text = "\(secondsStr).\(millisecStr)"
}
fileprivate func resetTimerSecsAndLabel() {
milliseconds = 0
seconds = maxTimeInSecs
timerLabel.text = initialStrForTimerLabel
}
fileprivate func invalidateTimer() {
if isBasicAnimationAnimating {
isBasicAnimationAnimating = false
if seconds != 0 {
pauseShapeLayerAnimation()
}
}
timer?.invalidate()
}
}
//MARK:- Gestures
extension ViewController {
fileprivate func setGestures() {
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapGesture))
roundButton.addGestureRecognizer(tapRecognizer)
let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(longPressGesture))
roundButton.addGestureRecognizer(longPressRecognizer)
}
#objc private func tapGesture(recognizer: UITapGestureRecognizer) {
print("tap\n")
}
#objc private func longPressGesture(recognizer: UILongPressGestureRecognizer) {
switch recognizer.state {
case .began:
resetTimerSecsAndLabel()
startTimer()
print("long gesture began\n")
case .ended, .cancelled:
invalidateTimer()
print("long gesture ended or cancelled\n")
case .failed:
print("long gesture failed\n")
default:
break
}
}
}
I think the animation finishing early is an illusion caused by three factors:
You are using CAMediaTimingFunctionName.easeInEaseOut which means the drawing starts slow and ends slow making it hard to judge the real end of drawing.
The drawing finishes by drawing over the start of the line which also makes it hard to see exactly when drawing stops.
Your timer should be subtracting 0.1 from the time before updating the label, because 0.1 has already passed when the timer first updates.
When I changed the timing function to CAMediaTimingFunctionName.linear and fixed the timer, it seemed to always hit 0 when the drawing finished.
I have a progress view like the one Snapchat and Instagram Stories have. My content changes after the progress view reaches to the end or when tapped on a button.
I'm reseting the progress view when content changes. Everything works as expected while there is no intervention. But when tapped on next button the progress view doesn't start again until the other loop executes.
You can see the video here quickly.
I came across this question while I was researching, I have the same scenario but I couldn't apply the principle as a newbie with swift 3.
Here is my code, any help would be highly appreciated:
func startTimer(){
self.timer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(myVievController.nextItem), userInfo: nil, repeats: false)
}
func updateProgressBar() {
self.progressView.setProgress(1.0, animated: false)
UIView.animate(withDuration: 2.8, animations: {() -> Void in
self.progressView.layoutIfNeeded()
}, completion: { finished in
if finished {
self.progressView.setProgress(0, animated: false)
}
})
}
func nextItem(){
// ...
self.updateUI(item: self.myCurrentItem)
// ...
}
func updateUI(item:MyItem){
self.updateProgressBar()
self.timer.invalidate()
self.startTimer()
// Clear old item and fill new values etc...
}
#IBAction func nextButtonPressed(_ sender: UIButton) {
self.nextItem()
}
Could also do it with a subclass:
class HelloWorld: UIProgressView {
func startProgressing(duration: TimeInterval, resetProgress: Bool, completion: #escaping (Void) -> Void) {
stopProgressing()
// Reset to 0
progress = 0.0
layoutIfNeeded()
// Set the 'destination' progress
progress = 1.0
// Animate the progress
UIView.animate(withDuration: duration, animations: {
self.layoutIfNeeded()
}) { finished in
// Remove this guard-block, if you want the completion to be called all the time - even when the progression was interrupted
guard finished else { return }
if resetProgress { self.progress = 0.0 }
completion()
}
}
func stopProgressing() {
// Because the 'track' layer has animations on it, we'll try to remove them
layer.sublayers?.forEach { $0.removeAllAnimations() }
}
}
This can be used by calling -startProgressing() when ever you need to start the progressView again from the start. The completion is called when it has finished the animation, so you can change the views etc.
An example of use:
progressView.startProgressing(duration: 5.0, resetProgress: true) {
// Set the next things you need... change to a next item etc.
}
You probably need something like this to update your progress bar: self.progressView.setProgress(0, animated: false)
func updateProgressBar() {
DispatchQueue.main.async {
self.progressView.setProgress(0.1, animated: false)
}
if self.progressView.Progress == 1.0 {
self.timer.invalidate()
} else {
self.timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(myVievController.updateProgressBar), userInfo: nil, repeats: false)
}
}
Then you can invalidate the timer and stop the update when you are at 100%
Example
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var progressView: UIProgressView!
var timer : Timer?
var timerCount = 0
var imageArray : Array<UIImage> = []
// MARK: - Lifecycle -
override func viewDidLoad() {
super.viewDidLoad()
// create gradient images
buildImageArray(duration: 3, highlightPercentage: 10.0, mainColor: .green, highlightColor: .yellow, imageWidth: Double(progressView.frame.width))
// set progressView to first image
progressView.progressImage = imageArray[0]
// set progressView progress
progressView.progress = 0.7
// schedule timer
if self.timer == nil {
self.timer = Timer.scheduledTimer(timeInterval: 1/60, target: self, selector: #selector(updateGradient), userInfo: nil, repeats: true)
RunLoop.main.add(self.timer!, forMode: .common)
}
}
func buildImageArray(duration: Int, highlightPercentage: Double, mainColor: UIColor, highlightColor: UIColor, imageWidth: Double){
let keyFrames = duration * 60
for i in 0..<keyFrames {
// Drawing code
let frame = CGRect(x: 0.0, y: 0.0, width: imageWidth, height: 1.0)
let layer = CAGradientLayer()
layer.frame = frame
layer.startPoint = CGPoint(x: 0.0, y: 0.5)
layer.endPoint = CGPoint(x: 1.0, y: 0.5)
var colors : [UIColor] = []
for n in 0..<keyFrames {
colors.append(mainColor)
}
let highlightKeyFrames : Int = Int(floor(Double(keyFrames) * (highlightPercentage/100)))
// 300 * .3 = 90 kf
for x in 0..<highlightKeyFrames {
let p = i+x
if p < keyFrames {
colors[p] = highlightColor
}
}
layer.colors = colors.map { $0.cgColor }
layer.bounds = frame
let image = UIImage.imageWithLayer(layer: layer)
imageArray.append(image)
}
}
// updateGradient
#objc func updateGradient(){
// crop image to match progress
let newWidth = self.progressView.frame.width * CGFloat(progressView.progress)
let progressImage = imageArray[timerCount].crop(rect: CGRect(x: 0, y: 0, width: newWidth, height: 1))
progressView.progressImage = progressImage
// increment timer
timerCount = timerCount + 1
if timerCount >= imageArray.count {
timerCount = 0
}
}
}
extension UIImage {
class func imageWithLayer(layer: CALayer) -> UIImage {
UIGraphicsBeginImageContextWithOptions(layer.bounds.size, layer.isOpaque, 0.0)
layer.render(in: UIGraphicsGetCurrentContext()!)
let img = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return img!
}
func crop( rect: CGRect) -> UIImage {
var rect = rect
rect.origin.x*=self.scale
rect.origin.y*=self.scale
rect.size.width*=self.scale
rect.size.height*=self.scale
let imageRef = self.cgImage!.cropping(to: rect)
let image = UIImage(cgImage: imageRef!, scale: self.scale, orientation: self.imageOrientation)
return image
}
}
What I am trying to do is increase the rate that the method spawnEnemy() is called on, and it works well using the starred numbers as Ints, but I felt like it goes by way too quickly so I thought of using Doubles and using the decimal point. However, if I go into the tenths spot of subtracting an amount from spawnRate in
self.spawnRate=spawnRate - 1.0 (I use anything but 0) spawnEnemy() will only be called on once in the simulator then nothing happens. Any advice or suggestions would be great. Thank you!
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var scoreLabel: UILabel!
var points: Int = 0
var tickCount=0.0 // **
var spawnRate=15.0 // Spawn every 15 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 - 0.5 // Change this to determine how quickly the spawn rate increases..... **
self.tickCount=self.spawnRate
}
}
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()
}
}
}
I think what's happening is you're trying to test a double with the equality operator. The problem is that there's always a bit of complexity in how doubles are stored that makes it very difficult to compare them with equality. Instead you need to do something like this:
if (--tickCount <= 0) {
That way you catch it going negative for sure, otherwise it can go right past 0 and continue to count down.
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()
}
Repeating NSTimers always fire on the same interval once you start them.
If you want to use a decreasing interval then instead of a repeating timer I suggest use use a single "one-shot" timer (not 2 timers). Create the timer with repeats:false. Then in your timer method (spawnEnemy, in your case) decrement your time interval and use it to create a new timer (also with repeats:false) using the new, shorter interval and calling the same method.
Your decreaseDouble function isn't going to work as written. It will always return the same value of 2.0 - 0.05, since you set num to 2.0 each time the function called. Instead get rid of the decreaseDouble function. Create an instance variable delayValue and assign it a value (2.0, for example) in your viewDidLoad. Then just subtract 0.05 from it each time spawnEnemy is called, spawn a new enemy, and create a new timer if delayValue hasn't gotten too small. (When delayValue gets really small you're going to be spawning 10 enemies a second. Eventually delayValue will go to zero, and a timer interval should not be <= 0.0.
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
I am trying to implement a vote system when users double tap the image. When the user double taps the image the vote count adds one and saves to parse. In my cell I have
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
//postsLabel.textAlignment = NSTextAlignment.Center
bottomBlurView.backgroundColor = UIColor(red: 0, green: 0.698, blue: 0.792, alpha: 0.75)
votesLabel!.textAlignment = NSTextAlignment.Right
let gesture = UITapGestureRecognizer(target: self, action: Selector("onDoubleTap:"))
gesture.numberOfTapsRequired = 2
contentView.addGestureRecognizer(gesture)
heartIcon?.hidden = true
//profileImageView.layer.cornerRadius = profileImageView.frame.height / 2
}
func onDoubleTap (sender: AnyObject) {
if self.complition != nil
{
self.complition!()
}
heartIcon?.hidden = false
heartIcon?.alpha = 1.0
UIView.animateWithDuration(1.0, delay:1.0, options:nil, animations: {
self.heartIcon?.alpha = 0
}, completion: {
(value:Bool) in
self.heartIcon?.hidden = true
})
}
}
and in my collection view controller I have
func onDoubleTap (indexPath:NSIndexPath)
{
let cell = self.collectionView.cellForItemAtIndexPath(indexPath) as! NewCollectionViewCell
let object = self.votes[indexPath.row]
if let likes = object["votes"] as? Int
{
object["votes"] = likes + 1
object.saveInBackgroundWithBlock{ (success:Bool,error:NSError?) -> Void in
println("Data saved")
}
cell.votesLabel?.text = "\(likes + 1)"
}
else
{
object["votes"] = 1
object.saveInBackgroundWithBlock{ (success:Bool,error:NSError?) -> Void in
println("Data saved")
}
cell.votesLabel?.text = "1"
}
}
However this does not add one and does not save to parse. Any help is appreciated. Thank you
You should place the first onDoubleTap in your collectionView's cellForItemAtIndexPath and configure it there.