-1

I have made a game in sprite kit in which balls shoot up from the bottom. I had made different Xcode Projects for each scene and then I compiled all of them into one. They do get compiled without any errors but the scenes do not run as expected.

In the different projects, infinite balls come up from the bottom, but when I run the compiled project, only one ball comes. I call addBall in didMoveToView.

-(void)addBall {

    int randomNumber = arc4random_uniform(5);

    if (randomNumber == 0) {
        [self addRedBall];

        SKAction *moveBall = [SKAction moveToY:CGRectGetMaxY(self.frame) duration:durationTimeMED];
        [redBall runAction:moveBall];

        [self performSelector:@selector(addBall) withObject:nil afterDelay:t];
    }

    else if (randomNumber == 1) {
        [self addBlueBall];
        SKAction *moveBall = [SKAction moveToY:CGRectGetMaxY(self.frame) duration:durationTimeMED];
        [blueBall runAction:moveBall];

        [self performSelector:@selector(addBall) withObject:nil afterDelay:t];

    }

    else if (randomNumber == 2) {
        [self addGreenBall];
        SKAction *moveBall = [SKAction moveToY:CGRectGetMaxY(self.frame) duration:durationTimeMED];
        [greenBall runAction:moveBall];

        [self performSelector:@selector(addBall) withObject:nil afterDelay:t];
    }

    else if (randomNumber == 3) {
        [self addCyanBall];
        SKAction *moveBall = [SKAction moveToY:CGRectGetMaxY(self.frame) duration:durationTimeMED];
        [cyanBall runAction:moveBall];

        [self performSelector:@selector(addBall) withObject:nil afterDelay:t];
    }

    else if (randomNumber == 4) {
        [self addYellowBall];
        SKAction *moveBall = [SKAction moveToY:CGRectGetMaxY(self.frame) duration:durationTimeMED];
        [yellowBall runAction:moveBall];

        [self performSelector:@selector(addBall) withObject:nil afterDelay:t];
    }
}

Isn't the performSelector is supposed to run infinitely many times?
Is there something that I am doing wrong? Or is there something that I am missing?

UPDATE: I am declaring the variables just after the @implementation and before any method. I am declaring the balls (all the colors) like this in the same area:

SKSpriteNode *yellowBall;  

and then setting all their respective properties in their respective methods.
t is NSTimeInterval type variable which I declared like this in the same area:

NSTimeInterval t;
Cœur
  • 37,241
  • 25
  • 195
  • 267
Rohan Kalantri
  • 103
  • 1
  • 9
  • 1
    Using `performSelector:withObject:afterDelay:` for timed repetitive actions is bad practice -if nothing else, it cannot be cancelled. Take a look at `NSTimer`. – Jakub Vano Mar 01 '15 at 16:44
  • Can you please explain what you mean? I am a beginner – Rohan Kalantri Mar 01 '15 at 16:46
  • @JakubVano That is not necessarily true, you can call `cancelPreviousPerformRequestsWithTarget:selector:object:` to cancel previously scheduled invocations. Of course, it doesn't give you fine grained control over what is cancelled and what isn't, but still, it is there. – JustSid Mar 01 '15 at 17:20
  • You will want to post the entire method as @Duncan C mentioned. – Skyler Lauren Mar 05 '15 at 12:30
  • I have updated the post with the entire method, please tell if you need some more code to see what is wrong @SkylerLauren – Rohan Kalantri Mar 05 '15 at 18:27
  • I don't see anything initially that would cause what you are explaining, but I would be interested in seeing how you declare your variables. You aren't calling self. so I am guessing they are iVars and I have seen this done incorrectly causing constants that persist and that could cause a lot of issues. You may how to show where you declare what t, yellowball, cyanBall ect. are first initially declared. – Skyler Lauren Mar 05 '15 at 18:34
  • I have updated the question with how I create the variables, please have a look and let me know if you need more code to know what is wrong. – Rohan Kalantri Mar 05 '15 at 18:45
  • Are those variable in { }'s? If not that could be the issue. – Skyler Lauren Mar 05 '15 at 18:54
  • No they aren't in any parenthesis. Should I add them? – Rohan Kalantri Mar 05 '15 at 18:56
  • http://stackoverflow.com/questions/13566862/where-to-put-ivars-in-modern-objective-c look at option 1 in answer. – Skyler Lauren Mar 05 '15 at 18:57
  • Okay, so i put the NSTimeInterval, integers, NSIntegers, SKSpriteNode, CGPoint, SKLabelNode and BOOLs in the parentheses. I added _ before every name. When I run it, I see no difference. What am I doing wrong? Can you please explain in detail with simple language? I am noob. @SkylerLauren – Rohan Kalantri Mar 05 '15 at 19:28
  • Well to be honest I am still unsure. It could also have to do with how you are loading multiple scenes. If you like you can send me an email at skyler@skymistdevelopment.com and I will try to help further later tonight. I don't think back and forth here in SO will be helpful at this point. – Skyler Lauren Mar 05 '15 at 19:31

2 Answers2

0

So you want addBall to call itself repeatedly? And then 1 out of 4 times it would add a ball?

You need to move the call to performSelector:withOBject:afterDelay outside of the if statement.

The way you've written it, it will only call itself again if randomNumber == 0. In all other cases, it stops. So your odds are 1:4 of it calling itself again once. The odds are 1:16 of it calling itself again twice, and 1:64 of it calling itself again 3 times.

Duncan C
  • 128,072
  • 22
  • 173
  • 272
0

To elaborate on my comment:

If it were functioning like you intended, once you start -addBall action, you could never stop recursive calls.

Better approach would be to have instance variable e.g. NSTimer* addBallTimer and use it for repetitive calls of -addBall.

When you want to start adding balls:

addRedTimer = [NSTimer scheduledTimerWithTimeInterval:delayTimeM 
                                               target:self 
                                             selector:@selector(addBall)
                                             userInfo:nil
                                              repeats:YES];

And remove recursion from -addBall

-(void)addBall {

    int randomNumber = arc4random_uniform(4);

    if (randomNumber == 0) {
        [self addRedBall];

        SKAction *moveBall = [SKAction moveToY:CGRectGetMaxY(self.frame) duration:durationTimeM];
        [redBall runAction:moveBall];
    } 
}  

This way you can allways cancel action with [addBalTimer invalidate];

Jakub Vano
  • 3,833
  • 15
  • 29
  • Still didn't quite get you, I put the addRedTimer declaration after calling addRedBall. What do I do after that? – Rohan Kalantri Mar 01 '15 at 17:40
  • When I fire the timer, it gives me a whole list of errors – Rohan Kalantri Mar 01 '15 at 18:10
  • Can you please explain where do I put the "addRedTimer" I am real noob. – Rohan Kalantri Mar 05 '15 at 11:18
  • @Jakub Vano He is going off of a fix I gave him in http://stackoverflow.com/questions/28155526/how-do-i-add-and-animate-infinite-number-of-objects-coming-from-the-bottom-of-th NSTimer would be a better solution. I was more worried about fixing what he had at the time. With that being said you might want to address it on the other question. Although looks like the code has gone through some evolution already and the entire method needs to be posted. – Skyler Lauren Mar 05 '15 at 12:33