baptzmoffire
baptzmoffire

Reputation: 589

UIView > SKView... willMoveFromView: not being called when expected and sprites not being "updated"

Maybe someone can point me in the right direction, here, cuz I've been beating my head against a wall over this. Major problems getting my head wrapped around Sprite Kit and UIKit interoperability.

My game starts at a table view, which holds all of the player's games in separate cells (a la with Friends games). When a cell is tapped, I load an SKView, which presents an SKScene containing all relevant game data downloaded from Parse.com beforehand.

The problem is, I can't figure out how to get the scene to "update," for lack of a better term, with all the current game data. The presented scene just shows the background image and a few other images, as expected, but the sprites that should be on screen are not. Instead, it's the sprites that WERE on screen when I swiped out of the SKScene last. I can log all the passed in game data into the console, so I know there's no problem there. Also, when I perform some kind of action on the scene's sprites (removing, refreshing, etc.), it causes the scene and all its sprite to kind of "wake up," and all the sprites that were supposed to be there show up.

A second, possibly related, problem is that, when I swipe from the SKScene back to the main table view, willMoveFromView: does not get called. (This is where I do all the cleanup code for the sprites, background, buttons, etc.) It's only when I tap that same table view cell and go back into the same game scene that willMoveFromView: gets called. Shouldn't it get called upon swiping out of the SKScene/SKView? But, again, I run into the same "updating" problem where the scene is kind of frozen with the old data/sprites. Any ideas? I've tried to include all relevant code, but I don't think you'll find anything out of the ordinary. My feeling is this is more of a conceptual problem and my comments above are sufficient:

@interface MGGameMenuViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, PFLogInViewControllerDelegate, PFSignUpViewControllerDelegate, NSURLConnectionDataDelegate, UIAlertViewDelegate>


@property (nonatomic, retain) UITableView *tView;
@property (nonatomic, readwrite) MGSpriteKitViewController *skvc;



@end


@implementation MGGameMenuViewController

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.section == 0) {
        self.matchtoBePassedIn = [self.yourTurnArray objectAtIndex:indexPath.row];
        [self launchGamePlaySceneWithMatchData:self.matchtoBePassedIn];
    }

    else if (indexPath.section == 1) {
        self.matchtoBePassedIn.cardsDealt = [NSMutableArray arrayWithCapacity:9];
        self.matchtoBePassedIn = [self.theirTurnArray objectAtIndex:indexPath.row];
        [self launchGamePlaySceneWithMatchData:self.matchtoBePassedIn];
    }

    else {
        NSLog(@"section chosen was neither 0 nor 1.");
    }
}

// launch gameplay
-(void)launchGamePlaySceneWithMatchData:(MGMatch *)match {
    if (self.skvc == nil) {
        MGSpriteKitViewController *spriteKitVC = [[MGSpriteKitViewController alloc] initWithNibName:@"MGSpriteKitViewController" bundle:nil];
        spriteKitVC.matchToBePassedFromGameMenuToGameplayScene = match;
        self.skvc = spriteKitVC;
    }

    if (self.skvc) {
        @try {
            if (![self.skvc isBeingPresented]) {
                self.skvc.matchToBePassedFromGameMenuToGameplayScene = match;
                [self.navigationController pushViewController:self.skvc animated:YES];
            }
        }
        @catch (NSException *exception) {
            NSRange range = [exception.reason rangeOfString:@"Pushing the same view controller instance more than once is not supported"];
            NSRange range2 = [exception.reason rangeOfString:@"Tried to pop to a view controller that doesn't exist"];
            if([exception.name isEqualToString:@"NSInvalidArgumentException"] &&
               range.location != NSNotFound) {
                NSLog(@"[MGGameMenuViewController] NSInvalidArgumentException caught.");
                if (![self.skvc isBeingPresented]) {
                    self.skvc.matchToBePassedFromGameMenuToGameplayScene = match;
                    [self.navigationController popToViewController:self.skvc animated:YES];
                }
            }
            if ([exception.name isEqualToString:@"NSInternalInconsistencyException"] && range2.location != NSNotFound) {
                if (![self.skvc isBeingPresented]) {
                    self.skvc.matchToBePassedFromGameMenuToGameplayScene = match;
                    [self.navigationController pushViewController:self.skvc animated:YES];
                }
            }   
        }
        @finally {
            NSLog(@"[MGGameMenuViewController] finally");
        }
    }
    [self.navigationController.navigationBar setHidden:YES];
}

// the SKView

SKView *spriteView;

@interface MGSpriteKitViewController : UIViewController
@property (nonatomic, retain) MGMatch *matchToBePassedFromGameMenuToGameplayScene;
@property (nonatomic, retain) MGGameplayScene *gameplayScene;
@end

@implementation MGSpriteKitViewController

@synthesize matchToBePassedFromGameMenuToGameplayScene, gameplayScene;

-(void)viewDidLoad {
    [super viewDidLoad];

    spriteView = (SKView *)self.view;
    spriteView.showsDrawCount   = NO;
    spriteView.showsFPS         = NO;
    spriteView.showsNodeCount   = YES;
}

-(void)viewWillAppear:(BOOL)animated {
    self.gameplayScene = [[MGGameplayScene alloc] initWithSize:CGSizeMake(320.0f, 568.0f)];
    self.gameplayScene.passedInMatch = self.matchToBePassedFromGameMenuToGameplayScene;
    self.gameplayScene.playerImageCache = self.playerImageCache;
    [spriteView presentScene:self.gameplayScene];
}

-(void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:YES];
    self.gameplayScene = nil;
}

@end

// SKScene where the gameplay happens

@interface MGGameplayScene : SKScene
@property (nonatomic) contentCreated;
... various assets
@end



@implementation MGGameplayScene

-(void)didMoveToView:(SKView *)view {
    if (self.contentCreated == NO) {
        [self createSceneContents];
        self.contentCreated = YES;
    }
}

-(void)willMoveFromView:(SKView *)view {
    [self removeAllChildren];
}

// for practicies
-(void)createSceneContents {
    self.backgroundColor = [UIColor whiteColor];
    self.scaleMode = SKSceneScaleModeAspectFit;
    [self setAllAssetsToNil];
    [self recreateAssetsWithRelevantData];
}

@end

Upvotes: 3

Views: 2202

Answers (2)

Ken Woo
Ken Woo

Reputation: 118

The issue is that MGSpriteKitViewController is, by default, creating a UIView for its view property.

To programmatically create the view as an SKView, you have to override the loadView method of your MGSpriteKitViewController:

@implementation MGSpriteKitViewController

- (void)loadView
{
    self.view  = [[SKView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
}

// Rest of Code
... 

Upvotes: 2

Banshi
Banshi

Reputation: 1345

In Storyboard assign the class of the uiview in MGSpriteKitViewController as skview.

Upvotes: 3

Related Questions