如您所知,在运行您的应用程序时,iPhone 始终以纵向模式启动。这与 Sprite Kit 无关。这是关于一般的 iOS 生命周期和视图问题。歪曲内容或丢失内容完全是因此而发生的。制作游戏时,通常使用纵向或横向。将它们一起使用是非常罕见的。要了解为什么您的内容被“拉伸”,请将以下代码写入您的 SKScene 的 initWithSize 方法:
NSLog(@"In initWithSize, at %0.f wide and %0.f high", size.width, size.height);
启动游戏并查看 NSLog 消息。即使我们认为我们是在横向模式下开始的(也就是说,如果您倾斜手机并等待游戏加载或稍后执行),NSLog 消息显示“In initWithSize, at 320 wide and 568 high”(我' m 使用 iPhone 5S)。这意味着即使我们在 Targets/Deployment Info 部分中选择了横向模式,场景也会以纵向模式渲染。我们希望宽度大于高度(568 宽和 320 高)!但为什么会发生这一切?问题在内部。iOS 应用程序生命周期从纵向开始每个应用程序,并且仅在加载过程中切换到横向。所以情节提要加载,它加载了初始视图控制器,它仍然认为它是纵向的。此视图控制器将自动加载视图对象(对于 Sprite Kit 即 SKView)。我们仍处于纵向。View 对象已加载,这将导致 viewDidLoad 在 View Controller 中被回调。我们仍处于纵向。但是在 viewDidLoad 方法中,我们创建场景(SKScene)并传入当前高度和宽度。仍然是纵向。所有这一切都只需要几分之一秒,但只有在此之后,应用程序才意识到它应该在 Landscape 中,并且 View Controller 切换到 Landscape 并带上 View。根据您的设置,场景将尝试通过扩大以填充可用空间来对此做出反应,并且我们将松散内容,因为在内部它' s 仍然是纵向的……只是放大了。我们如何解决这个问题?我们的场景是在 viewDidLoad 中创建的,但是当这种情况发生时,应用程序还不知道我们应该处于横向模式。所以我们需要创建我们的场景,但我们只需要在这个过程中稍晚一点——在 iOS 应用程序生命周期意识到我们处于横向模式之后。有几种不同的方法可以做到这一点。我喜欢的是viewWillLayoutSubviews。它是另一种内置的 View Controller 方法。在 viewDidLoad 和切换到横向模式之后会自动调用它。因此,如果我们将场景创建推迟几毫秒,直到我们进入 viewWillLayoutSubviews 方法,那么我们可以以正确的方向创建它。所以复制 & 粘贴 viewDidLoad 中的所有代码(除了对 [super viewDidLoad]; 的调用)并将其放入 viewWillLayoutSubviews。现在只有1个问题。viewWillLayoutSubviews 可能会在生命周期中被调用几次或至少一次以上。没关系。我们只是不想多次创建场景。因此,一旦我们抓住了视图,我们将创建一个 if 语句来检查该视图中是否有 Scene 对象。如果没有,我们将创建它并返回它。否则,我们不需要这样做。以下是所有这些代码在创建场景的视图控制器中的外观。没关系。我们只是不想多次创建场景。因此,一旦我们抓住了视图,我们将创建一个 if 语句来检查该视图中是否有 Scene 对象。如果没有,我们将创建它并返回它。否则,我们不需要这样做。以下是所有这些代码在创建场景的视图控制器中的外观。没关系。我们只是不想多次创建场景。因此,一旦我们抓住了视图,我们将创建一个 if 语句来检查该视图中是否有 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.
}
现在继续运行它。现在一切都应该看起来不错。NSLog 消息现在应该说“在 initWithSize,宽 568 高 320”。欢呼!