How to speed up a Sprite Kit game after every additional 50 points

I am making a 2D game with Sprite Kit and I need to add a method to speed up the game after every 50 points.

I worked out a method that adds the speed as wanted, but I have to copy, paste and adjust an if-statement in the update method for every additional 50 points.

  • What is the best method of synchronizing audio across iOS devices with WiFi?
  • How to add minutes to current time in swift
  • Swift Array Append Overwriting Other Array Values
  • How did Whatsapp app removed app's compatibility for iPad?
  • show UIAlertController outside of ViewController
  • Self-Sizing Table View Cell in Xcode 9
  • Another problem with my solution is that I have to give my points an increment right after speeding it up, because if not the game speeds up completely, though I don’t know why.

    Here is my solution so far:

    // inside the update method
    // points are added when an enemy is destroyed
    // pointSpeed is the float variable that is used to change positions
    
    if (points == 4) {
        pointSpeed++;
        points++;
    }
    if (points == 8) {
        pointSpeed++;
        points++;
    }
    if (points == 12) {
        pointSpeed++;
        points++;
    }
    

    I would like to implement this feature without being forced to do all increments manually and without the game speeding up without points increments.

    2 Solutions Collect From Internet About “How to speed up a Sprite Kit game after every additional 50 points”

    Swift way

    You can use didSet property observer to change the game speed based on the current score:

    import SpriteKit
    
    class GameScene: SKScene {
    
        var score:Int = 0 {
    
            didSet{
    
                if score % 10 == 0 {
                   gameSpeed += 0.5
                }
    
                label.text = "Score : \(score), Speed : \(gameSpeed)"
            }
    
        }
    
        var gameSpeed:Double = 1.0
    
        var label:SKLabelNode = SKLabelNode(fontNamed: "ArialMT")
    
        override func didMoveToView(view: SKView) {
            /* Setup your scene here */
    
            label.text = "Score : \(score), Speed : \(gameSpeed)"
            label.position = CGPoint(x: CGRectGetMidX(frame), y: CGRectGetMidX(frame))
            label.fontSize = 18
    
            addChild(label)
    
        }
    
        override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    
            score++
        }
    
    }
    

    From the docs:

    didSet is called immediately after the new value is stored.

    So, immediately after the new score is set, you should update the gameSpeed variable.

    Objective-C way

    In Objective-C there is no such a thing which can provide the exact same behaviour like Swift’s didSet and willSet property observers. But there are another ways, for example you can override a score’s setter, like this:

    #import "GameScene.h"
    
    @interface GameScene()
    
    @property(nonatomic, strong) SKLabelNode *label;
    
    @property(nonatomic, assign) NSUInteger score;
    
    @property(nonatomic, assign) double gameSpeed;
    
    @end
    
    @implementation GameScene
    
    -(instancetype)initWithCoder:(NSCoder *)aDecoder{
    
    NSLog(@"Scene's initWithSize: called");
    
    if(self = [super initWithCoder:aDecoder]){
    
            /*
    
             Instance variables in Obj-C should be used only while initialization, deallocation or when overriding accessor methods.
             Otherwise, you should use accessor methods (eg. through properties).
    
            */
    
            _gameSpeed  = 1;
            _score      = 0;
    
           NSLog(@"Variables initialized successfully");
        }
    
        return self;
    }
    
    -(void)didMoveToView:(SKView *)view {
    
        self.label      = [SKLabelNode labelNodeWithFontNamed:@"ArialMT"];
        self.label.fontSize = 18;
        self.label.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
        self.label.text = [NSString stringWithFormat:@"Score : %lu, Speed %f", self.score, self.gameSpeed];
        [self addChild:self.label];
    
    }
    
    //Overriding an actual setter, so when score is changed, the game speed will change accordingly
    -(void)setScore:(NSUInteger)score{
    
        /*
    
         Make sure that you don't do assigment like this, self.score = score, but rather _score = score
         because self.score = somevalue, is an actual setter call - [self setScore:score]; and it will create an infinite recursive call.
    
         */
        _score          = score;
    
    
        if(_score % 10 == 0){
            self.gameSpeed += 0.5;
        }
    
        // Here, it is safe to to write something like self.score, because you call the getter.
    
        self.label.text = [NSString stringWithFormat:@"Score : %lu, Speed %f", self.score, self.gameSpeed];
    
    }
    
    -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    
        self.score++;
    }
    
    @end
    

    Or, I guess, you can do the same using KVO, but for your example because of simplicity, you can just override a setter. Or maybe you could just make a custom method which will increase the score, handle the gameSpeed’s updating logic, and update the speed if necessary:

    //Whenever the player scores, you will do this
    [self updateScore: score];
    

    So, you will have an additional method definition, which must be called when player scores, in compare to this (assuming that score’s setter is overridden):

    self.score = someScore; 
    

    It’s really up to you.

    Hope this make sense and it helps!

    EDIT:

    I’ve changed the initWithSize: to initWithCoder, because initWithSize is not called when the scene is loaded from sks, which is probably how you are doing it, due to fact that in Xcode 7 scene is loaded by default from .sks file.

    if you want to update the speed at regular intervals, you can use the modulus operator – take the remainder after dividing by your interval – if that equals zero, take action.
    The reason you find the game speeding up completely is that the next time through the update function, it’s still on the right points level, and it just increments the speed – you could add another variable to track if you’re ready for an increment

    // as part of class declaration
    var bReadyForIncrement : Bool = true
    let pointIncrement : Int = 4  // or whatever you need
    
    
    // inside the update method
    // points are added when an enemy is destroyed
    // pointSpeed is the float variable that is used to change positions
    
    if (points % 4) 
    {
        if bReadyForIncrement
        {
           pointSpeed++;
           bReadyForIncrement = false // set this to true wherever you add points
        }
    }