Constraining proportions of GUI elements in Spritekit game

我与影子孤独终老i 提交于 2019-11-30 07:30:02
Skyler Lauren

Uniform GUI and Game Play

As far as I can tell the best way to handle a uniform GUI and game play is to set your scene size (regardless of device) and let SpriteKit scale from there.

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

That is the points for an iPhone 6. Because SpriteKit works in points but devices display in pixels the scene size will be 750px x 1354px pixels for @2x devices and 1125px x 2031px for the iPhone 6+ (the device in pixels is actual 1080 x 1920).

How does this work with assets?

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

What about @3x?

This is a better question for Apple. Apparently SpriteKit does not support @3x images in a texture atlas. There are a few question already on SO that have tried to address this.

One example...

Spritekit - not loading @3x images from SKTextureAtlas

It appears it hasn't been fixed in Xcode 6.2 either. If you are reading this and want @3x it might be worth filing a radar with Apple. One thing to note is that I didn't see anywhere in the docs claiming that texture atlases are suppose to support @3x (or even @2x for that matter) When they are supported you won't have to do any changes to your code. Just throw the @3x assets into your .atlas folders.

What can/should I do about the @3x assets?

My advice is to not worry about it and run @2x assets. SpriteKit does a decent job scaling images and there are a lot of apps out there that don't support @3x. As a fellow iPhone 6+ owner it is just something I have learned to live with at the moment. I hope that Apple supports the @3x images in the .atlas folder very soon.

Warnings

You are asking all devices to scale down with the exception of the iPhone 6 (and scaling up iPhone 6+) In most cases you shouldn't notice a big difference in your art (or performance from my testing), but as you know if you shrink images they may look slightly different. Also there is the black bar issue on the 4s which I don't have a solution for you at the moment.

Closing Points

You will get the exact same look and feel in your app across all devices if you set the scene size and set your scene to SKSceneScaleModeAspectFill however you are asking older devices to scale down. It saves a ton of time and planning with minor draw backs as far as I see it.

Hopefully that helps and the best of luck on your app.

Your main issues seem to be handling the various screen sizes in relation to your image assets and screen object coordinates.

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

With just a bit of code I was able to get an uniform layout for the iPhone 6 plus, 6, 5 and 4 screen sizes. I have included screen shots for each one. The character image is 300x300. The 2 button images are 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

iPhone 5

iPhone 6

iPhone 6+

Notice how even the text label is scaled down correctly not just by font size but also location.

For your reference, I did use the standard code in my GameViewController because I find it easier to work with a simpler version. This is the code I used to present my SKView:

- (void)viewDidLoad {
    [super viewDidLoad];

    SKView * skView = (SKView *)self.view;
    SKScene *scene = [GameScene sceneWithSize:skView.bounds.size];
    scene.scaleMode = SKSceneScaleModeAspectFill;
    [skView presentScene:scene];
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!