AS3 air multiple resolutions, assets and layout iphone and ipad app - actionscript-3

I am building an app in AS3/Air and I would like to target both iPhone and iPad resolutions. I understand the different aspect ratios between iPhone and iPad however the app I am building currently has different layout and slightly different content to fit the different screen sizes. I currently have 2 versions of the app already built, one for iPhone the other for iPad. All assets have been created with the target platform in mind but now, I would like to combine the 2 apps into a single one.
I am thinking I will rename each each screen file to iphone_login, ipad_menu, ipad_settings etc and include them all in the same build. Then during startup, check what device the user is on and set iphone_ or ipad_ and also set the resolution at this time too.
I prefer not to have black edges going from iphone resolution to ipad so my questions are:
Is my approach a suitable one considering the outcome I would like?
How do I determine what device a user is on to show the correct files, assets and resolution?
I understand the app size will increase at least double by adding 2 sets of assets and 2 sets of code files but considering the differences in design layout and content I don't see another solution, apart from keeping 2 apps.
Thanks :)

What's the problem? iPad and iPhone have different resolution and dpi combination, check them and identify current platform.
Get view you need by class like this:
public static const PAGE1:String = "page1";
public static const PAGE2:String = "page2";
private static var PHONE_VIEW_NAME_2_CLASS:Dictionary = new Dictionary();
private static var TABLET_VIEW_NAME_2_CLASS:Dictionary = new Dictionary();
public class ViewProvider
{
{
PHONE_VIEW_NAME_2_CLASS[ViewProvider.PAGE1] = Page1PhoneView;
PHONE_VIEW_NAME_2_CLASS[ViewProvider.PAGE2] = Page2PhoneView;
TABLET_VIEW_NAME_2_CLASS[ViewProvider.PAGE1] = Page1TabletView;
TABLET_VIEW_NAME_2_CLASS[ViewProvider.PAGE2] = Page2TabletView;
}
public function ViewProvider()
{
}
public static function isTablet():Boolean {
...analyze Capabilities.screenResolutionY, Capabilities.screenResolutionX and Capabilities.screenDPI
}
public static function getViewClass(name:String):Class
{
return isTablet() ? TABLET_VIEW_NAME_2_CLASS[name] : PHONE_VIEW_NAME_2_CLASS[name];
}
}
And in your program
navigator.pushView(ViewProvider.getViewClass(ViewProvider.PAGE1))
All coordinated, paddings and another position numbers, font sizes etc correct with multiplier depending on runtime dpi by simular way...

I'm in the middle of a similar problem.
My solution is to have the images at the best resolution in a file pool, and then downscale them depending on the device when the app starts. You can do this also with non animated vector assets and put them into a bitmapData object.
Another option is to always have the asset pool with files at the maximum resolution needed loaded in the memory, and downscale them at runtime when they are needed. This works well if you will be using some asset in different places at different sizes, for example an icon.
As for the code, you should find a way to separate the code that manages data, the codes that manages the logic, and the code that "paints" the UI. This way you will be able to reuse most of the code in both versions, but only change the code that "paints" the UI. Check the MVC pattern for more info.

Related

Libgdx, Setting the full screen resolution during runtime causes application to render at the wrong size

I am only using the desktop Application, no mobile.
I am experimenting with letting the user set the screen resolution during run time. I give him the Display Modes available and he applies one. This part actually works. The problem occurs when i save this mode and try to set this display mode the next time they launch the game.
I am using preferences to store the mode the user selected. I am unable to access preferences before the Create method in my Game class, or in the DesktopLauncher Object, where you normally set up the config file and pass it into the application. So my DesktopLauncher looks like this.
val config = Lwjgl3ApplicationConfiguration()
config.setFullscreenMode(Lwjgl3ApplicationConfiguration.getDisplayMode())
Lwjgl3Application(MainGame(), config)
I use the current screen resolution on the creation of the application. Then in my Create method in my MainGame class i get the mode they set from preferences and i set it like so...
override fun create() {
var modes = Gdx.graphics.displayModes.toList()
val mode = Gdx.graphics.displayMode
val preference: Preferences = Gdx.app.getPreferences("screenPreference")
val screenWidth = preference.getInteger("width", mode.width)
val screenHeight = preference.getInteger("height", mode.height)
val refreshRate = preference.getInteger("refreshRate", mode.refreshRate)
modes = modes.filter { it.width == screenWidth }
modes = modes.filter { it.height == screenHeight }
modes = modes.filter { it.refreshRate == refreshRate }
if (modes.isNotEmpty()) {
Gdx.graphics.setFullscreenMode(modes[0])
}
....
}
To summarize i get the list of modes, i pull from preferences what was set last, and i filter the list according to what was in preferences. This should leave one item left in the list and i apply it. If for some reason the list is empty, then i don't set it, or there is no preference set i just apply the current mode again.
This is where the weird stuff happens. I have checked all the numbers when creating my screens and cameras, and they are all correct. I do receive the correct resolution, but the application doesn't render correctly. Below are a couple examples of what happens.
In the first image you see the bounds of the application to the screen. My application only renders in the bottom corner, and the rest is black. What happened to achieve this effect is i started the application with a smaller resolution than my native resolution, so 1280x1024, then in my create method i set the application full screen mode to 1920x1080 before building the rest of my application. I have checked my cameras and my viewports, and they all have the resolution 1920x1080, but the image is not filling the entire screen.
And a second.
This one is what happens when i reverse the settings. So i start at native resolution 1920x1080, and in my create method i set it to 1280x1024, again before creating the rest of my application. This gives me black bars on both sides of the image like id expect, but the application is HUGE, and only a portion of it fits in the window, the rest goes out of bounds, as depicted by the dotted lines.
It will remain like this the entire time, unless i change the resolution while the application is running, it will then correct itself for the rest of the applications life.
I am confounded by this effect i am getting, and am looking for an answer as to why, or how to fix it.
I found the issue that was causing the image to render incorrectly. I was setting the display mode in the create() function in my main game class. This function is not run on the rendering thread, and you do not want to use Gdx.graphics on anything other than the rendering thread, as described in the libgdx wiki https://github.com/libgdx/libgdx/wiki/Threading
There is a function where you can pass in a lambda to be run on the rendering thread.
Gdx.app.postRunnable {
Gdx.graphics.setFullscreenMode(Gdx.graphics.getDisplayMode(modes[0]))
}
After passing that into postRunnable the game renders correctly on launch.

