1

I have an NSMutableArray in my game, in which the array stores "cloud" objects. When spawning the cloud, I iterate through the array and check whether there is a cloud that is nearby, if there is, then I do not spawn the cloud. Here is the code:

BOOL isCloudInRange = NO;
float distance;
do {
    //Horizontal Position
    isCloudInRange = NO;

    if (self.sprite.physicsBody.velocity.dx > 0) {
        cloud.position = CGPointMake(self.sprite.position.x + HW*16/5, 0);
    }
    else if (self.sprite.physicsBody.velocity.dx <0) {
        cloud.position = CGPointMake(self.sprite.position.x-HW*16/5, 0);
    }
    else {
        cloud.position = CGPointMake(self.sprite.position.x, 0);
    }

    //Vertical Position

    int offset = arc4random() % (int) 2*self.frame.size.height;
    offset -= (int) (self.frame.size.height);

    if (self.sprite.physicsBody.velocity.dy > 0) {
        cloud.position = CGPointMake(cloud.position.x, self.sprite.position.y + offset + self.sprite.physicsBody.velocity.dy);
    }
    else if (self.sprite.physicsBody.velocity.dy <0) {
        cloud.position = CGPointMake(cloud.position.x, self.sprite.position.y - offset - self.sprite.physicsBody.velocity.dy);
    }
    else {
        cloud.position = CGPointMake(cloud.position.x, self.sprite.position.y + 16*HW/5);
    }
    if (cloud.position.y <= 300) {
        cloud.position = CGPointMake(cloud.position.x, 100 + arc4random() %200);
    }

    // THIS IS WHERE THE ERROR HAPPENS

    for (SKNode *myNode in arrayOfClouds) {
        float xPos = myNode.position.x;
        float yPos = myNode.position.y;
        distance = sqrt((cloud.position.x - xPos) * (cloud.position.x - xPos) + (cloud.position.y - yPos) * (cloud.position.y - yPos));
        if (distance < 300.0f) {
            NSLog(@"%f",distance);
            isCloudInRange = YES;
        }
    }

} while (isCloudInRange);

If the bottom piece of code is changed to if (distance < 150.0f) everything works fine. If the distance is kept at 300.0f, however, in a couple seconds or runtime, the game starts iterating forever. Here is an example of a typical log file with this code:

![hola][1]

Click this link if above image doesn't appear (I don't know why it isn't): https://i.sstatic.net/qX8h7.png

The logged floats are the distances between the cloud and whatever cloud is nearby. None of these distances seem to match (I don't have a million clouds spawning every second, they're set to spawn every second or so), and since it freezes with these logs as soon as the game starts, I know there cannot be that many clouds. What is happening? Please help.. Thanks!

5
  • 2
    You should think of your problem again and rename the question. This is definitely about your distance calculations, not the NSMutableDictionary. You might also think of the concept. Dealing with "probably-forever-loops" is a bit dangerous and if you have chance to, try to avoid them. Commented Nov 10, 2014 at 4:25
  • Without disrespect, I disagree. I am using the exact same distance calculation to iterate over the same array and delete clouds that are far away from the character. That code works fine, so I do not see why this wouldn't. I agree potential forever loops should be avoided, and I can easily find a workaround, but I learn from error and would like to know what went wrong. Commented Nov 10, 2014 at 4:29
  • I'm not totally sure I understand the code you posted, but my guess is that when you set the distance to 300, after you add just a few clouds your game reaches a state where no matter where your new cloud tries to spawn, it is always within range of an existing cloud. Your do... while loop is therefore always going to evaluate to true, and you get stuck in an infinite loop. Commented Nov 10, 2014 at 4:37
  • @Andriko13: I comprehend your confusion. And yes, I see it shouldn't be a calculation issue, but NSMutableArray? This would be strange, never heard of such issues... Could you try using an float in your cloud.position.y <= if statement? I had hard problems with this tiny missing .0f in the past. Commented Nov 10, 2014 at 4:38
  • User, the clouds are moving constantly, therefore every couple milliseconds a spot SHOULD be available. Julian, it did not work. I would assume it wouldn't either, as everything works with a lower distance Commented Nov 10, 2014 at 4:46

