2

The sprites in my SpriteKit game, though properly scaled, are being rendered extremely small in my scenes. I've been following a few different tutorials using similarly sized sprites and theirs are scaled fine in the simulator. Below are some code snippets and screenshots. For example, the pause button on the top right of the screen is crazy small, yet the actual resolutions of the assets are standard in size.

GameScene.swift

private let pauseTex = SKTexture(imageNamed: "PauseButton")    

...

private func setupPause() {
    pauseBtn.texture = pauseTex
    pauseBtn.size = pauseTex.size()
    pauseBtn.anchorPoint = CGPoint(x: 1.0, y: 1.0)
    pauseBtn.position = CGPoint(x: size.width, y: size.height)
    pauseBtn.zPosition = Layer.Foreground.rawValue
    worldNode.addChild(pauseBtn)Btn)

    ...
}

GameVC.swift

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()

    ...

    if let skView = self.view as? SKView {
        if skView.scene == nil {

            let aspectRatio = view.bounds.size.height / view.bounds.size.width
            let scene = MenuScene(size: CGSize(width: 750, height: 750 * aspectRatio))

            scene.scaleMode = .aspectFill
            skView.ignoresSiblingOrder = true

            ...
        }
    }
}

enter image description here

enter image description here

Mike
  • 1,307
  • 3
  • 17
  • 29
  • Have you set the node's `size` property? – Jonathan H. Dec 06 '16 at 18:56
  • You are gonna want to set the size of the scene to match the size of the window on the device, then setup your objects so that the size is in relation to the actual size of the screen (percentages is easy). You do have to explicitly set it up. – MoDJ Dec 06 '16 at 19:03
  • what is the size of your 1x 2x and 3x graphics, they need to be the correct multiples – Knight0fDragon Dec 06 '16 at 19:03
  • do not do what @MoDJ says, that is the worst way to work with it – Knight0fDragon Dec 06 '16 at 19:05
  • @MoDJ, spritekit has scaleMode for a reason, you design for 1 size, and the system scales for you. No need for countless amounts of division, where you can easily mess up the math and waste time debugging – Knight0fDragon Dec 06 '16 at 19:07
  • So, I just updated the code to reflect setting the size property, though the size did not change. The graphics sizes are: 32x32, 64x64, 96x96. – Mike Dec 06 '16 at 19:12
  • ok, what is the size of the scene and the scalemode – Knight0fDragon Dec 06 '16 at 19:12
  • You are on iphone SE, so the desired scene size should be 320x568 for that device with a scale mode of .aspectFill – Knight0fDragon Dec 06 '16 at 19:13
  • this would make your pause button fill 1/10th of the scene size – Knight0fDragon Dec 06 '16 at 19:14
  • @Knight0fDragon, running the app on my device (iPhone 6s) still results in the sprite scaled in the same manner (just as small). – Mike Dec 06 '16 at 19:16
  • @Mike, of course there is no difference, you set the size of the sprite to the size of it's texture, which will end up the same as before. See my answer and test the size property with the size I provided as an example and see the difference. – Jonathan H. Dec 06 '16 at 19:16
  • `let scene = MenuScene(size: CGSize(width: 750, height: 750 * aspectRatio))` This means your fake screen size is 750 width. so a width of 32 would only cover 5% of the screen, which that may be doing – Knight0fDragon Dec 06 '16 at 19:17
  • So it sounds like I shouldn't be hardcoding the size of the SKScene? How should I properly set the size of the SKScene so that it scales properly across all iPhone devices? – Mike Dec 06 '16 at 19:20
  • hardcoding the size of your scene is actually the correct way to do it (other than use an sks file) when dealing with aspect fill, you need to make your assets proportionate to the size of your scene though, I am assuming the tree background is 750 width? – Knight0fDragon Dec 06 '16 at 19:21
  • The bg is 750x1334. So then if I'm understanding you correctly, I'm simply not sizing my other sprites correctly. – Mike Dec 06 '16 at 19:24
  • ok that is iphone 6 size, make the scene size 375x667 so that you are working at the 1x level, no idea why apple did not do this be default. 1x should be 375x667 2x should be 750x1334 and 3x should be 1125x3001 for your bgImage, then make your scene size be 375x667. Your pause button should now be about 9% of the screens width when this happens, and should look the same across all devices except the ipads – Knight0fDragon Dec 06 '16 at 19:25
  • Is there any documentation explaining how to correctly size these sprites? My BP is making these sprites from hand and we've been guessing (based off tutorial projects) the sizes of the 1x, 2x, 3x sprites. – Mike Dec 06 '16 at 19:28
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/129940/discussion-between-knight0fdragon-and-mike). – Knight0fDragon Dec 06 '16 at 19:29
  • Knight, you might have your way you like to do things. That does not mean other people are wrong. For example, using the default size and letting the system scale it for you means you cannot control pixel exact rendering. That would be a problem if you wanted to implement a pixel exact repeating pattern, like the following: http://www.modejong.com/blog/post20_spritekit_repeat_shader – MoDJ Dec 06 '16 at 19:41
  • @MoDJ, this would mean you would be using the .resizeFill scalemode, and are expecting different results across every device – Knight0fDragon Dec 06 '16 at 19:47
  • @MoDJ that repeating pattern is at the texture level, so the scaleMode should not affect it. also, yes there are rare circumstances where percentage works, but for a majority of games that beginners are working in, it is easier to work in a unified integer based system and let the hardware fit it to the screen for you. – Knight0fDragon Dec 06 '16 at 19:55
  • @MoDJ, did you happen to test this in iOS10? Is the shader performance improved? I have actually been looking for a way to repeat textures – Knight0fDragon Dec 06 '16 at 19:58
  • Yes, the performance under iOS 10 and Metal render mode seems to be fixed, that problem only seems to have been under iOS 9 and Metal mode (note that OpenGL mode worked just fine). It is kind of weird because, the basic FPS output on lower right screen seems to now be broken for default SpriteKit projects under IOS 10 and the FPS display inside Xcode is also not working in either OpenGL or Metal mode. This repeat shader is really a nice little bit of shader code, it works just fine in OpenGL or Metal mode. – MoDJ Dec 06 '16 at 20:12
  • Another situation where exact pixel rendering from the texture to the node can be required is when a movie at say 1024x1024 is decoded and then that is rendering into a node, if you do not want to have to deal with any weird scaling issues or non exact pixel color changes then the size of the scene can be set to the exact screen size and the size of the node can be set to exact pixels so that the shader basically just copies the pixel data onto the screen at a 1 to 1 ratio. – MoDJ Dec 06 '16 at 20:17
  • @MoDJ, yes, anytime where you want pixel perfect images you would have to use the .resizeFill scaleMode, this should not be something that should be taken as "easy" (heck dealing with shaders is very advance). Pixel perfect may not even be needed for most, the pixels are so small that you can barely notice them to begin with – Knight0fDragon Dec 06 '16 at 21:19

