Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Universal 2D Game Assets and Absolute Node Positioning

I have a question regarding universal game assets and absolute positioning of a SKNodes in Sprite Kit (iOS 8+).

I will try to present my problem through an example as follows:

Imagine a 2D top down game with a SKSpriteNode which represents a house. A house has multiple child SKSpriteNodes which represent chairs, desk, sofa, etc.

I have 3 versions of house asset:

  • 1x - 200 x 200px (Non-retina iPads),
  • 2x - 400 x 400px (Retina iPhones and iPads),
  • 3x - 600 x 600px (iPhone 6 Plus).

Important: Child nodes (chairs, desk, etc.) positions are defined in a .plist file. Something like this (JSON representation):

children: [
    {
        position = {20,20};
    },
    ...
]

Since the position is defined in points and not in pixels, everything gets positioned like expected according to device screen scale. For 1x devices the position stays {20,20}, for 2x position is {40,40} and for 3x the position is {60,60}.

Problem:

The problem is that 200x200px and 400x400px assets are way to small for iPad devices in order to achieve similar look and feel on all devices.

Question:

How to successfully present/import assets in a way that would enable me to achieve similar (if not the same) look and feel on all devices/screen sizes without breaking child nodes positioning?

My takes:

Take 1:

I could simply use the existing 400x400px assets on Non-retina iPad devices and 600x600px assets on Retina iPad devices for the house node but the positioning of a child nodes would become broken. This is because the child position value wouldn't change and would still be {20,20} and {40,40} for iPad devices respectively, while the assets would be bigger. This would yield inaccurate child positions relative to the house node.

Take 2:

I could also scale the SKScene size (zoom effect) while using the normal 200x200px and 400x400px sized assets for iPad devices respectively. This works and it keeps the child nodes positioning working but the rendered quality of the scene/assets is not good as it should be. Also, this feels like a hack and we don't want that.

Take 3:

I could also use twice as big assets for iPad devices and double the child nodes position at the runtime. In this case I would use a 400x400px asset for non-retina iPad devices and a new 800x800px asset for retina iPad devices. While this looks great and keeps the child nodes positioning working, it seems like a really big hack fixing child node position during runtime with this:

if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
    position.x *= 2.0f;
    position.y *= 2.0f;
}

Thank you for taking the time to read the question!

like image 335
damirstuhec Avatar asked Apr 20 '15 07:04

damirstuhec


1 Answers

I could simply use the existing 400x400px assets on Non-retina iPad devices and 600x600px assets on Retina iPad devices for the house node but the positioning of a child nodes would become broken. This is because the child position value wouldn't change and would still be {20,20} and {40,40} for iPad devices respectively, while the assets would be bigger. This would yield inaccurate child positions relative to the house node.

You can simply scale your house node (not the scene) to a larger size. All you need to do is set the scale on your house to a value that looks good on larger devices. And in fact, instead of checking for iPad we can come up with a formula that sets the scale depending on the size of the screen. Something like the code below should work. Note that it assumes your house is positioned perfectly on a iPhone 4 and it will consistently scale to all larger screens. Note that you really could pick any arbitrary size as your base case, but choosing the smallest screen and scaling up is easiest. Just be sure to provide larger textures so that the textures don't become blurry when scaled.

[house setScale:self.scene.size.width/320.0];

OR

You could use two nodes. A root node for holding the "actual" position, and then an image node child for displaying the image. This will allow you to separate your positional data from what's being displayed. You could resize and position your child image node however you want without messing with the actual position of the root node. You could even include this extra image node data in your JSON.


I could also scale the SKScene size (zoom effect) while using the normal 200x200px and 400x400px sized assets for iPad devices respectively. This works and it keeps the child nodes positioning working but the rendered quality of the scene/assets is not good as it should be. Also, this feels like a hack and we don't want that.

This option can definitely work if your App can handle the different aspect ratios in someway. For example you could allow scrolling the scene if the scene is scaled larger than the device screen. The loss in quality occurs because you are scaling the textures larger than their expected size. You need to provide larger textures to keep the quality high when zooming. In this case you could probably just use your 600x600 images (or maybe even larger) and let it scale with zoom. For example, in my RTS Sprite-Kit game for OS X I scale the entire scene so I get the same look across all devices. And I don't lose any quality because I make sure to provide very large textures so there is no loss in quality while scaling.


I could also use twice as big assets for iPad devices and double the child nodes position at the runtime. In this case I would use a 400x400px asset for non-retina iPad devices and a new 800x800px asset for retina iPad devices. While this looks great and keeps the child nodes positioning working, it seems like a really big hack fixing child node position during runtime with this:

This could also work, especially if your iPad requires custom layout. However, if possible avoid checking specifically for iPad and instead use the screen size to create layout rules so your nodes dynamically adjust on all screen sizes consistently (See the line of code above). Sometimes this is not possible if your iPad layout is very different from the iPhone, in which case you will have no choice but to check for iPad.


All three of these solution are good. I wouldn't consider any one of them "hacky." They all work for different purposes. You need to find the solution that works best for your game.

I would also recommend you see my two answers below. Not sure but they may help you with understanding universal positioning and scaling in Sprite Kit.

https://stackoverflow.com/a/25256339/2158465

https://stackoverflow.com/a/29171224/2158465

Good luck with your game, let me know if you have any questions.

like image 120
Epic Byte Avatar answered Oct 20 '22 01:10

Epic Byte