iOS Universal Device App with Spritekit, How to Scale Nodes for All Views

iOS Universal Device App with SpriteKit, how to scale nodes for all views?

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/

How to scale/position nodes Swift SpriteKit? Custom View?

To keep my games universal I make all my nodes sizes and positions dependant on SKScene size

Instead of using hardcoded numbers try using proportions from your SKScene size. For example:
Instead of writing this:

node.position = CGPointMake(100, 100)

Write somthing like this:

node.position = CGPointMake(world.frame.size.width / 32 * 16, world.frame.size.height / 18 * 9)

world - SKNode of exactly same size as your SKScene

Same for sizes

let blackSquare = SKSpriteNode(texture: nil, color: UIColor.blackColor(), size: CGSizeMake(world.frame.size.width / 32, world.frame.size.width / 32))

Also GameViewController should look something like this:

override func viewDidLoad() {
super.viewDidLoad()

// Configure the view

let skView = view as! SKView
skView.multipleTouchEnabled = false

// Create and configure the scene

let scene = GameScene(size: skView.bounds.size)
scene.scaleMode = .AspectFill
scene.size = skView.bounds.size

skView.presentScene(scene);
}

Was this helpfull?

Universal app background SpriteKit

The devices's screen size ratios are different, and one will have to stretch dimensions to fit the screen, and this may look weird. But you can use .Fill if you are sure you like this option. The smoothest alternative is to remain using .AspectFill and create an image for each screen dimension. Be creative! Good luck!

SkSpriteNode position in universal game

How can I set SkSpriteNode's position relative to visible area, so
that it'll be for example 50x50 from the corner on every device?

The "visible area" is simply the view.

So you can make your positions relative to the view, and not the scene. I actually do this a lot in my game, which is universal and runs on both OS X and iOS.

In my case I typically do this for the user-interface, so I might have a scaled scene but I want to set some positions not relative to the scaled scene but relative to the visible area (i.e. the view).

To do this, you can write a function that converts view coordinates to the corresponding scene coordinates.

Here is my function that I use. Note that I subtract my desired y-position from height of view so that I can treat (0,0) as the bottom-left like sprite-kit does instead of the top-left like UIKit does.

func convert(point: CGPoint)->CGPoint {
return self.view!.convert(CGPoint(x: point.x, y:self.view!.frame.height-point.y), to: self)
}

Here is an example of using this function:

self.node.position = convert(CGPoint(x: 50, y: 50)) 

This will always force the position of the node to be at (50,50) relative to the view (the visible portion of the screen) regardless of how your scene is scaled and sized.

iOS SpriteKit Get All nodes in a current scene and make the application universal.

  1. in Scene.m, you can use self.children to get all the SKSprite Nodes
  2. http://www.raywenderlich.com/49695/sprite-kit-tutorial-making-a-universal-app-part-1


Related Topics



Leave a reply



Submit