2 Answers 2

1

The main issue I can see here is the following:

You have a do..while loop running checking your cloud distance. Once a cloud is in range, you mark it as YES and re-run the loop. The cloud's X position is never changed in the loop which means it will never move out of range again (infinite loop).

Ideally this is a check that should happen once per game loop (remove the do while).

Also it will be a little more efficient if you put a break; in your for loop. Once a cloud has been found in range there is no need to check the others so you may as well end you loop here.

for (SKNode *myNode in arrayOfClouds) {
    float xPos = myNode.position.x;
    float yPos = myNode.position.y;
    distance = sqrt((cloud.position.x - xPos) * (cloud.position.x - xPos) + (cloud.position.y - yPos) * (cloud.position.y - yPos));
    if (distance < 300.0f) {
        NSLog(@"%f",distance);
        isCloudInRange = YES;
        break; // <--drop out of the for each loop now
    }
}
Sign up to request clarification or add additional context in comments.

6 Comments

Nice call with the break. However, the clouds are moving left and right very quickly after spawn. Even if a cloud is in the range, the next few frames or so it wouldn't be
I'm assuming that your posted code is running in a background thread then? Otherwise nothing is changing as you never leave the block of code posted.
This is a reaaaally stupid question, but how do I know if it's a background thread or not? Ive always knew the basics about threads, but never really bothered to look into the concept
I'm guessing if you have to ask that questing then you haven't taken the time to run it in a background thread :) If that is the case then the do while loop is running on your main thread, which means no other code will run until that loop finishes. In your loop, if you are in range of a cloud there is no code in there to move the cloud, which means you will never get out of range. Also if there was code in there to move the cloud, the cloud will appear to jump on screen as the rendering will never happen while a cloud is in range. Try removing the do while and see what happens
To just give a brief explanation on threads. Your app runs on the main thread. The main thread is responsible for handling UI interactions and UI display. UI stuff cannot run in a background thread. Therefore for if you have blocking code (long running loops, comms calls etc.) the app will appear to freeze. These long running calls are what gets moved to a "background thread" which allows them to run in parallel to the main thread (which allows the UI to continue working, and in your case. Your game to continue running)
|
1

You say "When spawning the cloud, I iterate through the array and check whether there is a cloud that is nearby, if there is, then I do not spawn the cloud" but to me it looks like your doing the exact opposite. If a cloud is in range (<300) you set isCloudInRange to yes and repeat. Once there are enough clouds it always finds a cloud in range it should loop indefinitely. The more clouds you spawn the harder and harder this is to every get out of the loop ( noting you set it to no at top)

If you are moving clouds and checking to create them on the same thread ( same run loop of code or function calls that are synchronous), you can try moving this code to a background thread, using dispatch_asynch(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), your code block here); and see if that helps.

Info on how to set up concurrency with dispatch_asynch is here:

https://developer.apple.com/library/mac/documentation/General/Conceptual/ConcurrencyProgrammingGuide/ConcurrencyProgrammingGuide.pdf

and blocks are explained:

https://developer.apple.com/library/mac/documentation/cocoa/conceptual/ProgrammingWithObjectiveC/WorkingwithBlocks/WorkingwithBlocks.html#//apple_ref/doc/uid/TP40011210-CH8-SW1

8 Comments

Can you explain a bit further? I can see where you're going, but I don't believe this is the case, as it works when the distance is reduced to 100.
Oh and the clouds are moving very fast, which is why I made an assumption that it won't loop indefinitely
i guess its looking like a deadlock situation. once there are enough clouds it gets stuck in the loop
and the greater the range the more likely you encouter deadlock - for example set it to entire screen size it would happen very fast
I would agree, but this happens when the array count is exactly 3 (aka at the start of the game). To follow up, when there are only 3 elements, i do not understand all of the NSLogs
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.