Set Display resolution limit in unity - android

So I released a game a few months ago.
I run a lot of test on devices I add at home (galaxy note 2, galaxy tab pro, wiko), and the game runs smoothly on these devices.
But last day, I run my game on an LG G3 device, and there are a lot of FPS drops.
I think it's because the game runs with the native display resolution of the screen (2560 x 1440).
Is it possible to create a script, that when it detects a display resolution upper than FullHD (like for the LG G3), it displays the game in a lower resolution?
I think it would stop the FPS drops.

Adjust same Camera Resolution on every Device.
If your Game is in portrait mode then use 720*1280 resolution and if using landscape mode the use 960*640 , your game will run perfect on every device.
Attach Script to your camera
Change Values targetaspect
using UnityEngine;
using System.Collections;
public class CameraResolution : MonoBehaviour {
void Start () {
// set the desired aspect ratio (the values in this example are
// hard-coded for 16:9, but you could make them into public
// variables instead so you can set them at design time)
float targetaspect = 720.0f / 1280.0f;
// determine the game window's current aspect ratio
float windowaspect = (float)Screen.width / (float)Screen.height;
// current viewport height should be scaled by this amount
float scaleheight = windowaspect / targetaspect;
// obtain camera component so we can modify its viewport
Camera camera = GetComponent<Camera> ();
// if scaled height is less than current height, add letterbox
if (scaleheight < 1.0f) {
Rect rect = camera.rect;
rect.width = 1.0f;
rect.height = scaleheight;
rect.x = 0;
rect.y = (1.0f - scaleheight) / 2.0f;
camera.rect = rect;
} else { // add pillarbox
float scalewidth = 1.0f / scaleheight;
Rect rect = camera.rect;
rect.width = scalewidth;
rect.height = 1.0f;
rect.x = (1.0f - scalewidth) / 2.0f;
rect.y = 0;
camera.rect = rect;
}
}
}

is not that easy (with a good quality result).
Basically, you can use asset bundle system for it and have double of your graphics in SD and HD formats. Unity supports it, it calls variants. Please find more information about Asset Bundles here:
https://unity3d.com/learn/tutorials/topics/scripting/assetbundles-and-assetbundle-manager
Detection of screen resolution is easy. You can use Screen.width and Screen.height for it.
I know Screen class has a method SetResolution and this might do a thing for you without using an Asset Bundle system. I have never use it on my own.
Here is more about Screen class:
https://docs.unity3d.com/ScriptReference/Screen.html
and concrete SetResolution method:
https://docs.unity3d.com/ScriptReference/Screen.SetResolution.html
You can use Camera.aspect to get an aspect ratio of the screen as well:
https://docs.unity3d.com/ScriptReference/Camera-aspect.html

Related

Android Camera2 preview occasionally rotated by 90 degrees

