Summary
I'm creating an SpriteKit game for different devices and I'm wondering what should be the size of the different assets.
What I have right now
I'm creating the SKScene in viewDidLoad:
scene = GameScene(size: view.bounds.size)
scene.scaleMode = .AspectFill
I don't want to use viewWillLayoutSubviews because it is called twice on start up and also each time the device is rotated. I don't think that initialising the scene here is a good idea.
With this configuration, my view is initialised with a width of 600 points (default storyboard size) and then rescaled to the device width. Using println(scene.size.width) after the view has been layout it displays a 375 points size in the iPhone 6 and 414 points in the iPhone 6 Plus.
I'm using xcassets to provide the background images and I would like to know which sizes should I use. My current configuration is ready for 320 points resolutions (iPhone 4, iPhone 5)
1x: 320 pixels
2x: 640 pixels
3x: 960 pixels
The problem
The problem is that the image will be rescaled in following devices:
iPhone 6: 750 pixels - 375 points
iPhone 6 Plus: 1242 pixels - 414 points
iPad: 768 pixels - 768 points
iPad retina: 1536 pixels - 768 points
I would like to know how am I supposed to configure the images and the SKScene size to optimise it for all the devices.
If you don't want to initialize scene twice you can initialize it only once:
- (void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
// Configure the view.
SKView * skView = (SKView *)self.view;
skView.showsFPS = YES;
skView.showsNodeCount = YES;
skView.showsDrawCount = YES;
skView.showsPhysics = YES;
skView.ignoresSiblingOrder = YES;
if(!skView.scene){
// Create and configure the scene.
GameScene * scene = [GameScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
// Present the scene.
[skView presentScene:scene];
}
}
For a project I'm currently working on, I decided to make my assets in the largest possible resolution, i.e. the one of the iPhone 6 Plus (2208 x 1242, iOS Resolution Reference). Since iPhone 6 and iPhone 5 use a 16:9 aspect ratio, it is no problem to down-scale the assets implicitly with
scene.scaleMode = .AspectFit
On iPad and iPhone 4s, this will result in a border, but I can live with that.
Related
The iPhone 6 and 6s are supposed to have a 750 x 1334 resolution [1], and the screen ratio for every iPhone since the iPhone 5 is 16:9 [2]. So in order to have a background image for an app that fits perfectly, it must have a 16:9 ratio. I'm working on a project using SpriteKit and I want the game to have a wallpaper that covers the back from edge to edge. However, when I run the app on the simulator the background image always gets cropped on the right and left. I've even tried with all sorts of ratios and resolutions. The code for this background on the project is:
let background = SKSpriteNode(imageNamed: "backtImage")
background.size = self.size
background.position = CGPoint(x: self.size.width/2, y: self.size.height/2)
background.zPosition = 0
self.addChild(background)
What am I doing wrong?
This could happened because your SKView don't match with your SKScene dimensions.
The sources:
#available(iOS 7.0, *)
public enum SKSceneScaleMode : Int {
case Fill /* Scale the SKScene to fill the entire SKView. */
case AspectFill /* Scale the SKScene to fill the SKView while preserving the scene's aspect ratio. Some cropping may occur if the view has a different aspect ratio. */
case AspectFit /* Scale the SKScene to fit within the SKView while preserving the scene's aspect ratio. Some letterboxing may occur if the view has a different aspect ratio. */
case ResizeFill /* Modify the SKScene's actual size to exactly match the SKView. */
}
You can change your code as below:
override func viewDidLoad() {
super.viewDidLoad()
if let scene = GameScene(fileNamed:"GameScene") {
// Configure the view.
let skView = self.view as! SKView
...
/* Set the scale mode to scale to fit the window */
scene.scaleMode = .ResizeFill // <- this is an example
skView.presentScene(scene)
}
}
If your image is getting cropped on the left and right side (in Portrait) Then we are dealing with an .AspectFill scale mode, and your aspect for your scene is shorter than the screen resolution. This is probably happening because the default scene size provided in the template build is a square. Go into your .sks file, and change the scene size to something in a 9x16 ratio, and your problem should be solved
I'm working on universal game (iPhone and iPad) with SpriteKit and I have issue with background size.
I created image size 2048x1536 and more image for iPhone devices in size 1136x852 and still the background is cropped on iPhone.
How can I fix it?
let screenHeight = screenSize.size.height
//Backgorund
var dayBackground = SKSpriteNode(imageNamed:"BackgroundDay")
dayBackground.zPosition = -1
dayBackground.position = CGPoint(x:size.width/2, y:size.height/2)
dayBackground.anchorPoint = CGPointMake(0.5, 0.5)
dayBackground.size = self.frame.size
GameViewController:
if let scene = GameScene(fileNamed:"GameScene") {
// Configure the view.
let skView = self.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 = .AspectFill
skView.presentScene(scene)
}
iPhone 6 Plus:
iPad Pro:
iPhone 4s:
Assets file:
#1x size is 2048x1536 and #3x is 1136x852
The sense scale is .AspectFill with .ResizeAll the position of SKSprtieNode it not like what I want.
Thanks!
I tried to split the image to parts but still is cropped
I think is happen because the iPhone 6 plus screen size is 736x414 and the scene size is 1024x768, and if I change the scene to the current device I need to position the sprites for each screen
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!
Why does my app look different from the simulator when I run it on my real phone?
I am making a game using spritekit. When I test it in the iPhone 5 simulator, the size of the screen and the size of the images are exactly as I want them, but then when I run the program on my actual iPhone 5, the images show up too big, parts of the top and bottom of the screen are cut off, and the left and right of the screen don't extend all the way to the sides of the phone--there's a letterboxing effect from left to right on the screen.
All my images are named with #2x, so they should work fine with retina screens. Here's the code relating to screen size that I use when I initialize my SKScene:
GameScene *scene = [GameScene unarchiveFromFile:#"GameScene"];
scene.size = self.view.frame.size;
scene.scaleMode = SKSceneScaleModeAspectFill;
I've tried each of the available SKSceneScaleModes and none of them help--they each just give a different outcome that doesn't look right. I'm using AspectFill simply because that mode does work correctly in the simulator.
I've also tried sizing the screen like this, just as something to try, but that didn't help either:
GameScene *scene = [GameScene unarchiveFromFile:#"GameScene"];
CGRect screenRect = [[UIScreen mainScreen] bounds];
scene.size = screenRect.size;
Thanks in advance.
It was indeed due to the fact that the simulator was simulating ios 8 while my device was on ios 7. ios 8 automatically changes the coordinate system when you go into landscape mode (the native mode of my game) while ios 7 does not. The fix was simple once I figured that out--just detect which os the device is running, and, if it's lower than ios 8, swap the height and width dimensions of the screen:
if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1) {
CGSize fixedSize = CGSizeMake(screenRect.size.height, screenRect.size.width);
scene.size = fixedSize;
}
else
scene.size = self.view.frame.size;
I have an image mySprite#2x.png it's dimensions 1240 x 1240 pixels or 620 x 620 points.
I want to use it for all iPhone models (different screen sizes). All I want it to resize it, but I can't figure out how to do this properly.
Here is what's go wrong:
let sprite = SKSpriteNode(imageNamed:"mySprite")
sprite.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
println(sprite.size)
sprite.size = CGSize(width: 300, height: 300)
println(sprite.size)
println(self.view?.frame.size)
self.addChild(sprite)
Here is log from testing on the iPhone 4S:
(620.0,620.0)
(300.0,300.0)
Optional((480.0,320.0))
log looks ok, but on screen I can see that image is bigger than iPhone 4S width. It's width and height (it's a square) almost as high as iPhone 4 screen height (about 440 pts).
Scene scaleMode is AspectFill.
Scene and sprite xScale and yScale = 1.0
I don't understand what I'm doing wrong.
Based on the log message from your view's frame, the width is 480 and the height is 320, meaning your view is in landscape mode.
If your SKScene's size is set to the size of your view in portrait mode, using scaleMode AspectFill will stretch the width of your scene from 320 to 480.
This means your SKSpriteNode will seem 450pts instead of 300pts.
You probably want to use SKSceneScaleModeResizeFill instead?
In portrait mode, i created a SKShapeNode at the position of 0,0. Yet it seems that it does not appear in the screen at all.
This is the code i am using now
let test = SKShapeNode(rect: CGRectMake(0, 0, 10, 10))
test.fillColor = SKColor.blackColor()
self.addChild(test)
The background colour white, so the shape node will definitely appear if it was on the screen
Yet 0 node appears in the screen?
children.count returns 1
And this is how i display the scene
override func viewWillLayoutSubviews () {
super.viewWillLayoutSubviews()
if let scene = GameScene.unarchiveFromFile("GameScene") as? GameScene {
// Configure the view.
let skView = self.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 = .AspectFill
skView.presentScene(scene)
}
}
The SKShapeNode is drawn, but it is outside the screen?
EDIT 1: I change the scale mode to .AspectFit, and this is what happened
Is the game forcefully running in landscape although the game is suppose to run in portrait?
Base on #fuzzygoat answer at https://stackoverflow.com/a/24170460/1879382.
Simply open GameScene.sks, then change the value of x and y to the appropriate value needed.
For me, I used 320 x 568 since i run the game on iPhone 5S