Why doesn't SKCameraNode center if aspect mismatch? Bug? - ios

Is there a bug in SKCameraNode when used with .AspectFill on devices where the aspect ratio of the SKScene does not match that of the devices view?
I have a minimal demo of the issue I see: an SKScene created in an SKS file, to be 768w x 1024h, filled with an image (also 768w x 1024h). It's loaded with .AspectFill. An SKLabel is positioned in the middle of the scene programmatically. The demo is simply the out-of-the-box iOS template for a SpriteKit game, with a background image added.
An iPad in Portrait (so 768w x 1024h) displays this fine. An iPhone 6+ in Portrait (414w x 736h) displays fine. An iPhone 5S (320w x 568h) displays fine.
If I add a camera to the scene, position it in the middle by setting its coordinates to (384, 512) in the SKS file and set the scene to use it, the iPad is fine but now the iPhones (and any other device with a aspect ratio other than 3:4) does NOT work. It displays the right-hand side of the scene. It is not centered. Screen shot from the iPhone below.
The camera being in the middle of the scene, should ALWAYS work.
I am currently using a work-around. When you use .AspectFill the sides of the scene are cropped by an amount - let's call it cropAmount - to fit on the narrower screen. The work-around is to move the camera left, so it is off-center by cropAmount, then the scene displays correctly.
The background image here is an #3x of a 768w x 1024h background for my game. I've put in green the cropAmount corresponding to the SKView for 9:16, and in red the scene bounds. Given the camera is set in the middle of the scene, same as the label and the pink dot in the middle of the image, why is the center of the view not also there?
If this is a bug, and I leave in my "fix" where I offset the camera by cropAmount, later updates could break production code running on devices.
Also I am not using .ResizeFill as it doesn't fix the camera node issue, and would also mean that the assets are incorrectly sized and positioned in the scene for the thousands of lines of code and dozens of SKS files I already have over 6 months of work.
Question has been edited. Originally I had my "fix" added as an extension but this just caused confusion so I have removed it.

Related

Scale sceneView to fit screen

I am developing a sample game using SceneKit and Swift in Xcode, I added a ship node (default) and add some animations. The problem is that the sceneView does not fit the screen because the aspect ratio does not seems to bee 16:9 as the screen of an average iPhone screen size. How can I scale the sceneView to fit the screen?
I found out that the best way of solving this issue was to set the Launch Screen File = Main

Scale sprite kit game for all devices