I'm working on some app using Android's Camera2 API. So far I've been able to get a preview displayed within a TextureView. The app is by default in landscape mode. When using the emulator the preview will appear upside-down. On my physical Nexus 5 the preview is usually displayed correctly (landscape, not upside-down), but occasionally it is rotated by 90 degrees, yet stretched to the dimensions of the screen.
I thought that should be easy and thought the following code would return the necessary information on the current orientation:
// display rotation
getActivity().getWindowManager().getDefaultDisplay().getRotation();
// sensor orientation
mManager.getCameraCharacteristics(mCameraId).get(CameraCharacteristics.SENSOR_ORIENTATION);
... I was pretty surprised when I saw that above code always returned 1 for the display rotation and 90 for the sensor orientation, regardless of the preview being rotated by 90 degree or not. (Within the emulator sensor orientation is always 270 which kinda makes sense if I assume 90 to be the correct orientation).
I also checked the width and height within onMeasure within AutoMeasureTextureView (adopted from Android's Camera2 example) that I'm using to create my TextureView. But no luck either - width and height reported from within onMeasure are always the same regardless of the preview rotation.
So I'm clueless on how to tackle this issue. Does anyone have an idea what could be the reason for the occasional hickups in my preview orientation?
[Edit]
A detail I just found out: Whenever the preview appears rotated onSurfaceTextureSizeChanged in the TextureView.SurfaceTextureListener seems not to get called. In the documentation for onSurfaceTextureSizeChanged it is said that this method is called whenever the SurfaceTexture's buffers size is changed. I have a method createCameraPreviewSession (copied from Android's Camera2 example) in which I set the default buffer size of my texture like
texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
From my logging output I can tell that onSurfaceTextureSizeChanged is called exactly after that - however, not always... (or setting the default buffer size sometimes silently fails?).
I think I can answer my own question: I was creating my Camera2 Fragment after the Android's Camera2 example. However, I didn't really consider the method configureTransform to be important as, opposite to the example code, my application is forced to landscape mode anyway. It turned out that this assumption was wrong. Since having configureTransform reintegrated in my code I haven't experienced any more hiccups.
Update: The original example within the Android documentation pages doesn't seem to exist anymore. I've updated the link which is now pointing to the code on Github.
I followed the whole textureView.setTransform(matrix) method listed above, and it worked. However, I was also able to manually set the rotation using the much simpler textureView.setRotation(270) without the need to create a Matrix.
I had also faced a similar issue on the Nexus device. The below code is working for me.
Call this function before opening the camera and also on Resume().
private void transformImage(int width, int height)
{
if (textureView == null) {
return;
} else try {
{
Matrix matrix = new Matrix();
int rotation = getWindowManager().getDefaultDisplay().getRotation();
RectF textureRectF = new RectF(0, 0, width, height);
RectF previewRectF = new RectF(0, 0, textureView.getHeight(), textureView.getWidth());
float centerX = textureRectF.centerX();
float centerY = textureRectF.centerY();
if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) {
previewRectF.offset(centerX - previewRectF.centerX(), centerY - previewRectF.centerY());
matrix.setRectToRect(textureRectF, previewRectF, Matrix.ScaleToFit.FILL);
float scale = Math.max((float) width / width, (float) height / width);
matrix.postScale(scale, scale, centerX, centerY);
matrix.postRotate(90 * (rotation - 2), centerX, centerY);
}
textureView.setTransform(matrix);
}
} catch (Exception e) {
e.printStackTrace();
}
}

galaxy s7 edge drag and drop

I have a user who has uprgraded from Samsung Galaxy S6 Edge to Samsung Galaxy S7 Edge.
My app has the ability to drag and drop playing card images.
The user indicates that this feature is not working on the S7 Edge but it did on the S6 Edge.
The dragging works, which suggests that the onTouch() and onDrag() are working but when an object is dropped it returns to its original position instead of the required position.
protected void measureDisplay() {
// get info about screen size to determine style of images to use
display = getWindowManager().getDefaultDisplay();
size = new Point();
display.getSize(size);
displayMetrics = new DisplayMetrics();
// get the density of the display
display.getMetrics(displayMetrics);
width = size.x;
height = size.y;
}
private void measureBoard(View v) {
// get the current view width and height
float viewWidth = v.getWidth();
float viewHeight = v.getHeight();
// extract the image offsets inside the view
Matrix matrix = ((ImageView) v).getImageMatrix();
float[] values = new float[9];
matrix.getValues(values);
boardLeft = values[2]; // the X offset
boardRight = viewWidth - boardLeft;
boardTop = values[5]; // the Y offset
boardBottom = viewHeight - boardTop;
cardOffsetW = (boardRight - boardLeft) / 10;
cardOffsetH = (boardBottom - boardTop) / 10;
}
At least some of the problems with behind-the-scenes display scaling can be solved by finding out if the user has Samsung's Game Tuner installed. It changes the Resolution Ratio for any "Game" app, and possibly does it without ever being opened.
To resolve, ask users to specify Resolution Ratio for your game in Game Tuner (they can do that on a per-app basis). See more here: DragEventListener not working on Samsung S7 (6.0)
I am working on an update for my game which would pop a message if they have Game Tuner installed.
This app:
https://play.google.com/store/apps/details?id=com.evozi.displayscaling
will resolve the issue on Samsung devices.
In our game we faced with similar problem and solution was this settings change.
I hope that Samsung will provide fix with some next OS update so we do need to inform users about this bug and forcing them to change settings.

How to make TMXTiledMap responsive?

