I have a kha app that runs perfecly on an iPad2 (1024/768px).
When I run the same project on a later iPad Mini with 2048/1516. My coordinates are all half the size, which kinda makes sense.
So when I double all the sizes of my objects and GFX it will work on the iPad mini, but will be too big for iPad2.
I looked into a backbuffer and a renderTarget as explained here:
https://www.youtube.com/watch?v=OV1PTo5XSCA
There is also the windowSize option in khafile, which seems to do nothing.
Surface x and y coodinates always seem to come in in real screen coodrdinates of the device.
What is the best way to write a resolution independent app?
Perfect would be a way that is either retina or non-retina, depending on the device, where the code stays the same.
According to https://github.com/Kode/Kha/wiki/Screen-Size-and-Scaling there's automated scaling for some targets. If you need other targets you have to manually scale everything to fit the screen.
The page mentions using this class for the task: https://github.com/Kode/Kha/blob/master/Sources/kha/Scaler.hx
Also you could take a look at how Wyngine does it:
https://github.com/laxa88/wyngine/search?utf8=%E2%9C%93&q=scale & https://github.com/laxa88/wyngine/blob/master/Wyngine.hx
You replied (to my comment) that scaling wasn't enough. So far it was enough for all of my games with the right display settings, but if you really need retina sized graphics you always have the option of using multiple graphics sets. Eg:
a set for retina resultion (eg iPad 3)
a default resolution (eg iPad 2) set at half retina size
a low res set for cheap android devices?
At startup of your app you check the screen size. You use that to choose the internal game size and the graphics set that fits the actual screen resolution the best. The internal game size as well as all X/Y positions for the selected graphics set can be calculated by applying the graphics sets scale factor to the raw base values.
Finally you use Scale.scale() to scale your game from the internal game size to fit devices like the iPad pro 12" and the wide variety of Android devices.
That approach is common with a lot of game engines, google should find you links like https://v-play.net/doc/vplay-different-screen-sizes/ that also explain screen ratios and how those can be handled.
Related
Note: Yes I know there are other ways of doing buttons in Android, but this is just an example to demonstrate my issue (the actuall buttons are far far more complex). So please don't reply in offering other solutions for buttons in Android, I am looking for a solution with PaintCode...
I have been using PaintCode for drawing custom buttons for years in iOS, it works brilliantly. I want to do the same for android and have the following issue:
In PaintCode I draw a button which is basically a rounded rectangle with a radius of 20 points.
I draw a frame around and then setting the correct resizing behaviour using the springs (see screenshot).
The result is that whatever the size of the button is going to be (= the frame) the corners will always be nicely rounded with 20 points. Basically a nicely resizable button.
This works very well on iOS but on android, the radius is 20 pixels not points, resulting in a far to small radius (now with the high res devices).
Or in general all drawings that I make in PaintCode when drawn using the draw method generated by PaintCode are to small.
It seams that the generated drawing code does not take into account the scale of the device (as it does on iOS).
Looking at https://www.paintcodeapp.com/documentation/android section "scale" PaintCode suggest to play with the density metric in android to perform scaling.
This does work, but makes the generated drawing fuzzy, I guess this is because we are drawing in lower resolution due to the scaling. So its not a viable solution.
class Button1 #JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : Button(context, attrs, defStyleAttr) {
var frame = RectF()
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
val displayDensity = resources.displayMetrics.density
canvas?.scale(displayDensity, displayDensity)
frame.set(0f,0f,width.toFloat()/displayDensity,height.toFloat()/displayDensity)
StyleKitName.drawButton1(canvas, frame)
}
}
Any suggestions to solve this? Is this a bug in PaintCode?
I'm the developer. Sorry about the long answer.
TLDR: handle the scaling yourself, for example the way you do. Switch layerType of your View to software to avoid blurry results of scale.
First I totally understand the confusion, for iOS it just works and in Android you have to fiddle around with some scales. It would make much more sense if it just worked the same I would love that and also would other PaintCode users. Yet it’s not a bug. The problem is difference between UIKit and android.graphic.
In UIKit the distances are measured in points. That means if you draw a circle with diameter 40 points, it should be more-less the same size on various iOS devices. PaintCode adopted this convention and all the numbers you see in PaintCode's user interface like position of shapes, stroke width or radius - everything is in points. The drawing code generated by PaintCode is not only resolution independent (i.e. you can resize/scale it and it keeps the sharpness), but also display-density independent (renders about the same size on retina display, regular display and retina HD display). And there isn’t anything special about the code. It looks like this:
NSBezierPath* rectanglePath = [NSBezierPath bezierPathWithRect: NSMakeRect(0, 0, 100, 50)];
[NSColor.grayColor setFill];
[rectanglePath fill];
So the display scaling is handled by UIKit. Also the implicit scale depends on the context. If you call the drawing code within drawRect: of some UIView subclass, it takes the display-density, but if you are drawing inside a custom UIImage, it takes the density of that image. Magic.
Then we added support for Android. All the measures in android.graphic are represented in pixels. Android doesn’t do any of UIKit's “display density” magic. Also there isn’t a good way to find out what the density is in the scope of drawing code. You need access to resources for that. So we could add that as a parameter to all the drawing methods. But what if you are not going to publish the drawing to the display but you are rather creating an image (that you are going to send to your friend or whatever)? Then you don’t want display density, but image density.
OK so if adding a parameter, we shouldn’t add resources, but the density itself as a float and generate the scaling inside every drawing method. Now what if you don’t really care about the density? What if all you care about is that your drawing fills some rectangle and have the best resolution possible? Actually I think that that is usually the case. Having so many different display resolutions and display densities makes the “element of one physical size fits all” approach pretty minor in my opinion. So in most cases the density parameter would be extraneous. We decided to leave the decision of how the scale should be handled to user.
Now for the fuzziness of the scaled drawing. That’s another difference between UIKit and android.graphics. All developers should understand that CoreGraphics isn’t very fast when it comes to rendering large scenes with multiple objects. If you are programming performance sensitive apps, you should probably consider using SpriteKit or Metal. The benefit of this is that you are not restricted in what you can do in CoreGraphics and you will almost always get very accurate results. Scaling is one such example. You can apply enormous scale and the result is still crisp. If you want more HW acceleration, use a different API and handle the restrictions yourself (like how large textures you can fit in your GPU).
Android took other path. Their android.graphic api can work in two modes - without HW acceleration (they call it software) or with HW acceleration (they call it hardware). It’s still the same API, but one of the hardware modes has some significant restrictions. This includes scale, blur (hence shadows), some blend modes and more.
https://developer.android.com/guide/topics/graphics/hardware-accel.html#unsupported
And they decided that every view will use the hardware mode by default if target API level >= 14. You can of course turn it off and magically your scaled button will be nice and sharp.
We mention that you need to turn off hardware acceleration in our documentation page section “Type of Layer” https://www.paintcodeapp.com/documentation/android
And it’s also in Android documentation https://developer.android.com/guide/topics/graphics/hardware-accel.html#controlling
I remember having a similar issue and, after talking to PaintCode support guys, we came up with a function to convert DP to PX. So, say, in Android those 20 points will be converted to "whatever" pixels -- considering the different display densities.
Long story short, this is the summary of PaintCode support answer:
The fact that Android doesn't support device independent pixels in its
drawing API is the reason for the different behaviour of iOS and
Android. When using UIKit, the coordinates entered are in Points, so
it takes care of display density itself. When generating bitmap in
Android the display density needs to be taken into account.
This is the function I created:
private static PointF convertDPtoPX(float widthDP, float heightDP) {
Context context = getAppContext();
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
float widthPX = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, widthDP, metrics);
float heightPX = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, heightDP, metrics);
return new PointF(widthPX, heightPX);
}
Here is an example on how to call it:
Bitmap myButton = StyleKit.imageOfMyButton(convertDPtoPX(widthDP, heightDP));
Of course in this example I'm using a bitmap of myButton (StyleKit.imageOfMyButton) due to the specifics of the project. You'd need to adjust the example to fit your needs.
You could, for instance, make that radius an external parameter in PaintCode, making each platform responsible for providing its value. Like:
// In Android, convert 20DP to 20PX based on the above function.
// In iOS, just pass 20.
StyleKitName.drawButton1(canvas, frame, radius)
I hope this helps.
I'm working on my first winjs app for windows 8.1. So I'm a newbie in this topic, so please forgive me if I ask something obvious.
My problem is the resolution of the target machine (DELL Latitude E7440 with touch screen) is 1920x1080, but when I run the app, it runs in 1370x771. Which is a bit confusing for me.
So my question is, how can I tell the app to run in the same resolution as the OS runs.
Strange thing I discovered: If I set the "Change the size of apps text, and other items on the screen (...)" settings from larger to default in the display settings then suddenly my app runs in the desired full hd resolution. But I don't wanna depend on this setting.
I know I could use ViewBox control, but all of the graphics and everything is designed for full hd resolution, so ViewBox would simply scale it down, this solution sounds a bit ridiculous considering I have a full hd laptop, and full hd design as well...
This app is only for this particular machine, so I don't have to deal with different resolutions.
Any tip/suggestion is highly appreciated.
Windows abstracts the physical device resolution specifically so you don't have to think about scaling issues. Just do your work against the resolution that's reported from the API. This is done because a high pixel density display can result in UI that's too small to be usable, e.g. touch targets that get too small for fingers. Most of the time, then, a 1920x1080 display that's on a smaller physical device (e.g. 13" or smaller screens) gets a 140% scaling factor applied, hence it reports something closer to 1366x768.
Generally speaking, then, if you write responsive CSS for layout then you really don't need to worry about scaling at all with the exception of providing raster graphics that can work at the 100%, 140%, and 180% scaling plateaus (and 240% on Windows Phone 8.1).
For more details refer to my free ebook from Microsoft Press, Programming Windows Store Apps with HTML, CSS, and JavaScript, 2nd Edition, which you can also read (free) within the Microsoft Press Guided Tour app in the Store. Page 42 (Chapter 1) has a short overview on Views and Resolution Scaling; the Branding Your App section on page 113 talks about sizes of logo/splashscreen images for different resolutions, and then Chapter 8, "Layout and Views" (starting on page 421) goes into all the details, especially "Screen Resolution, Pixel Density, and Scaling" on page 437.
Now that the new Macbook Pro is coming out with a Retina Display, there are a lot of resources out there on how to make Mac apps and now even websites "Retina Display Friendly". Even Google is updating Chrome for Retina Display...
Why is this necessary at all? From what I understand, Retina Display is just a higher resolution screen. Right?
I thought when you develop gui's for desktop software and develop websites, you are developing something that is supposed to work and scale properly with virtually any resolution... When you resize an app's window, or display it on a higher or lower resolution display, it is supposed to scale and display properly.
So why are these people coming out with guides on how to make something look good on a Retina Display? Shouldn't it already look fine by default? Is there something about Retina Display that I'm not understanding?
And for the record, I'm not talking about iPhone 4 Retina Display. Most iOS dev's make their apps with fixed position elements since they know the screen's won't change size/shape. So I understand the importance of developing an app to look good on the iPhone 4/s vs 3g/s.
With the Retina display apps don't actually scale like they're being resized, all the controls are resized to be twice as big. If an app would be scaled normally, not by scaling all the controls, etc. you wouldn't see anything, because everything would be too small. It's the same difference between a Retina and a lower-resolution display as on the iPhone 3GS / iPhone 4.
An example:
These images are actually the same size, just the pixel densities differ.
And here's how it looks not properly scaled (using some app to disable proper scaling):
http://cloudmancer.com/images/trueretina.jpg
I thought when you develop gui's for desktop software and develop websites, you are developing something that is supposed to work and scale properly with virtually any resolution... When you resize an app's window, or display it on a higher or lower resolution display, it is supposed to scale and display properly (StackOverflow, for example, uses a 960px-wide container).
From a web developer standpoint, you are often asked to develop fixed-width websites (ranging from normally 940 to 1000 pixels wide), and they don't get to scale at all. There are a lot of websites like this and many apps just aren't designed to increase in size.
Also, apps that do grow in size usually expect that a bigger resolution also means a bigger screen, so they simply stretch the main application panels and are done with it.
Now, consider static elements, like a 150x50 button that says 'Click me'. This button is not intended to become bigger and is perfectly acceptable on a regular 1440x900 display. Now the retina screen comes in with its 2580x1800 resolution. The app sees the resolution change but it thinks "Hey, that user must have a huge screen" so it keeps the button the same size.
The problem that now occurs is that the button, because both resolutions apply to the same 13" screen, is now appearing to be a fraction of the size of the original button. Depending on your user vision, he might not be able to read the text on it, and might have a hard time clicking it, depending on the mouse settings.
To fix that problem, Apple and Microsoft used two different solutions:
Microsoft decided to tell the app the display had a 2580x1800 resolutions, but that the user wanted to have everything scaled to 200 dpi. This means that, if an app does not follow the guidelines, it will look smaller. Many apps simply ignore the DPI settings (though this might change with Windows 8);
Apple decided to report to apps that the resolution of the monitor was 1440x900, but that it could display higher-resolution elements if asked to; This means that apps existing before the new retina settings will appear to be the same size as before for the end-user (with added benefits like crisper text if they use the default Apple APIs), but that they can decide to provide high-DPI images that will look much better on the display.
Both solutions requires apps to be aware that the display is high-DPI ('retina'), but the way Apple handled it means the static websites and apps mentioned earlier will keep looking just fine, except they wont have super-crisp, high-resolution images to use. And, to opt-in to the retina features, they have to provide 200x200 images for a 100x100 canvas, for example, and Apple will take care of the rest.
What is the recommended way of supporting multiple screen resolutions/aspect ratios across devices like iPad, iPhone, Windows Phones, and Android phones/tablets? Should I simply #if/#else specific code for each device? I don't know how well this would work. Especially for Android phones/tablets which come in all different sizes. Any pointers would be greatly appreciated.
Here is what we are doing for our game:
All menu or ui elements are positioned based on the screen size (we implement Horizontal and Vertical alignment)
All levels scroll, so on some devices you just see less of level of the level at a time
Our levels also zoom in on smaller devices where needed
Design fixed levels (ones that don't scroll) so that a bit of unused space is on the edges of the screen. This way it can get cropped on some devices no problem.
Make 3 sizes of images: small (3GS), medium (iPhone 4, Android, WP7, iPad), large iPad3
Position sprites/ui elements based on an images size
Take advantage of the #2x naming scheme for images
We made an iPhone-only and iPad-only version of the app, this helps in only having to put 2 sets of images in each app
Using the screen size for positioning is your best bet. Being able to center or dock to the bottom or right of the screen is also very helpful in general.
I could tell more, but I can't reveal specifics about our game yet.
I'm making an app but I don't wish to support retina display. The bad thing is that my app looks all pixelated. It's possible to deactivate the retina display feature ? So that my texture's proportions won't be doubled.
The scale property of UIScreen is read only and it's value is 2.0 in iphone 4, I would like it to be 1.0, so that my graphics in the iphone 4 looks exactly the same as older devices, without pixels.
The scale property of UIScreen is telling you that there are physically twice as many pixels in each direction on the retina screen.
You should not need to do anything special to get the app to appear the same on the retina display.
It will look slightly better if you provide #2x images though, and it may look more pixelated next to apps that are running at full resolution on the same device if the #2x images are not present.