How do I keep the AS3 Camera class from adding black bars?

Under certain conditions, picking a resolution with Camera.setMode() adds black bars to the camera input, "letterboxing" it. I understand that setMode() uses some kind of hidden algorithm that picks a resolution from one of your camera's available resolutions and then crops it to fit your desired dimensions, but apparently sometimes it would rather add black bars than crop it.
This behavior is dependent on what camera I'm using. Some cameras seem to always crop and never letterbox. This may be related to what available resolutions they have. But what's really strange is that the letterboxing only ever happens when I try it in a Flash Player ActiveX control, like in Internet Explorer. It doesn't happen when I try the exact same SWF in Flash Player Projector or Google Chrome. This seems to imply that different Flash Player versions use a different algorithm to select and fit a resolution to the desired dimensions.
Here's a very simple example of code that's been creating this problem for me. In this case I'm providing a 4x3 resolution to setMode(), which means it must be selecting a 16x9 resolution even though 640x480 is one of the camera's available resolutions.
public class Flashcam extends Sprite
{
private var _camera:Camera = Camera.getCamera("0");
public var _video:Video;
private var _width:int = 640;
private var _height:int = 480;
public function Flashcam()
{
_camera.setMode(_width, _height, 15);
_video = new Video(_camera.width, _camera.height);
addChild(_video);
_video.attachCamera(_camera);
}
}
Is there any way to stop Camera from letterboxing its input? If not, is there some way to tell whether or not it's being letterboxed and which camera resolution has been automatically selected so that I can write my own code to account for it?

Where has support for orientation gone in Universal Apps?

I'm working on a universal app, and I need for one page within this app to use landscape orientation (for taking a photo), whilst the majority of the app is primarily portrait orientation.
How do I tell the OS and the designer this, as the SupportedOrientation and Orientation properties from PhoneApplicationPage from the Silverlight toolkit, don't appear to exist on Page
If you want to make a different orientation on the Page, then I've been able to make it like this - by setting Page's orientation in its constructor:
public MainPage()
{
this.InitializeComponent();
DisplayInformation.AutoRotationPreferences = DisplayOrientations.Portrait;
}
public Page1()
{
this.InitializeComponent();
DisplayInformation.AutoRotationPreferences = DisplayOrientations.Landscape;
}
Here is simple example with three Pages - each with different orientation.

Resize Screen based on Device Resolution Monogame Windows Phone 8

