How can I make my game screen fit every Android device. The problem every answer I find is for 2d. I want for 3d games.
You need two things for a 3D game
1-) Optimizing the canvas : https://www.youtube.com/watch?v=95q79j0lNYA
2-) Optimizing the camera angle (if you want it)
Optimizing the camera for every screen resolution may not be as easy as canvas.
For this, you can take certain standard resolutions with (Get in start Script).
Let's set the filed of view of the camera accordingly at Scene Start.
public class CameraOptimize : MonoBehaviour
{
// ========
private void Start
{
CameraOptimizer();
}
private void CameraOptimizer
{
if (Screen.height == 2560 || Screen.width == 1440)
{
Camera.main.fieldOfView = 65.0f;
}
else if (Screen.height == 1920 || Screen.width == 1080)
{
Camera.main.fieldOfView = 75.0f;
}
}
}
Related
In Unity i have a UI Panel which has a player object (an UI Image object).
I moving player object into planel with user inputs (keyboard or touch)
I can't keep player object in it's parent panel,
Please check below image, I want to keep player inside of Red Panel
Here is my Tried Code
public Camera MainCamera; //be sure to assign this in the inspector to your main camera
private Vector2 screenBounds;
private float objectWidth;
private float objectHeight;
private RectTransform pnlBackgroundTransform;
private void Start()
{
pnlBackgroundTransform = GameObject.Find("PnlBackground").GetComponent<RectTransform>();
screenBounds = MainCamera.ScreenToWorldPoint(new Vector3(pnlBackgroundTransform.rect.width , pnlBackgroundTransform.rect.height , MainCamera.transform.position.z));
objectWidth = transform.GetComponent<SpriteRenderer>().bounds.extents.x; //extents = size of width / 2
objectHeight = transform.GetComponent<SpriteRenderer>().bounds.extents.y; //extents = size of height / 2
}
void LateUpdate()
{
Vector3 viewPos = transform.position;
viewPos.x = Mathf.Clamp(viewPos.x, screenBounds.x * -1 + objectWidth, screenBounds.x - objectWidth);
viewPos.y = Mathf.Clamp(viewPos.y, screenBounds.y * -1 + objectHeight, screenBounds.y - objectHeight);
Debug.Log(screenBounds);
Debug.Log(viewPos);
transform.position = viewPos;
}
I'd say it's not very usual having the player implemented as a UI element, and instead you should be implementing it outside the UI/Canvas system.
The UI/Canvas system uses a set of rules of placing and scaling to deal with responsive design. You have at least 4 values (excluding rotation) to place something on the screen: anchor, pivot, position and scale.
For example: if you want to create a square you can either set it's size in absolute pixel values or relative values (to parent). If you're using absolute values, your UI Scale Mode, defined on the Canvas object, should affect the visual results.
This means the UI/Canvas is for elements that should adapt to the screen, such as buttons, dialogs, labels, etc. Taking advantage of device parameters to improve the UX.
Outside the UI/Canvas system, things are directly based on Linear Algebra: you have a 3D vector space (a "World") where everything exists with an absolute size and position. Then, your Camera stretches and twists the whole world to match what your current perspective. That means your object will always have the same size, regardless of screen size.
Now, assuming you have a very specific reason to implement your game into UI, there are a few ways you can do it. I'll assume you're using absolute values. Please note all the units used here are pixels, and the effect should be different for devices with different resolutions and sensible to the UI Scale Mode parameter. Also, please note I've set both anchors min and max to (0,0), the bottom left corner (default is screen center, (0.5,0.5)), in order to avoid negative coordinates.
The following script is attached to the player's UI Image.
public class UIMovementController : MonoBehaviour
{
public float speed = 5.0f;
new private RectTransform transform;
private Rect canvasRect;
private void Start()
{
transform = GetComponent<RectTransform>();
canvasRect = GetComponentInParent<Canvas>().pixelRect;
}
void Update()
{
// Keyboard Input (Arrows)
Vector2 move = new Vector2(0,0);
if (Input.GetKey(KeyCode.UpArrow)) { move.y += speed; }
if (Input.GetKey(KeyCode.DownArrow)) { move.y -= speed; }
if (Input.GetKey(KeyCode.LeftArrow)) { move.x -= speed; }
if (Input.GetKey(KeyCode.RightArrow)) { move.x += speed; }
transform.anchoredPosition += move;
// Position clamping
Vector2 clamped = transform.anchoredPosition;
clamped.x = Mathf.Clamp(clamped.x, transform.rect.width / 2, canvasRect.width - transform.rect.width / 2);
clamped.y = Mathf.Clamp(clamped.y, transform.rect.height / 2, canvasRect.height - transform.rect.height / 2);
transform.anchoredPosition = clamped;
}
}
I'm using a Samsung Galaxy S8, Unity3D, Gear VR and ARCore.
ARCore is used as a passthrough of the smartphone camera.
Unfortunately the resolution of the background is stretched. (As you can see in the image, which should display a circle)
Does anyone know how to change the background resolution?
After a long time fiddling around I found an acceptable solution for me.
public class SetResolution : MonoBehaviour {
public int width = 1480; //half of the Samsung S8 WQHD+ 2960x1440 resolution
public int height = 1440;
void Start () {
Screen.SetResolution(width, height, true);
}
void Update () {
}
}
Maybe there is a more elegant solution but it works for me.
While in editor, everything's working fine, but when I build the game to my phone, the background seems to be short on top and bottom side.
This is a screenshot from the phone build.
This is a screenshot from Unity.
I checked all sizes and they were all the same - 800x1280. I think the problem started to happen when I made the cloudy background infinitely move with a quad.
Checked everywhere, can't seem to pin-point the problem.
You should resize the background according to screen size. You can do that through code. If you are using Sprite Renderer, you can follow this link to do so. Here's the main codes needed to resize a sprite according to the above link.
void Awake() {
SpriteRenderer spriteRenderer = GetComponent<SpriteRenderer>();
float cameraHeight = Camera.main.orthographicSize * 2;
Vector2 cameraSize = new Vector2(Camera.main.aspect * cameraHeight, cameraHeight);
Vector2 spriteSize = spriteRenderer.sprite.bounds.size;
Vector2 scale = transform.localScale;
if (cameraSize.x >= cameraSize.y) { // Landscape (or equal)
scale *= cameraSize.x / spriteSize.x;
} else { // Portrait
scale *= cameraSize.y / spriteSize.y;
}
}
Or if you are using a UI Panel under Canvas to draw the background, you can set the anchors on the edge points and set the Canvas's UI Scale Mode to Scale With Screen Size
Generally for Unity I design all my artwork in Illustrator. So I start off with 1440x1920 (for portrait games) and outline a red frame of 1080x1920. So everything that fits well within the 1080x1920 usually covers the family of iOS devices for me. Then I set the Pixels Per Unit to 192 for all my images. This approach has really served me well. Now that the iPhone X is in the mix, how can I cater for it in a similar way?
As My experience, you don't have to do many things, the gameobject in a scene will just fit well, Unity has done that for you the only thing you maybe need to do is adjust the UI canvas if you are using UGUI, and it pretty easy too, why? because most phones have the similar width/height ratio, and in our team, we do the fix thing like this:
design all the UI stuff based on 1080p(1080x1920) (720p is fine too, but we presume there will be more 1080p device in the future)
attach following scripts to all the canvas to make an auto-fix thing:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class CanvasScreenAutoFix : MonoBehaviour
{
public static CanvasScreenAutoFix instance;
private static float DEPEND_W = 1080;
private static float DEPEND_H = 1920;
public float scaleRatio = 1.0f;
private void ResizeCanvas()
{
int screenW = Screen.width;
int screenH = Screen.height;
if (DEPEND_W == screenW && DEPEND_H == screenH)
{
scaleRatio = 1.0f;
return;
}
else
{
float W_scale = screenW / (float)DEPEND_W;
float H_scale = screenH / (float)DEPEND_H;
float scale = W_scale < H_scale ? W_scale : H_scale;
GetComponent<CanvasScaler>().scaleFactor = scale;
scaleRatio = scale;
}
}
private void Awake()
{
ResizeCanvas();
if(instance == null)
{
instance = this;
}
}
}
And the result turns to be pretty well, actually, we don't have to care about the scale things with the iPhone Family anymore after this(there may be some issue with iphone4 cause they have a different aspect ratio, but as there a rarely that devices anymore ...).
I am working on a 2D Game similar to Space Shooter. I developed it for Web and PC and it works great. I am now porting it to Android and am having an issue with the Player code.
The player(a space ship) will be at the bottom of the screen and it moves left to right within the screen. I wrote a piece of code which limits the player within the screen and here is the code:
private float screenx = Screen.width -20;
playerPosScreen = Camera.main.WorldToScreenPoint(transform.position);
if(Input.GetKey(KeyCode.RightArrow) && playerPosScreen.x < screenx)
{
transform.Translate(Vector3.right * speed * Time.deltaTime * 0.4f);
}
if (Input.GetKey(KeyCode.LeftArrow) && playerPosScreen.x > 20)
{
transform.Translate(-Vector3.right * speed * Time.deltaTime * 0.4f);
}
I am aware that I still need to convert few of the static values in the above code and this is is not really a good way to code.
My question here is how do I do this in Android? I want the player to stay in the screen, i.e if the user moves the player by dragging him to extreme left, no matter how much ever he tries to drag, the player should stay at the left corner of the screen and the same applies to right. In simple terms I want to detect the left and right edges of the screen and limit my object within these edges.
My game will be in landscape mode.
Any help would be very much appreciated. Thanks in advance.
This sort of problem is generally solved in the following manor:
if(transform.position.x < screenx) {
transform.position.x = screenx;
}
Here, we are checking to see if the transformed player is out of the screen space. If it is, we set it to the minimum it can be - which I am assuming is screenx.
public Transform player;
public float distanceFromCamera=10;
public float offsetx=.05f;
public float offsety=.05f;
void Awake()
{
player.position=Camera.main.ViewportToWorldPoint(new Vector3(offsetx,offsety,distanceFromCamera));
}
this will be your bottom left screen boundry