2 Answers2

1

Basically what has happened here is Mike got confused with scene size vs screen size. He was thinking that since the sprite was 32 pixels, it should be taking up 10% of the iPhone SE Screen since it has a 1x width of 320 (Natively it is 640 [2x]) But in reality, his scene is 750 pixels wide, so it was only showing at 5%. He switched his scene size to be 375x667 (iPhone 6 non retina resolution) to properly use the retina graphics, and now everything should be aligning up for him.

The only issue he is going to come across with now, is cropping on iPad devices. He just needs to work in safe zones for this.

Knight0fDragon
  • 16,609
  • 2
  • 23
  • 44
0

The size of your assets will not always reflect the desired size on-screen due to resolution discrepancies between different devices (this is true if the SKScene's scaleMode is set to resizeFill). If you want a specific size for your sprite, you need to set the SKNode's size property to your desired value.

What this would look like in your method:

private func setupPause() {

    pauseBtn.anchorPoint = CGPoint(x: 1.0, y: 1.0)

    // Set size property (arbitrarily selected below)
    pauseBtn.size = CGSize(width: 50, height: 50)

    pauseBtn.position = CGPoint(x: size.width, y: size.height)
    pauseBtn.zPosition = Layer.Foreground.rawValue
    worldNode.addChild(pauseBtn)

}
Jonathan H.
  • 939
  • 1
  • 7
  • 21
  • this is not true except in the case of resizeFill or fake resize fill, which would make the button size disproportionate across the various screen sizes – Knight0fDragon Dec 06 '16 at 19:04
  • @Night0fDragon, you are right, I could have explained that better. However this doesn't change the fact that neither the `size` property nor the `setScale()` method was set, and he was relying solely on the original size/scale of the resource (which clearly is not the desired scale). – Jonathan H. Dec 06 '16 at 19:09
  • we are missing a lot of info here, like scaleMode, scene size, and size of all 3 assets – Knight0fDragon Dec 06 '16 at 19:11
  • One sec Knight, will update question with more info! – Mike Dec 06 '16 at 19:13
  • @Knight0fDragon I've added the info you've requested. – Mike Dec 06 '16 at 19:15