17

I want to make a landscape app to be universal, so that the sprite nodes scale proportionally to whatever view size is running the app. I'd like an entirely programmatic solution because I don't like the IB.

My game is pretty simple, and I don't need scrolling or zooming of any kind, so the whole game will always be present and take up the entire view.

Is it possible that what I'm looking for is to change the size of the scene to always fit the view? If so, can you explain this thoroughly because I've tried changing this section of my view controller

    if let scene = GameScene(fileNamed:"GameScene")

to be the constructor method that takes size as a parameter but Xcode doesn't like that.


Things I've tried

  1. Using fractions of self.view.bounds.width/height. This usually makes all iPhones look good, but on iPads stretches and skews nodes and the boundary box around thew view.
  2. Changing the scaleMode among all four types. I'd like to keep good practice and feel like .AspectFill (default) is the one I should make my app work with, but open to suggestions. Note; I don't want black edges on any device, just the entire view displayed/scaled proportionally.
  3. Applying programmatic constraints. Now I'm fairly new to this and don't understand constraints completely, but no tutorials I've seen even from RayWenderlich talk about constraints on nodes so I didn't delve to deep in this.
  4. Using a method like this to convert points among views. This actually worked pretty well for point positioning of nodes, and if possible I would like this method to work out, but then I still have the problem of sizes of nodes. Also when I build for iPad with this method the view seems to start off as portrait and the nodes look fine but then I have to manually switch it to landscape and the sprites and view boundaries once again get messed up. Here's the method:

    func convert(point: CGPoint)->CGPoint {
        return self.view!.convertPoint(CGPoint(x: point.x, y:self.view!.frame.height-point.y), toScene:self)
    }
    
  5. Countless vid tutorials on RW and everywhere else on internet.

Thanks in advance! I appreciate the help. I know this topic is weird because a lot of people ask questions about it but everyone's situation seems to be different enough that one solution doesn't fit all.

ljs
  • 315
  • 2
  • 10

1 Answers1

14

I initially tried to do the scaling myself with 2 games and it was just madness (scene size = view size or scene scale mode = .ResizeFill). You have to adjust all values e.g font size, sprite sizes, impulses etc for all devices and it will never be consistent.

So you have 2 options basically

1) Set scene size to 1024X768 (landscape) or 768x1024 (portrait). This was the default setting in Xcode 7.

You than usually just have/show some extra background at the top/bottom (landscape) or left/right (portrait) on iPads which gets cropped on iPhones.

Examples of games that show more on iPads / crop on iPhones:

Altos Adventure, Leos Fortune, Limbo, The Line Zen, Modern Combat 5.

2) Apple changed the default scene size in xCode 8 to iPhone 6/7 (7501334-Portait, 1337750-Landscape). This setting will crop your game on iPads.

Examples of games that show less on iPads:

Lumino City, Robot Unicorn Attack

Chosing between the 2 options is up to you and depends what game you are making. I usually prefer to use option 1 and show more background on iPads.

Regardless of scene size scale mode is usually best left at the default setting of .aspectFill.

To adjust specific things such as labels etc you can do it this way

 if UIDevice.current.userInterfaceIdiom == .pad {
   ...
 }

You can try the scene scaling yourself, create a new SpriteKit sample game project. Run on all iPhones and you will notice the HelloWorld label looks perfect on all devices.

Now change the default settings to scene size = frame or use .ResizeFill, the HelloWorld label is not scaled properly anymore on all devices.

As a side note, the line

 if let scene = GameScene(fileNamed: "GameScene")

references the GameScene.sks file. You said you do everything programatically, therefore you can probably delete the GameScene.sks file and change the line to

 let skView = view as! SKView!
 let scene = GameScene(size: CGSize(width: 1024, height: 768)) // 768 x 1024 if portrait

Update:

I am now using a slightly different variant as I had problems adapting my game to iPhoneX. I set scene size to 1334x750 and use aspect fit as scale mode. I than run some code to remove the black bars if needed e.g. on iPads or iPhone X. It’s based on this great article (link no longer works).

http://endlesswavesoftware.com/blog/spritekit-skscene-scalemode/

crashoverride777
  • 10,581
  • 2
  • 32
  • 56
  • 2
    Thanks for the help! I marked this correct because it contains a valid solution to my problem. However I just solved it another way and will stick this method: In my info.plist I noted that the screen orientations for iphone and ipad were there and the portrait views for ipad were still there as well. I simply removed them from the list. After that I also needed to set the scene.size to skView.bounds.size and those two things fixed it (one without the other will break the program however). Now I continue to position and scale nodes relative to the view and everything works fine. – ljs Jan 20 '16 at 06:45
  • 2
    Thanks for marking. Yeah i didnt realise you were looking for the landscape stuff in the plist. Its a bit weird that those 2 entries remain even if you unselect portrait in Xcode, caused me many headaches in the beginning. Happy coding – crashoverride777 Jan 20 '16 at 12:56