Using different arrays for different iPhones - ios

I have each of those images set in an array that calls out to Firebase for the image. I was wondering if I could have a separate array to call from for different sized iPhones because the iPhone X screen size cuts some of the text off. I want to resize the images for just the iPhone X. Is there a way to see what device the user has and then if it is the iPhone X it would show array1, and if was anything else it would show array2. I have tried looking at this post however what they did is too complicated and not what I am looking for. What I am trying to do I know is very simple. I am just not sure the direct code for it. I just need to know if it's an iPhone X then switch to array1, otherwise I don't care which device it is wether it's an iPad with cellular or wifi. Just check if the device is an iPhone X otherwise just keep everything the same.

I don't think that you should know about a model of a iPhone.
You should know about a screen/view ratio (width / height).
Ratio is a main reason to decide what images you should use.
You can find screen ratio with bounds property, for example:
if (CGRectGetWidth([UIScreen mainScreen].bounds) / CGRectGetHeight([UIScreen mainScreen].bounds) <= GOOD_VALUE){
//use one
}
else
{
//use other
}
Also screen has a property scale, that will be very useful for you.

Related

Making a ruler functionality within the app, but different screen sizes?

I'm working on a project which particularly in this ViewController, I have set up a scale as a UIImageView and it needs to react on touch events based on that scale and to produce some output. However, my question is, how to implement accuracy for all of the different devices? I was thinking to try with if else statements for every single device (iPhone 4,5,6) and assign the properties based on those conditions. But that would be like dirty coding, or no? Is there any other method for this type of functionality? I need you to give me some opinions or tips just to put me on the right track. Thanks
You can use UIScreen's scale property to determine if the device has a retina screen (#2x or #3x), which will help to some extent. At present, every iPhone has the same number of points per inch (163), with differing numbers of pixels per inch depending on the device. The iPads are a different matter, though, as the iPad Mini has the same point density as an iPhone, but the 9.7" iPad and the iPad Pro have a lower density. I think for the iPads you'll need to detect the specific device to be able to figure out the physical screen size.

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!
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.
There's no easy way to do what you want. One approach would be to use a fixed screen size on your devices. The iPhone 5 all the way up to iPhone 6+ all use a 16:9 aspect ratio for their screens. Whereas the iPad and iPhones 4s and earlier, all use a 4:3 screen aspect ratio.
Before presenting your GameScene, you can determine the screen's aspect ratio and then set a fixed view size like this for 16:9:
GameScene *startGame = [[GameScene alloc] initWithSize:CGSizeMake(736, 414)];
startGame.scaleMode = SKSceneScaleModeAspectFit;
or this for 4:3
GameScene *startGame = [[GameScene alloc] initWithSize:CGSizeMake(1024, 768)];
startGame.scaleMode = SKSceneScaleModeAspectFit;
The exact values really do not matter, only the ratios.
Knowing the exact screen size will allow you to place objects in more precise manner regardless of iPhone 5 screen or 6+ screen.
Using image assets, you can also specify iPad versions of an image.
However there's not really a way around adding some extra logic to your app, branching depending on whether or not your running on the iPad, and adjusting the position manually.
We could discuss how to best incorporate that though: I'm not a fan of this "if I'm not this device" checks all throughout the code. Create an abstract superclass and two subclasses, each handling layout (or whatever you may want to call it) for one interface idiom. You will the only need to check once (when instantiating these) and polymorphism will take care of the rest.
You can use a software as PaintCode to dynamically generate texture perfectly sized to your need.
All you have to do is to define the frame' dimensions for each of your devices.

How to make my Gideros game adaptable to all screen sizes?

