Limiting the proportions of GUI elements in a Spritekit game

GUI elements example image

I apologize in advance for the huge post, but everyone who has ever tried to make some kind of universal application knows that this is quite problematic, so please be calm ...

goal

What I'm trying to achieve (shown in the image above) is to use @ 2x assets on iPhone 5 and 6 and maintain the same look and feel of the application. And, if possible, do all this without manually calculating the properties of the scale and the position of the nodes based on the detected device ... In short, how to get this application to automatically keep the proportions between the elements (and the scene)? I would also like to have the same kind of application on iPhone 6+ using @ 3x assets, but because of simplicity, I focused only on iPhone 5 and 6.

What I found on the Internet is that some people say that this (downsampling) is done automatically by iOS, for example, they offer this:

"Make the assets @ 2x the size of the iPhone 6, and then iOS will automatically scale for the iPhone 5."

But this is obviously not true when it comes to the Spritekit scene, or I'm missing something.

Problem

Despite the fact that the iPhone 6 and iPhone 5 have the same aspect ratio and the same PPI, using the same asset will not look compared to the size of the scene (see the sprite menu on the 1st and 2nd images compared with the size of the scene), since PPIs are related to the pixel density, and the iPhone 6 has more space (large diagonal, more inches), which means that it has more pixels than the iPhone 5. And here my problem arises, and I don’t know what would be an efficient way to handle it.

What have i done so far

The second image is not a problem for the graphical interface, but for the gameplay in my case it is because I want the same appearance on different devices. Just look at the first and third image.

Thanks to the Skyler Lauren proposal, I was able to get the same appearance of the application on all iPhone 5 devices, either on 7.1 or 8.1 systems, as well as on iPhone 6. So, now the problem is how to adapt this code to work with iPhone 6+ using textures @ 3x, as well as on the iPhone 4s. Here is the solution for iPhone 5 and 6:

View .m controller

GameScene *scene = [GameScene sceneWithSize:CGSizeMake(375,677)];//fixed instead of view.bounds.size scene.scaleMode = SKSceneScaleModeAspectFill; 

Thus, the scene always has a fixed size in the dimensions of the iPhone 6, and the size of the view varies depending on the device. I use the resource directory for startup images, not an xib file. Images have a recommended size of 640x960px for 4s, 640x1136px for 5, 750x1334px for 6, and 1242x2208 for 6+. Assets are sized for the iPhone 6, so there is no scaling for this model at all.

Regarding the 4s model, when I use this method described above, there are two black bars on each side ...

So far, I only tested this on the simulator and the iPhone 6 device (what I see is like the first image on the device or simulator).

Question

So far I have said that everything works on iPhone 4s (with two black bars due to different proportions), 5, 6 using 2x2 assets, but how to make everything work with iPhone 6+ using @ 3x assets? If I use the dimensions 375x667 for the scene, then everything is positioned correctly and has good proportions, but the quality suffers (due to 2x zooming)

+6
ios size sprite-kit sprite
Mar 22 '15 at 19:29
source share
2 answers

Unified graphical interface and game play

As far as I can tell, the best way to handle a unified graphical interface and gameplay is to set the size of your scene (regardless of device) and release the SpriteKit scale.

 GameScene *scene = [GameScene sceneWithSize:CGSizeMake(375,677)];//fixed instead of view.bounds.size scene.scaleMode = SKSceneScaleModeAspectFill; 

These are dots for iPhone 6. Since SpriteKit works in dots, but devices are displayed in pixels, the scene size will be 750 pixels x 1354 pixels for devices @ 2x and 1125px x 2031px for iPhone 6+ (the device in pixels is actual 1080 x 1920).

How does this work with assets?

Well this works well enough for 1x and 2x assets in the .atlas folder. Again, because everything is converted to points, you can have button.png and button@2x.png in the texture atlas, and the positioning will be the same and look the same for all iPhones.

What about @ 3x?

This is the best question for Apple. SpriteKit does not seem to support @ 3x images in texture atlas. There is still a question about SO that tried to solve this problem.

One example ...

Spritekit - not loading @ 3x images from SKTextureAtlas

It looks like it has not been fixed in Xcode 6.2. If you are reading this and want @ 3x, it might be worth ordering a radar from Apple. It should be noted that I have not seen anywhere in documents claiming that texture atlases are supposed to support @ 3x (or even @ 2x, for that matter). When they are supported, you don’t have to make any changes to your code, just drop the @ 3x resources into your .atlas folders.

What should I do / need to do with @ 3x assets?

