Question

I've been developing a game in Cocos2D for about 3 years which utilizes a transparent background to show a UIView. The reason for this is to have the parallax background still run as Cocos2D does scene transitions.

I'm having a new issue that started when I updated to iOS 7. Slow down occurs in combination of these circumstances:

-ONLY if the parallax background's frame position has changed.

-If I destroy an enemy which emits small sprites and a particle effect.

So it's the combination of those two things and it only happens sometimes. The debug value of the frame rate does not dip when the slow down happens. If I load a new scene it goes back to normal. Sometimes when I destroy another enemy the slow down disappears as well.

I have code in my parallax UIView that runs just about every frame of in-gameplay. I summed down the issue to one line:

-(void)updateImagePosWithPos:(CGPoint)pos{ // in game

    // create vel based on last currentPos minus new pos

    CGPoint vel = CGPointMake(currentPos.x-pos.x, currentPos.y-pos.y);

    // init variables tmpVel and tempTotalImages

    CGPoint tmpVel = CGPointZero;

    int tmpTotalImages = 0;

    // create indexLayerArr

    NSMutableArray *indexLayerArr = [NSMutableArray array];

    // for every parallax layer, add the number of images horizontally minus 1 to indexLayerArr

    for (int j=0; j<totalLayers; ++j){

        [indexLayerArr addObject:[NSNumber numberWithInt:[[totalImagesArr objectAtIndex:j] intValue]-1]];

    }

    int i = 0;


    for (UIImageView *imageView in self.subviews) {

        CGRect tmpRect = CGRectZero;

        NSMutableArray *tmpRectArr = [rectContainer objectAtIndex:imageView.tag];

        float speed = 0.00;


        tmpTotalImages = [[totalImagesArr objectAtIndex:imageView.tag] intValue];

        speed = [[speedArr objectAtIndex:imageView.tag] floatValue];

        tmpVel = CGPointMake(vel.x*speed, vel.y*speed);

        i = [[indexLayerArr objectAtIndex:imageView.tag] intValue];

        tmpRect = [[tmpRectArr objectAtIndex:i] CGRectValue];


        if(tmpRect.origin.x - tmpVel.x > wins.width){

            tmpRect.origin.x -= (tmpTotalImages)*tmpRect.size.width;

        }
        else if(tmpRect.origin.x - tmpVel.x < -tmpRect.size.width){

            tmpRect.origin.x += (tmpTotalImages)*tmpRect.size.width;

        }

        tmpRect.origin.x -= tmpVel.x;
        tmpRect.origin.y += tmpVel.y;

        [tmpRectArr replaceObjectAtIndex:i withObject:[NSValue valueWithCGRect:tmpRect]];


        imageView.frame = [[tmpRectArr objectAtIndex:i] CGRectValue]; // <-- slow down cause



        i--;

        [indexLayerArr replaceObjectAtIndex:imageView.tag withObject:[NSNumber numberWithInt:i]];


    }

    currentPos = CGPointMake(pos.x, pos.y);

}

See commented line imageView.frame = [[tmpRectArr objectAtIndex:i] CGRectValue];

So if I comment that line out, the problem will never happen. If I keep the line and as well as don't change the values of tempRect, the problem also won't happen.

It looks like there's an issue in iOS 7 in changing the UIImageView's frame position, but only sometimes. Just wondering what other alternatives could I use? Or am I doing something definitely wrong in iOS 7?

Was it helpful?

Solution

Not a solution to your problem but workarounds. I'll start with the one that's probably requires the most code changes.

  1. You don't actually have to have a UIView in order to keep background with transitions. Instead if you implement the background entirely in cocos2d (as part of the scene), you can achieve the same effect if instead of replacing scenes you transition layers in and out. Scene transitions for the most part use the same actions that also work on nodes.

  2. Implement the background using cocos2d nodes, and have one parent node acting as the container (ie "layer") of the background nodes. You can do one of two things with that node:

    a. Edit CCDirectorIOS's code and add a reference to your background node. Update the node before all other nodes in the drawScene method, by calling visit on the background node just before [_runningScene visit].

    b. When transitioning to a new scene, either remove the background node from the current scene and add it to the new scene, or create a copy of the background with all the same settings and add it to the new scene. Ensure the copy starts with the exact same state as the original. Though this won't work with most transitions due to the nature of their animation (ie move/flip/zoom).

  3. If you need the background to animate while a transition is running, there's a simple trick. Schedule update on a non-CCNode object that has global lifetime (ie AppDelegate). Then manually send the update to all nodes that should continue to update their state during a transition, and only during a transition.

You can register updates on non-node objects like this:

[_director.scheduler scheduleUpdateForTarget:self priority:0 paused:NO];

This update method will be called even during scene transitions. Alternatively it should also be possible to continue updating nodes by changing their paused state and thus resuming scheduler and actions, either by overriding the paused property or by explicitly unpausing specific nodes when a transition occurs.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top