Issues with screen sizes and activity rendering - android

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.

Related

Unity Normal Maps don't work on Android device

I'm an experienced native iOS developer making my first foray into Android through Unity. I'm trying to set up a custom shader, but I'm having some trouble with the Normal maps. I've got them working perfectly in the Unity simulator on my computer, but when I build to an actual device (Samsung Galaxy S8+), the Normal maps don't work at all.
I'm using Mars as my test case. Here's the model running in the simulator on my computer:
And here's a screenshot from my device, running exactly the same code.
I've done a LOT of research, and apparently using Normal maps on Android with Unity is not an easy thing. There are a lot of people asking about it, but almost every answer I've found has said the trick is to override the texture import settings, and force it to be "Truecolor" which seems to be "RGBA 32 Bit" according to Unity's documentation. This hasn't helped me, though.
Another thread suggested reducing the Asino Level to zero, and another suggested turning off Mip Maps. I don't know what either of those are, but neither helped.
Here's my shader code, simplified but containing all references to Normal mapping:
void surf (Input IN, inout SurfaceOutputStandard o) {
half4 d = tex2D (_MainTex , IN.uv_MainTex);
half4 n = tex2D (_BumpMap , IN.uv_BumpMap);
o.Albedo = d.rgb;
o.Normal = UnpackNormal(n);
o.Metallic = 0.0;
o.Smoothness = 0.0;
}
I've seen some threads suggesting replacements for the "UnpackNormal()" function in the shader code, indicating that it might not be the thing to do on Android or mobile in general, but none of the suggested replacements have changed anything for better or worse: the normal maps continue to work in the simulator, but not on the device.
I've even tried making my own normal maps programmatically from a grayscale heightmap, to try to circumvent any import settings I may have done wrong. Here's the code I used, and again it works in the simulator but not on the device.
public Texture2D NormalMap(Texture2D source, float strength = 10.0f) {
Texture2D normalTexture;
float xLeft;
float xRight;
float yUp;
float yDown;
float yDelta;
float xDelta;
normalTexture = new Texture2D (source.width, source.height, TextureFormat.RGBA32, false, true);
for (int y=0; y<source.height; y++) {
for (int x=0; x<source.width; x++) {
xLeft = source.GetPixel (x - 1, y).grayscale * strength;
xRight = source.GetPixel (x + 1, y).grayscale * strength;
yUp = source.GetPixel (x, y - 1).grayscale * strength;
yDown = source.GetPixel (x, y + 1).grayscale * strength;
xDelta = ((xLeft - xRight) + 1) * 0.5f;
yDelta = ((yUp - yDown) + 1) * 0.5f;
normalTexture.SetPixel(x,y,new Color(xDelta,yDelta,1.0f,yDelta));
}
}
normalTexture.Apply();
return normalTexture;
}
Lastly, in the Build Settings, I've got the Platform set to Android and I've tried it using Texture Compression set to both "Don't Override" and "ETC (default)". The former was the original setting and the latter seemed to be Unity's suggestion both by the name and in the documentation.
I'm sure there's just some flag I haven't checked or some switch I haven't flipped, but I can't for the life of me figure out what I'm doing wrong here, or why there would be such a stubborn difference between the simulator and the device.
Can anyone help a Unity newbie out, and show me how these damn Normal maps are supposed to work on Android?
Check under:
Edit -> Project Settings -> Quality
Android is usually set to Fastest.

Set Display resolution limit in unity

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

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;

Why does the matrix generated by Android's frustumM differ from the Redbook's?

Something seems funny about the way that Android's frustumM works. If I check the OpenGL red book, the matrix generated looks like this:
(source: glprogramming.com)
Songho.ca seems to agree with this:
(source: songho.ca)
However, one component is multiplied by 2 with Android's frustumM, and not in the other example matrices. Here's what it seems to be doing:
Everything seems to functionally match up, except the first row, third column. Why is that being multiplied by two? Here's the lines of code from android.opengl.Matrix's frustumM method that generate the first three elements of the third column:
final float A = 2.0f * ((right + left) * r_width);
final float B = (top + bottom) * r_height;
final float C = (far + near) * r_depth;
With r_width, r_height, r_depth defined as:
final float r_width = 1.0f / (right - left);
final float r_height = 1.0f / (top - bottom);
final float r_depth = 1.0f / (near - far);
The line starting with "final float A" appears to be mistakenly multiplying by 2.
Is this a mistake in Android's code, or am I just missing something? I know that the term cancels out if the frustum is symmetrical. When running the code with an asymmetrical frustum, the generated matrices actually are different and so are the resulting vectors when the same vector is multiplied with those differing matrices.
It's a bug with Android. Please see http://code.google.com/p/android/issues/detail?id=35646
((I'd preffer just to comment but I'm not allowed.))
Thank you guys for the insight. I just had to add
mMyMatrix[8] /= 2f;
after
Matrix.frustrumM(mMyMatrix, ...)
To solve my aspect ratio problems :)
yes, if you call the function with a (-ratio, ratio, -1, 1, 1, 10) parameters set, it does not cause the probelm, but if you call with (right != -1 * left), it makes thing different.
I find this issue when i check the source code. sigh.

How create an unfinished jump game?

i want to create an unfinished jump game. i use super jumper code. the main part for change height of world is :
while (y < WORLD_HEIGHT - WORLD_WIDTH / 2) {
...
y += (maxJumpHeight - 0.5f);
y -= rand.nextFloat() * (maxJumpHeight / 3);
}
if i change while condition to a big number(for example 100 or 1000), fps goes low(i get lag).
i try many things. but i couldn't reach to a correct answer.
if someone can, help me.
(sorry for my english...)
Changing
while (y < WORLD_HEIGHT - WORLD_WIDTH / 2) {
to
while (y < WORLD_HEIGHT * 100) {
in Super Jumper's World.generateLevel will generate a lot more content, but won't actually make the level longer (the display system will only display up to WORLD_HEIGHT, and the end-of-level Castle will still be in the same place.
If you want to make a very large level, change the definition of WORLD_HEIGHT itself. Its currently set to about 20 screens worth of platforms.
The reason the game slows down when you make the levels larger is probably because all the per-frame update and collision detection code uses a linear scan of all the elements. For small levels, this is fine, but if you have very large levels, this won't scale. However, I'm just guessing, and you should probably run the profiler to figure out where all the time is being spent.

Categories

Resources