My advice is not to worry about this and run @ 2x assets. SpriteKit does decent image scaling, and there are many apps that don't support @ 3x. Owning an iPhone 6+, this is what I learned to live with right now. I hope that Apple will soon save @ 3x images in the .atlas folder.

Warnings

You are requesting that all devices shrink, with the exception of the iPhone 6 (and expanding the iPhone 6+). In most cases, you should not notice a big difference in your art (or performance from my testing), but as you know, if you compress images, they may look a little different. There is also a problem with the black bar on 4s, on which I have no solution right now.

Closing points

You will get the same look in your application on all devices if you set the scene size and set your scene to SKSceneScaleModeAspectFill , however you will ask older devices to zoom out. As far as I understand, this saves a ton of time and planning with a few digressions.

Hope this helps and good luck with your application.

+5
Mar 26 '15 at 1:23
source share

Your main problems seem to be related to different screen sizes in relation to your images and the coordinates of the display objects.

My solution is to write your code as if you were encoding the iPhone 6 plus. Make all your 3x images and screen coordinates for iPhone 6 screen size.

With just the code, I was able to get a single format for the screen sizes of the iPhone 6, 6, 5 and 4. I included screenshots for each of them. Character image 300x300. Images with two buttons 100x100.

 static const float kIphone6PlusScaleFactorX = 1.0; static const float kIphone6PlusScaleFactorY = 1.0; static const float kIphone6ScaleFactorX = 0.9; static const float kIphone6ScaleFactorY = 0.9; static const float kIphone5ScaleFactorX = 0.772; static const float kIphone5ScaleFactorY = 0.772; static const float kIphone4ScaleFactorX = 0.772; static const float kIphone4ScaleFactorY = 0.652; #import "GameScene.h" @implementation GameScene { float scaleFactorX; float scaleFactorY; SKSpriteNode *node0; SKSpriteNode *node1; SKSpriteNode *node2; SKLabelNode *label0; } -(void)didMoveToView:(SKView *)view { self.backgroundColor = [SKColor blackColor]; if(view.frame.size.height == 736) { NSLog(@"iPhone 6 plus"); scaleFactorX = kIphone6PlusScaleFactorX; scaleFactorY = kIphone6PlusScaleFactorY; } if(view.frame.size.height == 667) { NSLog(@"iPhone 6"); scaleFactorX = kIphone6ScaleFactorX; scaleFactorY = kIphone6ScaleFactorY; } if(view.frame.size.height == 568) { NSLog(@"iPhone 5"); scaleFactorX = kIphone5ScaleFactorX; scaleFactorY = kIphone5ScaleFactorY; } if(view.frame.size.height == 480) { NSLog(@"iPhone 4"); scaleFactorX = kIphone4ScaleFactorX; scaleFactorY = kIphone4ScaleFactorY; } node0 = [SKSpriteNode spriteNodeWithImageNamed:@"Pic"]; node0.position = CGPointMake(self.size.width/2, self.size.height/2); [node0 setScale:scaleFactorX]; [self addChild:node0]; node1 = [SKSpriteNode spriteNodeWithImageNamed:@"button0"]; node1.position = CGPointMake(100*scaleFactorX, 100*scaleFactorY); [node1 setScale:scaleFactorX]; [self addChild:node1]; node2 = [SKSpriteNode spriteNodeWithImageNamed:@"button1"]; node2.position = CGPointMake(314*scaleFactorX, 100*scaleFactorY); [node2 setScale:scaleFactorX]; [self addChild:node2]; label0 = [SKLabelNode labelNodeWithFontNamed:@"HelveticaNeue-Bold"]; label0.text = @"Big Game Menu"; label0.fontSize = 48*scaleFactorX; label0.fontColor = [SKColor whiteColor]; label0.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeCenter; label0.verticalAlignmentMode = SKLabelVerticalAlignmentModeCenter; label0.position = CGPointMake(207*scaleFactorX,690*scaleFactorY); [self addChild:label0]; } 

iPhone 4

enter image description here

iPhone 5

enter image description here

iPhone 6

enter image description here

iPhone 6+

enter image description here

Please note that even the text label is reduced correctly not only in font size, but also in location.

For your reference, I used the standard code in my GameViewController, because it is easier for me to work with a simpler version. This is the code I used to represent my SKView:

 - (void)viewDidLoad { [super viewDidLoad]; SKView * skView = (SKView *)self.view; SKScene *scene = [GameScene sceneWithSize:skView.bounds.size]; scene.scaleMode = SKSceneScaleModeAspectFill; [skView presentScene:scene]; } 
+5
Mar 26 '15 at 1:56
source share



All Articles