I develop game using monogame framework.
code of game itself is converted from XNA code, which i coded previously before.
I develop game asset (background, etc) for 800*480 resolution. problem appear when i try run it in different device resolution (emulator 720p).
How to resize it actually?
I already add this code, but nothing happen
public Game1()
{
_graphics = new GraphicsDeviceManager(this);
this.Windows.ClientSizeChanged += Window_ClientSizeChanged;
}
void Window_ClientSizeChanged(object sender, EventArgs e)
{
int currentWidth = this.Window.ClientBounds.Width;
int currentHeight = this.Windows.ClientBounds.Height;
}
that code only return 0 value for both currentWidth and currentHeight;
i also follow this code
this.Window.ClientSizeChanged += new EventHandler<EventArgs>(Window_ClientSizeChanged);
void Window_ClientSizeChanged(object sender, EventArgs e)
{
graphics.PreferredBackBufferWidth = Window.ClientBounds.Width;
graphics.PreferredBackBufferHeight = Window.ClientBounds.Height;
graphics.ApplyChanges();
}
But it has similar result. Nothing happen for resize.
Please point me a way to fix this. Because my game only be able to run in 480*800 resolution. In other resolution, it will display some space instead.
Thanks before.
How I handled it for my game was, something that I think was a simple solution.
You need two things: design dimensions, and device dimensions. Sounds like you coded it for 800 * 480 so those are your design dimensions.
So you need to get the actual device width and height first. I do this in the App.xaml.cs because if you want to reuse your code for another platform (we did) you will want to do their specific way to get screen dimensions.
So in App.xaml.cs you can do this:
private void Application_Launching(object sender, LaunchingEventArgs e)
{
// Get device viewport.
double scaleFactor = (double)App.Current.Host.Content.ScaleFactor / 100f;
double width = App.Current.Host.Content.ActualWidth * scaleFactor;
double height = App.Current.Host.Content.ActualHeight * scaleFactor;
ResolutionSystem.SetResolutionAndScale((float)width, (float)height);
}
Now what you are doing is getting the devices scale factor (with 1.0 being 800 * 480 for WP8). You then get the ActualWidth and ActualHeight (which are always 800 and 480) and then multiply by the scaling factor. So there you have your device dimensions now, and you're not wiring into the game logic itself (unless your logic needed to be based off of the possibility of a mid game landscape to portrait switch).
So then what we do is set the game's scaling Matrix. There's a lot of other stuff I had to do with scaling and render targets due to shaders and UI but I'll keep it simple. Essentially you want to now get a scaling matrix for your sprite batch that you run the gameplay on. This means you do everything in your desired design viewport bounds then scale it to the desired size after the fact (you may want to consider redoing your assets for a higher resolution like WXGA or even 1080p if you can).
So to get our scale matrix in our ResolutionSystem.cs class we call:
public static void SetResolutionAndScale(float deviceWidth, float deviceHeight)
{
ScaleMatrix = Matrix.CreateScale(DeviceWidth / DesignWidth,
DeviceHeight / DesignHeight,
1f);
}
This function for us does a lot more but I trimmed it all out. So you should now have a scale matrix for you to store however you'd like.
Now in your draw call which can be done in numerous ways you simple include that scale matrix as the Matrix transformMatrix parameter in the SpriteBatch.Begin call.
So something like this:
spriteBatch.Begin(SpriteSortMode.FrontToBack, null, null, null, null, null, ResolutionSystem.ScaleMatrix);
And you should now have something that works. You can check out my game SkyFehl in the Windows Phone Store and test it out. It was used with design parameters of 1280 * 768. Porting over to iOS was relatively easy using this method (I won't link it in case that's frowned on). Hopefully I made some form of sense.
Making Resolution independent games, here is a blog which will give you a step by step procedure to achieve it.
http://www.craftworkgames.com/blog/monogame-code-snippets/monogame-resolution-independence/

Set ApplicationDPI in AS3 Mobile application

I developing an application in Flash Builder with AS3 only (no flex stuff). In flex it is possible to set the application's dpi by the following code:
<s:ViewNavigatorApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" applicationDPI="320">
But I using only AS3. I have read that it is not possible to change the application's DPI in run-time (with AS3), but how can I set this in project settings, compiler settings or is there another way to do it?
Also, what is the default application's DPI setting?
Ask it here because can't find it on the net (only flex based solutions).
The DPI on mobile is set by the hardware, it is entirely dependent on the phone and screen. When you set the applicationDPI in a Flex mobile you're telling Flex to automatically scale your assets.
Automatic scaling. Developers can choose to specify a target DPI for their application by setting the applicationDPI property on the application. When this is explicitly set, developers should set up their skins and layout as if they were running on a device of the given DPI. At runtime, if the device has a different DPI from the specified target DPI, Flex will automatically scale the entire application to preserve the approximate physical size of the application and its controls. For example, if an application is targeted at 160 DPI, it will automatically scale by 1.5x on a 240 DPI device. If you choose not to use this feature, you'll need to make sure your custom skins and view layouts adapt properly to different pixel densities at runtime.
Source
In an AS3 mobile project you're going to need to handle this yourself.
You can get the current DPI using Capabilities.screenDPI but I think what you may be after is a ratio to scale your assets by. One way to do this would be to start with the original game width.
private static const WIDTH:Number = 1024;
You can then get a ratio using
var ratio:Number = stage.fullScreenWidth / WIDTH;
And apply this to your assets
myBitmap.scaleX = myBitmap.scaleY = ratio;
Now this isn't going to take the rotation of the device into account, so fullScreenWidth/Height may be flipped. To check for that you're going to need to do something like this
if (stage.fullScreenWidth > stage.fullScreenHeight){
//portrait
} else {
//landscape
}
Hopefully this helps