34

i just started a new Sprite Kit project to learn how to use it. I watched and read a lot of tutorials but no tutorial has a answer for my question/problem.

I want to create an application just for my iPhone 5S. So the screen size is 1136x640. I created a 1136x640 background image for my application. But when i add the image to my app, its waaay to big! The iOS Simulator just displays the middle of the image.

Can someone tell me what screen size i have to use and why?

Thanks a lot!

Here is the code which i copied from a tutorial. The code is in the myScene.m file in the initWithSize method

        SKSpriteNode *background = [SKSpriteNode spriteNodeWithImageNamed:@"myBackground"];
    background.position = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMidY(self.frame));

    [self addChild:background];

EDIT:

I searched on google and found this:

The viewDidLoad method has to be changed with "viewWillLayoutSubviews".

Here is this method:

    - (void)viewWillLayoutSubviews
    {
    [super viewWillLayoutSubviews];

    // Configure the view.
    SKView * skView = (SKView *)self.view;
    skView.showsFPS = YES;
    skView.showsNodeCount = YES;

    // Create and configure the scene.
    SKScene * scene = [MyScene sceneWithSize:CGSizeMake(skView.bounds.size.width*2,skView.bounds.size.height*2)];
    scene.scaleMode = SKSceneScaleModeAspectFill;

    // Present the scene.
    [skView presentScene:scene];
}

At first the scene = MySceneWithSize line was:

SKScene * scene = [MyScene sceneWithSize:skView.bounds.size];

But then it was just the half of the iPhone 5 screen size (568x320). So i had to double the size. Does somebody know why?

CodeSmile
  • 64,284
  • 20
  • 132
  • 217
Mike_NotGuilty
  • 2,253
  • 5
  • 32
  • 64
  • 1
    Just a thought: if you want to make an app for your phone, you really should test it primarily on your phone. The simulator tends to be a source of pain, in my humble experience. – Kheldar Feb 16 '14 at 01:36
  • Mike - if you're still on SO, could you mark the correct/most useful answer below. I'm biased, but I think mine's the one ;-) – GilesDMiddleton Sep 21 '15 at 13:27
  • 1
    @Gilesey - I'm sorry.. totally forgot about this thread. Sure. Your answer works. – Mike_NotGuilty Sep 22 '15 at 16:41

9 Answers9

30

The short answer to your immediate problem:

background.size = self.frame.size;

The long answer, and discussion about other methods...

The scene works in Logical Units, not physical pixels (as mentioned in other posts).

1 Logical Unit is typically 1 pixel on older kit, and 2 pixels on newer kit/iPads. This maybe 4 pixels in 5 years time.

Working in Logical Units protects you from sizes changing in future, and is supposed to help the programmer - although this often confuses newbies.

The simplest way to get an image to fill the current scene is to set its size in 'logical units' no matter what size it is originally.

