Search code examples
ioscamerasprite-kitscreenshotsknode

SpriteKit : Why can't I hide SKSprite nodes and take a screenshot right after that?


This may be a dumb question but why when I execute hide buttons does the screenshot occur before the buttons are hidden? Is there a way to make sure the buttons are gone before the screenshot occurs? Do I need a separate thread call? Thank You!

if([node.name isEqualToString:@"ScreenshotButton"])
{
    [self UserHideAllButtons];   //This hides all menus and buttons
    [self captureFullScreen];  This takes a screenshot and sends it to camera 
    roll
}

-(void)UserHideAllButtons
{
    [self showItem:-1 withItemNamed:btnCandy];
    [self showItem:-1 withItemNamed:btnCharacter];
    [self showItem:-1 withItemNamed:btnDecor];
    [self showItem:-1 withItemNamed:btnGifts];
    [self showItem:-1 withItemNamed:btnGreeting];

    [self showItem:-1 withItemNamed:btnCandyPressed];
    [self showItem:-1 withItemNamed:btnCharacter];
    [self showItem:-1 withItemNamed:btnDecorPressed];
    [self showItem:-1 withItemNamed:btnGiftsPressed];
    [self showItem:-1 withItemNamed:btnGreetingPressed];



    [self hideObjects:-1 withArrayNamed:candyObjects];
    [self hideObjects:-1 withArrayNamed:characterObjects];
    [self hideObjects:-1 withArrayNamed:decorObjects];
    [self hideObjects:-1 withArrayNamed:giftsObjects];
    [self hideObjects:-1 withArrayNamed:greetingObjects];

    [self clearMenu];
    sliderArrowBtn.zPosition=-1;
    sliderMenu.zPosition=-1;
    slider.zPosition=-1;
    selectedItemBack.zPosition=-1;
}

-(UIImage *)captureFullScreen
{
    AppDelegate *_appDelegate = (AppDelegate *)[UIApplicationsharedApplication].delegate;

    // if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
    // for retina-display
    UIGraphicsBeginImageContextWithOptions(_appDelegate.window.bounds.size, NO, [UIScreen
    mainScreen].scale);
    [_appDelegate.window drawViewHierarchyInRect:_appDelegate.window.bounds 
    afterScreenUpdates:NO];
     screenshot= UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Photo Saved To Camera Roll"
                                                    message:@""
                                                   delegate:nil
                                          cancelButtonTitle:@"OK"
                                          otherButtonTitles:nil];

    screenshot=[self centerCropImage:screenshot];

    UIImageWriteToSavedPhotosAlbum(screenshot, nil, nil, nil); //if you need to save
    [alert show];
    return screenshot;
}

Solution

  • Most likely because you do both hiding and taking screenshots during the update of the same frame. So what you actually take a screenshot of is the screen contents of the currently displayed frame which doesn't show any changes like hidden buttons until Sprite Kit renders the screen anew at the end of the update/actions/physics cycle.

    You will have to wait for one frame so Sprite Kit renders the scene with the buttons removed, then you can show the buttons again. Note that this will inevitable cause the buttons to flicker.

    To wait for one frame, it should suffice to run a runBlock action:

    [self runAction:[SKAction runBlock:^{
        UIImage* screenshot = [self captureFullScreen];
    }];
    

    If it doesn't suffice, run the action in didEvaluateActions or didSimulatePhysics to ensure the action is scheduled to run the next frame.