How to stop Sprite Kit from reinitializing the scene with iAd banner - ios

I made a game using sprite kit in landscape mode. The only allowed orientations are landscape left and landscape right. When I select the banner ad in my game, rather than freezing the scene and returning to the original point in the game, the entire scene reinitializes itself (music player restarts, content shows as start screen, etc).
The same thing happens when I flip the phone around so that the orientation switches. How can I prevent this?

As for when you flip your phone you need this...
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
SKView * skView = (SKView *)self.view;
if ( !skView.scene ) {...
SKScene * scene = [MenuScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
[skView presentScene:scene];
}
}
I'm still looking into the iAd issue, I'll update if I figure anything out.

Thanks for the response. That was the problem. I had been initializing the scene in the viewWillLayoutSubviews method in my root view controller. I moved the scene initialization to the viewDidLoad method and it fixed the issue.

Related

How to make my sprite kit scene appear above a UIView?

I've done some searching but haven't found anything directly addressing my issue: I have an SKScene with several SKNodes each with SKSpriteNode objects for my game, and I am using a background UIImageView (there are some things I need to do with background that cannot be reasonable done with sprite kit - to my knowledge at least); the problem I'm having is that the UIImageView appears above everything and I can't see my game objects.
In my view controller (.m file) I have the following code to call my scene
#implementation GameViewController
- (void)viewDidLoad
{
[super viewDidLoad];
SKView * skView = (SKView *)self.view;
SKScene * scene = [GameScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
[skView presentScene:scene];
}
In the GameScene above, I have several SKNodes where all my game objects are children of (for example nodeHDU, nodePlay, nodePauseMenu...), and I am using a UIImageView as my background (I am switching between background scenes over time and am using some nice transitions such as UIViewAnimationOptionTransitionCrossDissolve; couldn't accomplish this with a SKSpriteNode as background without using multiple SKSpriteNodes and an intricate array of SKActions so I"m using UIImageView)
UIView *backgrounds = [[UIView alloc] init];
[self.view insertSubview:backgrounds belowSubview:self.view];
UIImageView *imageBackground = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,self.view.frame.size.width,self.view.frame.size.height)];
[backgrounds addSubview:imageBackground];
[backgrounds sendSubviewToBack:imageBackground];
[imageBackground setImage:[UIImage imageNamed:#"1-A.png"]];
imageBackground.alpha=1.0;
However, the ImageBackground above is the only thing I see when running the app in Xcode. The other objects from my game (children of other nodes) exist, and various NSLog statements are getting called, but they seem to appear behind the ImageBackground I have. The code above "belowSubview" and "sendSubviewToBack" don't help.
So How can I send the imageBackground to actually be the background?
Your problem is here that you are directly setting SKView as a controller view. To overcome from this issue don't make self.view a type of SKView. Do the following step in your storyboard or Xib :
Add an UIImageView on the controller's view first. Set the image as well.
Then add a SKView over the UIImageViewand set UIClearColor to the background colour.
So the complete hierarchy is like UIViewController->UIView->UIImageView->SKView

More Sprite Kit Game modes

I have a small game and I wish to present, in the menu, 2 game modes:
I have the first up and running from my original sprite kit scene and, in order to build my second one, I added another view to the storyboard, created another scene, linked them up just like the originals:
// Configure the view.
SKView * skView = (SKView *)self.view;
skView.showsFPS = NO;
skView.showsNodeCount = NO;
skView.multipleTouchEnabled = YES;
// Create and configure the scene.
SKScene * scene = [MyScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
and linked it to another button in my menu. The problem was, whenever i would press the button to go to the second game mode I would get a SIGABRT Thread 1 error. I made sure everything I linked was declared and valid and still got the error. I then removed the second SKScene (MyScene) and the view was loaded with no problem... just no content.
Is there a specific way I must proceed in order to have another View linked to a SpriteKit game?

SKView Flashing Gray before Scene

I have a main view of type UIView. This view has two skview's (left and right) in landscape only orientation. All views and scenes are set with a black background.
I start out with the two skviews hidden. The main screen shows questions on either side of the screen. If the answer is incorrect I set a scene to an effect and then enable that effect and unhide the skview (left or right). The effect is shown for several seconds after which I disable it with [self.leftView presentScene:nil]; I do the same with the rightView. I then hide the views again.
The issue is that when the scenes are shown there is a brief flash of the view in a white color before the scene is rendered appropriately with the black background. In fact this is why I took to hide the skviews to begin with as if I don't they will show with a lighter background despite my setting it to black.
How can I show these scenes without the flash of a lighter background color?
Some representative code:
self.fireSceneLeft = [FireScene sceneWithSize:self.leftView.bounds.size];
self.fireSceneLeft.scaleMode = SKSceneScaleModeAspectFill;
self.fireSceneLeft.backgroundColor = [UIColor blackColor];
[self.leftView presentScene:self.fireSceneLeft];
[self.leftView setHidden:NO];
As for the scene effect itself:
#implementation FireScene
-(SKEmitterNode *)fireEffect
{
SKEmitterNode *emitter = [NSKeyedUnarchiver unarchiveObjectWithFile:[[NSBundle mainBundle] pathForResource:#"FireEffect" ofType:#"sks"]];
emitter.position = CGPointMake(150,80);
emitter.name = #"fire";
emitter.targetNode = self.scene;
emitter.numParticlesToEmit = 2;
return emitter;
}
-(void)update:(CFTimeInterval)currentTime {
[self addChild:[self fireEffect]];
}
#end
I solved this issue by creating another scene that is simply black. Instead of setting the scene I want to move away from to nil, I simply substitute in the black scene. A scene with nothing on it (blank SKView) has a gray color which is the cause of my problem. By starting the app with the black scene and using it when no scene should display, my problem was solved. An important point here as well is pausing the scene. Even a black scene with no movement will use up CPU if not paused. I found the best place to pause the black scene was in the following method of the scene controller:
-(void)update:(CFTimeInterval)currentTime {
[self addChild:[self blackEffect]];
[self.view setPaused:YES];
}
This was also tricky because pausing the scene elsewhere actually paused the older scene. This is a timing problem because even if you call a new scene and then pause, it won't have had the time to get the new scene in place before the pause. The method above was the only place I could reliably call the pause and have it take effect on the correct scene.
On iOS you can't have 2 (or more) SKView instances at the same time. While it works technically and on first sight it is actually unusable because one view will dominate the other(s), leaving very little time for the other view(s) to update and render their contents as well as receiving touch and other events. I suspect the brief flash is related to this.

Positioning SKView / SKScene that has SKSceneScaleModeAspectFit?

I'm using a basic setup with a SKView to display a SKScene. The SKScene has a pre-defined size and uses a scale mode SKSceneScaleModeAspectFit:
- (void)viewDidLoad {
[super viewDidLoad];
SKView *skView = (SKView *)self.view;
SKScene *scene = [MyScene sceneWithSize:CGSizeMake(320, 480)];
scene.scaleMode = SKSceneScaleModeAspectFit;
[skView presentScene:scene];
}
As expected, on iPhone 5 this causes letterboxing, i.e. black sections above and under my scene. On iPad, letterboxing causes black stripes to the left and right of the scene.
However, I'd like to position the scene e.g. on iPhone 5 so that the scene is aligned to the bottom of the screen, while all of the black space is positioned above the scene. Is this possible?
I've tried quite a few things with .frame .center .origin, etc. properties of the SKView/SKScene, but can't seem to be able to move the 'display area'. For example, adding
[scene runAction:[SKAction moveTo:CGPointMake(0,-44) duration:0]];
moves the scene's contents inside the display area but not the area itself.
Any ideas?

Flipping iPhone orientation reloads viewcontroller

I have a viewcontroller with an SKview (I'm working with spritekit) inside of it and every time I change the orientation of the phone (from landscape one way to landscape another way or vise versa) it reloads the viewcontroller as if I had just opened the app (the viewcontroller is the initial one).
Is there a work around for it?
I can't seem to find anyone having the same problem.
Code:
http://pastie.org/8669630
You are setting up your SKView in viewWillLayoutSubview which gets called every time device is rotated (view frame changes).
Which is good, because view will have correct dimensions, but you should place some var to know should you set up the view again. For example BOOL sceneSetUp
- (void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
if(!self.sceneSetUp){
// Configure the view.
SKView * skView = (SKView *)self.view;
//skView.showsFPS = YES;
// Create and configure the scene.
SKScene * startScene = [StartViewController sceneWithSize:skView.bounds.size];
startScene.scaleMode = SKSceneScaleModeAspectFill;
SKScene * scene = [gameViewController sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
// Present the scene.
[skView presentScene:startScene];
//[skView presentScene:scene];
self.sceneSetUp = YES;
}
}

Resources