This is better than using SKActions (because the user might end up seeing them, and any calculations based on the dimensions of the node can't be relied upon until the action has completed), and it's better than scaling because scaling requires you to know the original image dimensions.

You can do this via the size property, or through an action if you really want to make an animation.

In the scene simply....

-(void)didMoveToView:(SKView *)view
{
    [super didMoveToView:view];

    SKSpriteNode* background = [SKSpriteNode spriteNodeWithImageNamed:@"myBackground"];
    background.size = self.frame.size;
    background.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
    [self addChild:background];
} 

Alternatively, if your image works well, as is, on higher resolutions, you can rename your image to myBackground@2x.png, add that to your project and you probably won't need to resize at all, but you'll also need to shrink it by 50% for the lower resolution devices, and save that as myBackground.png.

I always set the size of an imported image to exactly the logical units I want (or a percentage of the screen dimensions) to preserve my sanity.

GilesDMiddleton
  • 2,279
  • 22
  • 31
  • 1
    this is the most important part of setting the BG image in sprite kit. background.size = self.frame.size; well done man. – Adrian P Feb 07 '15 at 15:54
9

I've found that if an image is not the same size as the node you are looking to create the sizing gets a little funny (say using a retina image on a non-retina device or incorrect image naming). You can scale the image to fill if you create the texture from the image and set the texture and the node size using something like the following:

SKTexture *backgroundTexture = [SKTexture textureWithImageNamed:@"MyImage.png"];
SKSpriteNode *background = [SKSpriteNode spriteNodeWithTexture:backgroundTexture size:self.view.frame.size];
background.position = (CGPoint) {CGRectGetMidX(self.view.frame), CGRectGetMidY(self.view.frame)};
[scene addChild:background];

I'm not a 100% sure this if this will fix your issue or not but it might be worth a shot.

James Jones
  • 1,486
  • 1
  • 12
  • 22
  • Sorry to bother you... but I'm curious... is there a reason/benefit/advantage to using a SKTexture instead of just doing something like this with an image: SKSpriteNode *bgImage = [SKSpriteNode spriteNodeWithImageNamed:@"background"]; – Confused Jun 21 '14 at 13:43
  • 1
    When I was playing with SpritKit last year I found that [SKSpriteNode spriteNodeWithImageNamed:@"background"]; would not scale the images to a specified SKSprideNode size (for example if my image was 20x20 it would not scale the image when I set the node size to 100x100). However doing a separate SKTexture and passing it to the constructor with a different size would scale the image. I haven't played with SpritKit since 7.1 has been release so IDK if this is still true or not. – James Jones Jun 27 '14 at 16:58
8

This line returns size in points, not pixels. This is made because different devices have different resolutions, but will have same sizes in points. On non retina devices 1 point is 1 pixel and on retina devices 1 point is two pixels. Thats why you get this size from

SKScene * scene = [MyScene sceneWithSize:skView.bounds.size];

You don't want to double the size of scene since it will just be our of bounds of your screen, invisible.

Dvole
  • 5,725
  • 10
  • 54
  • 87
7

Have you tried adding "@2x" to the end of the name of your image?

  • I think it might only be for Xcode 5, but Xcode can automatically depict which image resolution you're using. If you are using both 2x and just the standard, it will usually just pick the 2x as automatic – user2277872 Feb 02 '14 at 18:42
  • This. Also, try in a real device, not the simulator. – Nicolas Miari Apr 17 '14 at 05:58
3

I basically do as the answers above however I go ahead and set the width and height directly so that I don't have to worry about if it is set correctly or not, of course I would also need to check if there were using an iPhone4 for a complete solution.

- (void)viewWillLayoutSubviews
{
    [super viewWillLayoutSubviews];

    // Configure the view.
    SKView * skView = (SKView *)self.view;
    if (!skView.scene) {
        skView.showsFPS = YES;
        skView.showsNodeCount = YES;

        CGSize tmpSize;
        tmpSize.width = 640;
        tmpSize.height = 1136;
        // Create and configure the scene
        SKScene * scene = [CreationScene sceneWithSize:tmpSize];

        scene.scaleMode = SKSceneScaleModeAspectFill;

        // Present the scene.
        [skView presentScene:scene];
    }
}
2

This worked for me. Is this ok to do?

//Set background image.
    SKSpriteNode *background = [SKSpriteNode spriteNodeWithImageNamed:@"myBackground.png"];
    background.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
    background.xScale = 0.5;
    background.yScale = 0.5;

    [self addChild:background];
Jason
  • 650
  • 2
  • 10
  • 33
  • It's ok to do, if you never change the underlying image dimensions. If you did, you'd have to change your code. By setting .size you will protect yourself from that type of change. – GilesDMiddleton Jan 17 '15 at 20:19
2

Solution:

Put this code into your viewWillLayoutSubviews instead into the viewDidLoad of the UIViewController which loads the sprite.

  - (void)viewWillLayoutSubviews
{
    [super viewWillLayoutSubviews];

    // Configure the view.
    SKView * skView = (SKView *)self.view;
    if (!skView.scene) {
      skView.showsFPS = YES;
      skView.showsNodeCount = YES;

      // Create and configure the scene.
      SKScene * scene = [MyScene sceneWithSize:skView.bounds.size];
      scene.scaleMode = SKSceneScaleModeAspectFill;

      // Present the scene.
      [skView presentScene:scene];
    }
}

Explanation : This creates the scene with a size as the bounds of the view. However, when viewDidLoad is called, this is before the view has been added to the view hierarchy and hence it hasn’t responded to layout changes yet. So the view bounds might not be correct yet, and this probably isn’t the best time to start up the scene.

This answer is copied from : http://www.raywenderlich.com/42699/spritekit-tutorial-for-beginners The credit goes to Ray :).

I have used the same code in my SKScene like you, but without this solution Ray offered in the UIViewController which presents the scene it would not work.

MB_iOSDeveloper
  • 4,178
  • 4
  • 24
  • 36
2

I did use and sprite for background.

    double escalax =        self.size.width/ sprite.size.width  ;
    double escalay =        self.size.height/ sprite.size.height  ;


    SKAction *mostrar = [SKAction scaleXTo:escalax y:escalay duration:0];

Hope it helps!

1

I got the same issue with you. After several days googling and trying, finally I got the key of this problem. You can try to change your scene.scaleMode several times, until you got the size which you satisfied with. I just found this last night, so if you want to know more, here is a link

https://developer.apple.com/library/ios/documentation/SpriteKit/Reference/SKScene_Ref/Reference/Reference.html#//apple_ref/doc/uid/TP40013024-CH1-DontLinkElementID_3

Alfred
  • 161
  • 10
  • Finally I fix my issue. I had set the scene to 1024*768, so the height of my scene is 768, not 480. Everybody who saw this can have a try. – Alfred Aug 29 '14 at 13:20