Luiz Luiz - 2 months ago 17
Swift Question

Swapped width and height values

Explanation



For some reason, width and height values are being swapped in my game (as you can see below) that is set to be in landscape orientation. This way, the sprite that should be centered in the screen, is totally off the right position.

enter image description here




Code



You can download it here.

GameScene

import SpriteKit

class GameScene: SKScene {

override func didMoveToView(view: SKView) {

print("width:", self.frame.width)
print("height:", self.frame.height)

//Sprite
let sprite = SKSpriteNode (imageNamed: "sprite")
sprite.anchorPoint = CGPointZero
sprite.position = CGPoint(x: self.frame.width / 2 - sprite.frame.width / 2, y: self.frame.height / 2 - sprite.frame.height / 2)
addChild(sprite)
}
}


GameViewController

import UIKit
import SpriteKit

class GameViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()

// Set view size.
let scene = GameScene(size: view.bounds.size)

// Configure the view.
let skView = view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true

/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = true

/* Set the scale mode to scale to fit the window */
scene.scaleMode = .ResizeFill

skView.presentScene(scene)
}

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
return .Landscape
} else {
return .Landscape
}
}
}




Thanks in advance,

Luiz.

Answer

If you go to targets-General in your xCode project (where you set version number, bundle ID etc) did you untick portrait?

You approach unfortunately is bad practice a lot of tutorials teach you and I would not continue like this.

If you use "scaleMode ResizeFill" or set the scene size to "view.bounds" your game will never look consistent on all devices. Furthermore all your values (sprite sizes, font sizes, physics values etc) will also not be the same on devices different to the one you are testing on.

Basically you will have to adjust for all of this on like 5-6 devices and its madness, especially using xCode simulator. Trust me I have been there before with 2 games and it nearly killed me. Its a game of game of "yeah this looks about right".

Dont go through this, so what you should do is

1) Change your scene size to the default scene size used by xCode

  GameScene(size: CGSize(width: 1024, height: 768)) // swap if portrait 

If you dont do this, and leave it at view.bounds.size, point 2 will not work.

2) Change your scene scale mode to .AspectFill (also default xCode settings).

UPDATE: It seems with xCode 8 apple changed the default scene size (point 1) from 1024x768 to 1334*750 (iPhone size). Bear this in mind when continuing reading the rest. The basic idea should still be the same.

This way all your stuff will look great on all iPhones. Your values will scale correctly and you save yourself a lot of work. On iPads you will have some extra space at the top and bottom (landscape) or left and right (portrait) which you usually just cover with some more background and have as a non playable area

Your scene basically looks like this now.

enter image description here

The red area is your whole scene size (iPad) but if you run on iPhones you will only see the green bit. In Portrait mode that red area would be on the left and right side.

Thats why y positioning is usually done from the centre because if you use frame.minY or frame.maxY you would be in the red zone and won't see the sprite on iPhones. That red zone you just cover with some more background (your background full screen images should be iPad size).

This also make your game more balanced, because if your would just stretch up your game than it will be easier on iPads because you have more space.

So design your game within the green zone. Than on iPads the only thing you might have to do is move up some UI, like pause button or score label, when you want to show them at the top edge. I do it this way.

 // Some button
 ...
 someButton.position = CGPoint(x: frame.midX, y: frame.midY + 200)
 addChild(someButton)

 if UIDevice.current.userInterfaceIdiom == .pad {
     // set for iPad
 }

 // Some label
 someLabel.positon = CGPoint(x: frame.midX - 100, someButton.position.y) // because its y position is the same as someButton I only have to adjust someButton.position.y on iPads.
 addChild(someLabel)

I would not continue with your approach, even if it means redoing a lot of work.

Hope this helps

Comments