Andriko13
Andriko13

Reputation: 990

NSMutableArray Acting Weird

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!

Upvotes: 1

Views: 81

Answers (2)

LanternMike
LanternMike

Reputation: 664

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

Upvotes: 1

Matthew Cawley
Matthew Cawley

Reputation: 3008

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
    }
}

Upvotes: 1

Related Questions