Just so you know, when running your application the iPhone always begins in Portrait mode. This has nothing to do with Sprite Kit. It's about general iOS lifecycle & view issues. Skewing content or loosing content entirely happens because of this. When making a game usually Portrait or Landscape is used. Using them together is pretty rare. To understand why your content is being "stretched" write the following code into your SKScene's initWithSize method:
NSLog(@"In initWithSize, at %0.f wide and %0.f high", size.width, size.height);
Fire the game up & look at the NSLog message. Even though we think we started in Landscape mode (that is if you tilted your phone & waited for the game to load or did that a bit later), the NSLog message displays "In initWithSize, at 320 wide and 568 high" (I'm using an iPhone 5S). That means the scene is being rendered in Portrait mode even if we selected Landscape mode in the Targets/Deployment Info section. We want the width to be more then the height (568 wide and 320 high)! But why is all of this happening? The issue is internally. The iOS app life cycle begins EVERY application in Portrait and ONLY switches to Landscape during the loading process. So the Storyboard loads, it loads that initial View Controller and it still thinks it's in Portrait orientation. This view controller will automatically load the View object (for Sprite Kit that's the SKView). We're still in Portrait orientation. The View object loaded and that will cause viewDidLoad to be called back in the View Controller. We're still in Portrait orientation. But in the viewDidLoad method that is where we create our scene (SKScene) passing in the current height & width. Still Portrait orientation. All of this is taking a fraction of a second, but it's only after this that the application realizes it's supposed to be in Landscape and the View Controller switches to Landscape taking the View with it. Depending on your settings, what the Scene is going to do is trying to react to this by scaling up to fill the available space and we're going to loose content because internally it's still in Portrait orientation...just scaled up. How do we fix this? Our scene is being created in viewDidLoad, but when this is happening the application DOES NOT yet know we're supposed to be in Landscape mode. So we need to create our scene, but we just need to do it a bit later in the process - after the iOS application life cycle has realized we're in Landscape mode. There's a couple of different methods to do this. The one I like is viewWillLayoutSubviews. It is another built-in View Controller method. It gets called automatically after viewDidLoad and after the shift to Landscape mode. So if we post-pone our scene creation by a few milliseconds until we're in viewWillLayoutSubviews method then we can create it with the right orientation. So copy & paste all the code in viewDidLoad (apart from the call to [super viewDidLoad];) and put it into viewWillLayoutSubviews. There is only 1 more issue now. It is possible viewWillLayoutSubviews will be called a couple of times or at least more then once during the lifecycle. That's ok. We just don't want to create the scene several times. So once we have grabbed hold of the view we're going to create an if statement to check if there's a Scene object in that view. If not, we'll create it and return it. Otherwise, we don't need to do that. Here's how all of this code looks inside the View Controller that creates our Scene.
//Method can be deleted (It's called behind the scenes regardless).
-(void)viewDidLoad
{
[super viewDidLoad];
}
//Called AFTER viewDidLoad & after the view shifts to landscape (which is what we want).
-(void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews]; //Don't really need to call this method (but a good habit just in case Apple ever changes that).
//Configure the view.
_skView = (SKView *)self.view;
_skView.showsFPS = YES;
_skView.showsNodeCount = YES;
//_skView.showsPhysics = YES;
//viewWillLayoutSubviews might get called several times & that's ok. But, we don't want several GameScenes to be created. Therefore...
//Is there a scene object in that view? If there ISN'T, we'll create it.
if (!_skView.scene)
{
//Create & configure the scene.
SKScene *sceneGame = [MainMenuScene sceneWithSize:_skView.bounds.size];
sceneGame.scaleMode = SKSceneScaleModeAspectFill;
//Present the scene.
[_skView presentScene:sceneGame transition:[SKTransition fadeWithDuration:0.5]];
}
//If there is, we don't need to do that.
}
Now go ahead and run this. Everything should look good now. The NSLog message should now say "In initWithSize, at 568 wide and 320 high". Hurray!