When creating my game in spriteKit I used the game size 1080x1920. Now however If I am to run it on Ipad it looks bizarre. Is there an easy fix? I am simply worried that my app will get rejected. Thank you in advance?
Its quite a commonly asked question.
What we usually do in SpriteKt is to give the SKScene a fixed size and let SpriteKit do the scaling for you on different devices.
So basically we have 2 ways to do it correctly
1) Set scene size to iPad (e.g 1024x768 -landscape, 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 (750*1334-Portait, 1334*750-Landscape). This setting will crop your game on iPads.
Examples of games that show less on iPads:
Lumino City, Robot Unicorn Attack
Choosing between those 2 options is up to you and depends what game you are making.
Regardless of scene size scale mode is usually best left at .aspectFill or .aspectFit, again depending on what you prefer and need (e.g cropping with aspectFill or black bars with aspectFit)
You would use the Universal asset slot and/or device specific images. This way you will have a consistent experience on all devices
Spritekit scale full game to iPad
How to make SKScene have fixed width?
Hope this helps
When you present the scene's you also set the aspect ratio.
example :
if let scene = SKScene(fileNamed: "GameScene") {
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill
// Present the scene
view.presentScene(scene)
}
There are 4 different aspect radios you can set
aspectFit
aspectFill
fill
resizeFill
You can find out about the 4 different types here in the apple documents.
It looks to me that you currently have it set to aspectFill but you would be better off using aspectFit. This will create a black bar on the top and bottom on some devices but it will keep the aspect ratio the same.
If you want it to look good on all devices(no black bar) you would need to check which device it is running on then update the size and position of your sprites accordingly.
Whenever scenes are hard coded, (not made within the editor) using .resizeFill will ensure that the width AND height of the scene ALWAYS conform to the view. So your game will scale correctly on any device. For scenes that are made within the editor, this is not the case.
Personally, I hardcoded all the levels in my game "Astro Path" (it's on the app store for reference) and used .resizeFill so it would scale correctly on any device without any cropping or black bars. (who wants that stuff yuck) For my title screens, I used:
.aspectFill on iPhone
.fill on iPad
because they were designed within the editor. I checked for the current device using: if UIDevice.current.userInterfaceIdiom == .pad { do w/e }

SpriteKit camera is not centred with aspectFit

My scene is set to be .AspectFit. I have camera node in scene center and it is connected. Everything works fine for iPad landscape, but when I rotate simulator or run in different device then iPad in landscape camera is not centred. Why?
This is for landscape with camera on center:
After rotation camera is not centred:
Similar issue is for e.g. for landscape iPhone5s:
Why is camera shifted with scene setting .AspectFit with other device then iPad in landscape?
You can try out or experiment with this project on bitbucket I made.
EDIT: When I don't use camera, everything is on its place.
Set the scene anchor point to 0.5, 0.5 to center your camera onto the scene , there is an issue with the view to scene conversion, and will draw in the top left corner instead of the center. (Also, you will notice your hello world is off, this is because it is not accounting for the anchor change)
Perhaps the lack of a camera will make the scene translate where it draws to inside of the black bars, I have no idea.

How to scale app so iPhone 6 is identical(zoomed) to iPhone 5 SpriteKit

Ive been making an app using sprite kit in Xcode 7. I made all my sprite nodes positioned around by referencing other sprite nodes and self.frame
for example
self.block.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame)
When I came to test my app on an iPhone 6 Plus (I previously tested on iPhone 4s but it worked nicely on an iPhone 5) My app didn't scale the nodes, Just the space Between them. The game relies on everything being the same otherwise people playing on an iPhone 6 would find it easier then people playing on a smaller device. Is there anyway that I could make the iPhone 6 view just a stretched version of the iPhone 5 view? Thanks Guys!
It's best not to position your sprites using self.frame as a reference. Much better to treat the scene as the "true" coordinates and let SpriteKit scale your scene for you.
ie. Specify the scale mode of your scene when you create it (probably in the view controller viewDidLoad). I prefer AspectFill for the scale mode, which makes sure the screen is filled, but you will lose the edges on some devices. Just make sure the core gameplay is in the middle of the scene.
scene.scaleMode = .AspectFill
Then, position your sprites using the size of your scene for reference. On a landscape scene, I tend to use a scene size of 1024x768 (iPad size).
Hope that helps.
Another way: If you remove the iPhone 6 and iPhone 6+ launch images from the project then those devices will switch to "zoom mode", which is exactly the same view as on iPhone 5, just bigger (well, zoomed).
Just look in your project for "Images.xcassets", there is a image-set called "LaunchImage". In this image-set are multiple other images, just remove the one for iPhone 6 and 6+.

SpriteKit position confusion

In learning SpriteKit so I'm making a scene with 1 buttons. I do not understand the way positions work. What I read was that 0,0 was the bottom left corner and the default anchor point is in the middle of each button (0.5,0.5). The scene is scene.scaleMode = .AspectFill. If I write:
self.playButton.position = CGPointMake(self.playButton.size.width/2,CGRectGetMidY(self.frame))
self.addChild(self.playButton)
I get what is in the screenshot below.
If I set the playbutton.position.x to be self.playbutton.size.width/2 then I would assume it would be on the left edge of the screen. Not weirdly somewhat off the screen. I've read the documentation about size for a couple of days now and I still can't seem to understand it. I've also explicitly set:
self.size.width = 768
self.size.height = 1024
Meaning the scene size width and height. Also I have "Use Auto Layout" in the main storyboard checked.
If you change your scene's scale mode to .AspectFit you'll be able to quickly see what the problem is. The resolution you're setting for your scene is a completely different aspect ratio from that of your device. In fact, when I answered your last question, I assumed that your usage of the 768x1024 resolution meant that you were developing for an iPad, for which this is the correct resolution.
On an iPhone with a 4 inch screen, you should be setting the scene's size to be 320x568, and 320x480 for 3.5 inch screens. This can however be simplified by adding this line to the creating of your scene in your view controller. It will set the scene's size to the size of the view controller's view.
scene.size = skView.bounds.size

Resources