I am quite new to Gideros and game development as well.
I am trying to build a game, it looked fine with the Gideros player, but when I tried with an Android phone, the background was way too small. I changed its properties to autoscaling so as to fit in with the width. The background now fits in the width, but other objects seem to go to absurd locations.
Though I was using W = application:getDeviceWidth(), H = application:getDeviceHeight(), and while setting up the location, used W/2 and H/2 instead of hardcoding it.
However, this object that seems to shift to rightmost bottom end(in landscape left mode) was right at its center if I do not apply fit width property.
What can I do to fix it?
You should use W = application:getContentWidth() , H = application:getContentHeight() which would return logical dimensions that are used when in scaling mode.
Basically it all brings down to these points:
1) Choose the scaling mode that is proper for your game (Letterbox being most popular)
2) Choose logical dimensions for your game and create all the graphics for logical dimensions you set in the project properties (recommended 480x800 or 640x960)
3) Create backgrounds a little more bigger than logical dimensions to cover whitespaces on devices with different ratios
4) Use absolute positioning (http://appcodingeasy.com/Gideros-Mobile/Ignore-Automatic-Screen-Scaling-when-positioning-objects) for objects that need to stick to sides of the screen as on screen buttons for example
5) (Optionally) prepare bigger graphics in in some fixed ratio coefficient and use Automatic Image Resoltuion feature to automatically load them for bigger devices
More information available here:
http://members.giderosmobile.com/knowledgebase.php?action=displayarticle&id=79
Addition: (Difference between device and logical dimensions)
Device dimensions is exactly what device has. Meaning on an iPhone 3GS it will return width as 320
But logical dimensions are exactly what you set in your project properties. No matter what resolution you have, the logical dimensions will always be the same. They basically will be scaled based on the scale mode you choose.
Here are more specifics on that topic: http://appcodingeasy.com/Gideros-Mobile/Difference-between-content-logical-and-device-dimensions-in-Gideros-Mobile
So if you are developing only for one specific resolution, you can use Device dimensions, otherwise it is suggested to use Logical dimensions with the scale mode you find suitable.

Adaptive Positioning Based on iOS Device

I made an iPhone game a few months ago, and am now trying to port it as a universal app to both the iPad and iPhone 5 with Cocos2D. I was wondering if there was a simple-ish way to determine where an object should be placed based on the device running the game.
I could use if statements to figure out which device the game is running on, so when I get the correct sized images for the device I could have separate positions for each object, but it seems like there would be a maths formula which would allow me to use a lot less code. Obviously something like a full screen background is very simple, because it just needs to be centred with:
[background setPosition:CGPointMake(screenSize.width/2,screenSize.height/2)];
I haven't a clue how to adapt a button that would be X = 144 & Y = 330 on the old 3.5inch, 640 by 960 resolution iPhone to an iPad or iPhone 5 resolution.
I'm willing to use a more recent version of iOS if it will make my life easier, but because I'm not using any of Apple's objects I don't know if that is possible.
Maybe this isn't even possible because the button will be different sizes for the iPhone and iPad version, but I thought I would ask.
yeah, i am usually facing the same problem,
but if it is just a static objects placement
i would have relative coordinates instead of absolute for every object
and then use screen sizes to place them correctly
so you might want to use a function like:
-(CGPoint) relativeToScreen:(CGPoint) p {
return ccp(screenSize.width * p.x, screenSize.height * p.y)
}
where 0.0 <= p.x =< 1.0 and the same for p.y
and don't forget about your anchorPoint, because the node position is based on it as well
and i hope you have discovered that cocos2d already does image choosing instead of you,
you just have to set right suffixes for your images: -hd, -ipad, -ipadhd
For iphone5 resolution, I position hud buttons relative to the screen dimensions. Very similar to what you are doing for the background. So for example, a pause button I want in the top left I would position like this:
[pauseButton setPosition:CGPointMake(0.0f + 30.0f, screenSize.height - 50.0f)];
For ipad it gets really tricky. The lazy way which I have implemented is to play around with the content scale factor and zoom everything up and have "dead" borders to compensate for the ipad's screen ratio. Not the best, but at least you can re-use all the same assets for the ipad.

Does CGContextConvertRectToDeviceSpace work properly on retina devices?

I'm building an iOS-based core text application (iOS 5, iPad), and have a view within which I'm performing some typographic calculations (in drawRect).
I've noticed that when I use CGContextConvertRectToDeviceSpace, the result I get on a retina device is double that of a non-retina device. It's my understanding that within drawRect there is an implicit transform applied that should hide any retina/non-retina device differences, so I'm confused why I should see any difference at all.
More specifically, I'm trying to calculate the location in user coords of a given CTLine in user space coords. I first use CTLineGetTypographicBounds for my line, and use those values in CGContextConvertRectToDeviceSpace to get a rect... but the rect I get back has double the width and height on a retina device versus a non-retina one. Is there something I'm missing?
I've noticed that when I use CGContextConvertRectToDeviceSpace, the result I get on a retina device is double that of a non-retina device.
Sounds normal to me. "Device space" represents the actual pixels on the output device, which in this case is the retina display. It's normally scaled 2x larger than the CGContext's user space coordinate system.
Normally it's rare to need to convert to or from device space -- you would only do it if you absolutely positively needed to align your drawing to real pixels.
What are you trying to accomplish by using CGContextConvertRectToDeviceSpace? There may be an alternative.

Resources