My game is a 2D car-based one, with a straight infinite map where I've finally been able to add some random obstacles. There are only 3 positions the car can be at, and everything is working fine.
The point is that I've recently noticed that it is not responsive, and tried to make it responsive by adding a line like these one to the AppDelegate.cpp:
glview->setDesignResolutionSize(1024.0, 600.0, kResolutionFixedWidth);
I've tried to use kResolutionFixedWidth, kResolutionFixedHeight and all others 5 variables you can put there, but I only got black lines along the screen and every single screen breakdown you can imagine -.-'
I can figure out I need to resize my TMXTiledMap manually because of the nature of tiles (I did it with Tiled), but I don't know how to face this problem.
Note that I'm currently developing for a 1024x600 Android device but I would want to support at least the most common resolutions for both tablets and smartphones.
There are probably 2 resolution policies you want to use.
If you use No Border then you shouldn't see any black bars, but the engine will crop your design resolution so you won't want to put UI in the corners, or you'll want to use Visible Origin and Visible Size to calculate positions.
If you use Exact Fit you should set the design resolution to the devices exact size, and then you're responsible for positioning and scaling everything correctly to avoid distortion.
You will need to scale your art depending on your policy and design resolution choices if you are seeing black bars.
Have you read through this wiki page?
http://www.cocos2d-x.org/wiki/Multi_resolution_support
Here's what we do for one of our games:
auto director = Director::getInstance();
auto glview = director->getOpenGLView();
float contentScaleFactor = 1.f;
// Set the design resolution
Size frameSize = glview->getFrameSize();
Size designSize = glview->getDesignResolutionSize();
CCLOG("defaults:");
CCLOG("framesize = {%f,%f}", frameSize.width, frameSize.height);
CCLOG("visibleSize = {%f,%f}", glview->getVisibleSize().width, glview->getVisibleSize().height);
CCLOG("designSize = {%f,%f}", designSize.width, designSize.height);
CCLOG("contentscalefactor = %f", director->getContentScaleFactor());
Vec2 origin = director->getVisibleOrigin();
CCLOG("visibleSize = %s", CStrFromSize(director->getVisibleSize()));
CCLOG("origin = {%f,%f}", origin.x, origin.y);
// Retina?
contentScaleFactor = director->getContentScaleFactor();
float designWidth = frameSize.width / contentScaleFactor;
float designHeight = frameSize.height / contentScaleFactor;
CCLOG("contentScale = %f, designWidth/Height = {%f,%f}", contentScaleFactor, designWidth, designHeight);
glview->setDesignResolutionSize(designWidth, designHeight, ResolutionPolicy::EXACT_FIT);
// we designed the game for 480x320 (hence the divisors)
// used to scale full screen backgrounds
float fullWidthScaleFactor = designWidth/480.f;
// used to scale up most UI
float largeScaleFactor = floorf(designHeight/320.f);
// round to closest HALF step (1.0,1.5,2.0,2.5,3.0,etc)
// used for scaling UI where pixel art is affected by .1 scales
float largeScaleFactorExact = floorf(designHeight * 2.f / 320.f) * 0.5f;
// used to scale up UI that must be touchable (larger on high desnsity)
float largeScaleFactorUI = STROUND(designHeight / 320.f);
// this forces minimum of 1x scale (we should just not support these devices)
float scaleFitAll = designWidth > designHeight ? designHeight/320.f : designWidth/480.f;
if(largeScaleFactor < 1.f)
largeScaleFactor = scaleFitAll;
if(largeScaleFactorExact < 1.f)
largeScaleFactorExact = scaleFitAll;
if(largeScaleFactorUI < 1.f)
largeScaleFactorUI = scaleFitAll;

Flash game - configure stage dimensions for Android

