7

TL;DR : I want to find a method to give an impulse to an object so that the speed of this object is precisely proportional to the scene size.

I am currently building a SpriteKit game that will be available on many different screen sizes, my scene resizes itself to be the same size in points as its view (scene.scaleMode = .ResizeFill), when I launched my game on other devices than the one which I had developed it, I noticed that :

  • The size of nodes was too small

  • The speed of the objects was too low (the way I give speed to my objects is by calling applyImpulse(:_) on their physics body).

I think I fixed the size issue with a simple proportionality operation : I looked at the objectArea/sceneArea ratio of the scene that had the correct object size and than, instead of giving fixed dimensions to my objects, I simply gave them dimensions so that the ratio is always the same regardless of the scene area.

For the object speed, it was trickier...
I first thought it was due to the physics body mass being higher since the object itself was bigger, but since I attributed to objects their mass directly via their mass property, the objects would have the exact same mass regardless of their size.

I finally figured out that it was just due to the screen size being different therefore, an object, even by moving at the same speed, would seem to move slower on a bigger screen.

My problem is that I don't know exactly how to tune the strength of my impulse so that it is consistent across different scene sizes, my current approach is this one :

force = sqrt(area) * k

Where k is also a proportionality coefficient, I couldn't do the proportionality on the area, otherwise, speed would have grown exponentially (so I did it with the square root of the area instead).

While this approach works, I only found this way of calculating it with my intuition. While I know that objects areas are correctly proportional to the scene size, I can't really know if the speed can be considered as equivalent on all screen sizes

Do you know what I should do to ensure that the speed will always be equivalent on all devices ?

Pop Flamingo
  • 3,023
  • 2
  • 26
  • 64
  • um, I have a question, why are you manually doing scaling? Just make 3 sks files (one that has a 16:9 aspect, one that has a 4:3 aspect and one that has a 3:2 aspect) and just select the correct one with .AspectFill scaleMode – Knight0fDragon Aug 30 '16 at 13:03

1 Answers1

4

Don't do it

Changing the physics world in relation of the screen of the device is wrong.

The physics world should be absolutely agnostic about its graphics representation. And definitively it should have the same properties (size, mass, distance, ...) regardless of the screen.

I understand you don't want the scene to be smaller of the screen when the game runs on a iPad Pro instead of an iPhone 5 but you need to solve this problem in another way.

I suggest you to try another scaleMode like aspectFill (capitalized if you're on Xcode 7: AspectFill). This way the scene is zoomed and all your sprites will appear bigger.


Another point of view

In the comments below @Knight0fDragon pointed out some scenarios where you might actually want to make some properties of the Physics World depending on the UI. I suggest the reader of this answer to take a look at the comments below for a point of view different from mine.

Luca Angeletti
  • 58,465
  • 13
  • 121
  • 148
  • Thank you for your advice about the physics world ! My biggest concern about aspectFill is that it may crop the scene, and the issue with aspectFit is that I won't be able to fully fill the view with my scene in some cases... would you have any advice about that ? – Pop Flamingo Aug 29 '16 at 23:48
  • Yes, you are right. `aspectFill` will crop your scene if its proportions are different from the current device screen. One question: which devices do you want to support? – Luca Angeletti Aug 29 '16 at 23:50
  • iOS (all devices) and tvOS ! – Pop Flamingo Aug 29 '16 at 23:51
  • 2
    If you want to support every device and every orientation (and you don't want your game to run in letterbox on several devices) you'll need to crop part of your scene (so `aspectFill`). I don't know your game but with the information you provided there is not a better solution. Would it be a big deal? – Luca Angeletti Aug 29 '16 at 23:55
  • 1
    Ok, I understand. Thank you again for your advice about the physics world, I'll see what I can do about eh different scaleModes ! – Pop Flamingo Aug 29 '16 at 23:58
  • Take a look at this link: http://stackoverflow.com/questions/34864533/ios-universal-device-app-with-spritekit-how-to-scale-nodes-for-all-views – Nik Aug 30 '16 at 03:25
  • 1
    What he is doing is not "wrong" though, the physics world should know what its metrics are, and there are valid reasons to do this. (The OP is not doing it one of these ways) When dealing with ResizeFill, different scene sizes means different distances from edge to edge, and more force will be needed to stay consistent. if he expects an object to travel the same screen distance. – Knight0fDragon Aug 30 '16 at 13:14
  • @Knight0fDragon: the physics world should not change its properties depending on the screen size – Luca Angeletti Aug 30 '16 at 13:15
  • yes, it could, you just have tunnel vision. Let's say we have a ball that we want to travel from one side of the scene to the other in 1 second, and we do not want to use any scaling because we have pixel perfect graphics, and the scale mode ruins it, how do you propose to do that if the physics world does not know the size of its world – Knight0fDragon Aug 30 '16 at 13:21
  • @Knight0fDragon: IMHO the physics world should know nothing about its graphics representation (in theory it could be connected to a text only interface) About your example I think a physics body should not be teleported depending on the screen size because this way you are creating a game that behave differently on different screens. On an iPhone 5 (portrait) the ball will be teleported of X meters while on an iPad Pro (landscape) will be teleported of Y meters. This could generate inconsistency and (possibly) different levels of difficulties when the game runs on different devices. – Luca Angeletti Aug 30 '16 at 13:49
  • Again, you are living in tunnel vision, the physics world needs to know basic information like shapes and sizes, it does not need to know about things like textures. The game experience is determined by the developer, and is their wish to keep it consistent. A sacrifice in consistent game play may be worth the lush experience they created. I am saying it is not a good idea to declare something wrong just because you do not want to design this way. When somebody else sees this answer, they are going to take this answer literally, when in reality, it depends on the game and the experience. – Knight0fDragon Aug 30 '16 at 13:57
  • In a perfect world, the answer would be to change the representation of pixels per meter, but unfortunately from what I can tell, this can't happen – Knight0fDragon Aug 30 '16 at 14:01
  • 1
    @Knight0fDragon: In Cocos2D you could explicitly define the pixel per meter relation. However I think the `scaleMode` option in SpriteKit provides an higher level tool. – Luca Angeletti Aug 30 '16 at 14:03
  • 1
    this is not Cocos2D, so even mentioning it is irrelevant, unless your answer is to switch to it. scaleMode is the lazy mans approach. 9 / 10 times, it works great, because the pixels are so small it is tough to notice. There is that 1 / 10 time though when you have those amazing artists that know how to make use out of every pixel, that scaleMode becomes a problem – Knight0fDragon Aug 30 '16 at 14:06
  • 1
    @Knight0fDragon: I added a new section to my answer to represent your point of view. – Luca Angeletti Aug 30 '16 at 14:08
  • You both make great points. We are all victims of the insane desire to have the same experience on different devices with differing CPU/GPUs, aspect ratios, screen resolutions and pixel densities. These "cross-platform" and "Universal" mantras need to die. – Confused Oct 02 '16 at 15:09