- Home /
The question is answered, right answer was accepted
Scaling my background Sprite to fill screen? (2d)
So I'm trying to scale my background sprite(s) to fill the screen, there are 2 a regular background image, and a sprite that lays over it with alpha transparency to fake shadows (since lighting doesn't apply to 2d sprites) the issue is i cant seem to find that magical float to multiply my sprite width/height by to get the desired size (maybe i just suck at math. My First attempt was:
percentW = (float)scrW/(float)imgW;
percentH = (float)scrH/(float)imgH;
which gives me 0.3125/0.3125
but in playing with inspector variables i found that for this particular resolution i need 0.8/0.8 so i looked online and found this code:
float height = 2.0f * Mathf.Tan(0.5f * Camera.main.fieldOfView * Mathf.Deg2Rad);
float width=height * scrW/scrH;
which gives me 0.649 for height, closer but still not perfect. I can hard code a close approximation by multiplying by 1.3 to get .84 but i want .8 almost exactly, and its driving me nuts.
This is going to be an android title meaning tons and tons of varying resolutions so of course independence is of the utmost importance. So has anyone figured out how to do this yet?
Answer by robertbu · Jan 19, 2014 at 08:49 PM
I've not spent a lot of time with the 2D stuff yet, but it seems to be that you have to use the world size of the sprite to make this calculation. In particular, since you can specify Pixels to Units when you import a sprite texture, the world mapping needs to use the sprite.bounds. Here's some sample code. There may be a simpler solution. It assumes an Orthographic camera centered on the image parallel to the camera plane:
function ResizeSpriteToScreen() {
var sr = GetComponent(SpriteRenderer);
if (sr == null) return;
transform.localScale = Vector3(1,1,1);
var width = sr.sprite.bounds.size.x;
var height = sr.sprite.bounds.size.y;
var worldScreenHeight = Camera.main.orthographicSize * 2.0;
var worldScreenWidth = worldScreenHeight / Screen.height * Screen.width;
transform.localScale.x = worldScreenWidth / width;
transform.localScale.y = worldScreenHeight / height;
}
P.S. I see you are trying to use fieldOfView. If you are using a perspective camera, this code will need to be modified.
This helped me $$anonymous$$ASSIVELY in my project, cheers :)
HI Robert, When I use this code, monodevelop says
Error: Assets/C#Scripts/$$anonymous$$ain$$anonymous$$enu1.cs(45,35): error CS1061: Type object' does not contain a definition for
sprite' and no extension method sprite' of type
object' could be found (are you missing a using directive or an assembly reference?)
@rahulreddyv - The code above compiled fine for me. I just tested it again to make sure. What changes did you make from what is here?
I hv copied it into a CS Script, and it puked these errors. I will work it for CS thank you for the code. I think this transforms all the sprites isn't it?
The above code scales a sprite to fill the screen. And yes the code will need a bit of changing for C#.
Answer by Shubhra · Jun 14, 2014 at 10:23 AM
Many Many thanks to robert. It helped me a lot. This is the C# implementation of robert's code:
void Resize()
{
SpriteRenderer sr=GetComponent<SpriteRenderer>();
if(sr==null) return;
transform.localScale=new Vector3(1,1,1);
float width=sr.sprite.bounds.size.x;
float height=sr.sprite.bounds.size.y;
float worldScreenHeight=Camera.main.orthographicSize*2f;
float worldScreenWidth=worldScreenHeight/Screen.height*Screen.width;
Vector3 xWidth = transform.localScale;
xWidth.x=worldScreenWidth / width;
transform.localScale=xWidth;
//transform.localScale.x = worldScreenWidth / width;
Vector3 yHeight = transform.localScale;
yHeight.y=worldScreenHeight / height;
transform.localScale=yHeight;
//transform.localScale.y = worldScreenHeight / height;
}
A little dated post, but you can do that simpler with C#
SpriteRenderer sr = GetComponent<SpriteRenderer>();
float worldScreenHeight = Camera.main.orthographicSize * 2;
float worldScreenWidth = worldScreenHeight / Screen.height * Screen.width;
transform.localScale = new Vector3(
worldScreenWidth / sr.sprite.bounds.size.x,
worldScreenHeight / sr.sprite.bounds.size.y, 1);
Also, you may not want to do "if(sr==null) return;", because debugger would just let it run and you wouldn't see where the error is.
Zafis, your right that would also work...
Use "Public SpriteRender sr;" at the beginning of the script ins$$anonymous$$d of "SpriteRenderer sr = GetComponent();" so that you can use it in any gameobject, however this requires more work if the sprite is created by code...
Dated addition. Also, probably a little redundant and not the cleanest solution. However, I've modified the above to allow for keeping an aspect ratio (so if you try and put a 640x480 sprite on a 500x500 screen - it will create a 667x500 sprite).
In this case, I called it AutoStretchSprite.cs and attached it to a SpriteRender.
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(SpriteRenderer))]
public class AutoStretchSprite : $$anonymous$$onoBehaviour {
/// <summary> Do you want the sprite to maintain the aspect ratio? </summary>
public bool $$anonymous$$eepAspectRatio = true;
/// <summary> Do you want it to continually check the screen size and update? </summary>
public bool ExecuteOnUpdate = true;
void Start () {
Resize($$anonymous$$eepAspectRatio);
}
void FixedUpdate () {
if (ExecuteOnUpdate)
Resize($$anonymous$$eepAspectRatio);
}
/// <summary>
/// Resize the attached sprite according to the camera view
/// </summary>
/// <param name="keepAspect">bool : if true, the image aspect ratio will be retained</param>
void Resize(bool keepAspect = false)
{
SpriteRenderer sr = GetComponent<SpriteRenderer>();
transform.localScale = new Vector3(1, 1, 1);
// example of a 640x480 sprite
float width = sr.sprite.bounds.size.x; // 4.80f
float height = sr.sprite.bounds.size.y; // 6.40f
// and a 2D camera at 0,0,-10
float worldScreenHeight = Camera.main.orthographicSize * 2f; // 10f
float worldScreenWidth = worldScreenHeight / Screen.height * Screen.width; // 10f
Vector3 imgScale = new Vector3(1f, 1f, 1f);
// do we scale according to the image, or do we stretch it?
if (keepAspect)
{
Vector2 ratio = new Vector2(width / height, height / width);
if ((worldScreenWidth / width) > (worldScreenHeight / height))
{
// wider than tall
imgScale.x = worldScreenWidth / width;
imgScale.y = imgScale.x * ratio.y;
}
else
{
// taller than wide
imgScale.y = worldScreenHeight / height;
imgScale.x = imgScale.y * ratio.x;
}
}
else
{
imgScale.x = worldScreenWidth / width;
imgScale.y = worldScreenHeight / height;
}
// apply change
transform.localScale = imgScale;
}
}
Just a little note: this code does not work if the Sprite in a child object and the parent Object has scale not equal to (1,1,1). I've made 2 adjustents:
1) The image is centered with the camera; 2) The localScale is modified to fit the screen even if the sprite is a child of some other GameObject
SpriteRenderer sr = GetComponent<SpriteRenderer>();
transform.position = Camera.main.transform.position + Vector3.forward * this.transform.position.z;
transform.localScale = new Vector3(1, 1, 1);
Vector3 lossyScale = transform.lossyScale;
float width = sr.sprite.bounds.size.x;
float height = sr.sprite.bounds.size.y;
float worldScreenHeight = Camera.main.orthographicSize * 2f;
float worldScreenWidth = worldScreenHeight / Screen.height * Screen.width;
Vector3 xWidth = transform.localScale;
xWidth.x = worldScreenWidth / width;
transform.localScale = xWidth;
//transform.localScale.x = worldScreenWidth / width;
Vector3 yHeight = transform.localScale;
yHeight.y = worldScreenHeight / height;
transform.localScale = yHeight;
Vector3 newLocalScale = new Vector3(transform.localScale.x / lossyScale.x,
transform.localScale.y / lossyScale.y,
transform.localScale.z / lossyScale.z
);
transform.localScale = newLocalScale;