I'm developing an actionscript game made for web. However, I want to port it for android devices as well. The orientation of the game is static (landscape). How can I configure the stage size in order to have a full screen game in Android?
You can try this :
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.displayState = StageDisplayState.FULL_SCREEN;
More info in Adobe's documentation :
http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS2E9C7F3B-6A7C-4c5d-8ADD-5B23446FBEEB.html
The exact screen size (in fullscreen, without battery or signal icon bar) is defined with
var SW:int = flash.system.Capabilities.screenResolutionX;
var SH:int = flash.system.Capabilities.screenResolutionY;
Either you can zoom your application with a ratio based on your flash stage size, or you can set all your elements with your phone's screen size.
For example if your flash is 320x480, your Zoom variable is :
if(SW > 320 && SH > 480){
if (SW / 320 < SH / 480) {
ZOOM = SW / 320;
}else {
ZOOM = SH / 480;
}
}
Then you have ZOOM = 1.5 if your phone is 480x800 (most of android).
In my game, I used:
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
In app's xml file I hadsomething like this:
<initialWindow>
...
<fullscreen>true</fullscreen>
<aspectRatio>landscape</aspectRatio>
</initialWindow>
and for detection of width/height i used:
stage.fullScreenWidth
stage.fullScreenHeight
and then I positioned all elements accordingly. You cannot just "set" stage size. Maybe you want to read this http://www.adobe.com/devnet/air/articles/multiple-screen-sizes.html

Issues with screen sizes and activity rendering

I'm currently developing my first android app, and my first game. I've been developing on a netbook with a CliqXT (HVGA). Things are going well, it renders perfectly on the smaller screen. I knew I'd have some issues when rendering on larger screens, but the issues I'm having are not what I was expecting and I'm kind of stuck.
So basically the game consists of a main SurfaceView which I'm rendering the tiled game world on to. I followed this tutorial to get started, and my structure is still pretty similar except that it calculates the boundries based on the player location:
http://www.droidnova.com/create-a-scrollable-map-with-cells-part-i,654.html
The game also has various buildings the player can enter. Upon entering it launches another activity for that particular building. The building activities are just normal Views with Android UI stuff defined in XML (Buttons, TextViews, etc).
What I expected to happen:
So I expected the the building UIs to render correctly on the larger screen. I specified all dimensions in "dp" and fonts in "sp" in hopes that they'd scale correctly. I expected the actual game tilemap to render generally correctly, but maybe be really tiny due to the higher resolution / dpi. I'm using a very similar function to the tutorial linked above (calculateLoopBorders(), my version is pasted below) to calculate how many tiles to render based on screen height and width (getHeight() and getWidth()).
What is actually happening:
The whole game is just being rendered as if it's HVGA. The tilemap, and the building UIs are just scaled down to the smaller screen size, leaving black borders around the left, right, and bottom (see images).
If anyone can point me in the right direction it'd be greatly appreciated, thanks a lot!
(Some of you may recognize this public domain DOS classic)
Edit: Thanks Christian for fixing code formatting.
mCellHeight and mCellWidth are the width/height of the cells in pixels
mMapHeight and mMapWidth are the width/height of the total game world in number of tiles
public void calculateLoopBorders() {
mWidth = getWidth();
mHeight = getHeight();
mStartRow = (int) Math.max(0, mPlayer.mRow - ((int) (mHeight / 2) / mCellHeight));
mStartCol = (int) Math.max(0, mPlayer.mCol - ((int) (mWidth / 2) / mCellWidth));
mMaxRow = (int) Math.min(mMapHeight, mStartRow + (mHeight / mCellHeight)) + 1;
mMaxCol = (int) Math.min(mMapWidth, mStartCol + (mWidth / mCellWidth));
if (mMaxCol >= mMapWidth) {
mStartCol = mMaxCol - (mWidth / mCellWidth);
}
if (mMaxRow >= mMapHeight) {
mStartRow = mMaxRow - (mHeight / mCellHeight);
}
int x1 = mStartCol * mCellWidth;
int y1 = mStartRow * mCellHeight;
int x2 = x1 + mWidth;
int y2 = y1 + mHeight;
mBgSrcRect = new Rect(x1, y1, x2, y2);
mBgDestRect = new Rect(0,0, mWidth, mHeight);
}
I figured it out. I was targeting 1.5 in the Project so it was assuming HVGA. Targeting 2.1 fixes the issue and the bitmaps even seem to scale correctly using some kind of android magic.
I still have a question though, when I finish this game I want it to work with 1.5+ devices. Do I need to put separate builds into the market, one for each device class? This seems like a lot of trouble for something that could be handled in a line or 2 of code in the app itself... but I've never released an app so maybe it's easily handled in the process.

Categories

Resources