- Home /
Limit a sprite to not go off-screen
Hello there!
I would like to limit my sprite object so it can't go off-screen. The object is controlled by mouse so it is possible to get some of the object out of camera view.
How would i solve this?
EDIT: I have now done this, but it only "stops" at the center of the sprite, so half the sprite can still go off-screen.
Vector3 viewPos = Camera.main.WorldToViewportPoint (this.transform.position);
viewPos.x = Mathf.Clamp01 (viewPos.x);
viewPos.y = Mathf.Clamp01 (viewPos.y);
this.transform.position = Camera.main.ViewportToWorldPoint (viewPos);
Thanks!
Frederik
Do you want the whole piece to stay on the screen or is it okay for parts of it go off the screen
I don't want any part of the object to be able to go off-screen.
Vector3 mousePos = Input.mousePosition;
mousePos.z = 1.0F;
Vector2 worldPos = Camera.main.ScreenToWorldPoint (mousePos);
this.transform.position = worldPos;
Answer by ildac · Nov 23, 2013 at 10:26 AM
I know it's an old question, but since I've started now playing around with Unity3D 4.3, i had the same problem and i want to share with you my solution to understand if I'm doing it right.
I've managed to keep the full sprite in the screen with these code:
Vector3 playerSize = renderer.bounds.size;
// Here is the definition of the boundary in world point
var distance = (transform.position - Camera.main.transform.position).z;
var leftBorder = Camera.main.ViewportToWorldPoint (new Vector3 (0, 0, distance)).x + (playerSize.x/2);
var rightBorder = Camera.main.ViewportToWorldPoint (new Vector3 (1, 0, distance)).x - (playerSize.x/2);
var bottomBorder = Camera.main.ViewportToWorldPoint (new Vector3 (0, 0, distance)).y + (playerSize.y/2);
var topBorder = Camera.main.ViewportToWorldPoint (new Vector3 (0, 1, distance)).y - (playerSize.y/2);
// Here the position of the player is clamped into the boundaries
transform.position = (new Vector3 (
Mathf.Clamp (transform.position.x, leftBorder, rightBorder),
Mathf.Clamp (transform.position.y, bottomBorder, topBorder),
transform.position.z)
);
What it does is simply reduce the camera view of half of the sprite size, in this way when the center of the sprite hits the boundary it not outside the view but just inside.
Answer by perchik · Aug 07, 2013 at 11:01 PM
You could use your current code, but instead of clamping x and y from 0 to 1, clamp it to a smaller range.
float widthRel = width / (Screen.width); //relative width
float heightRel= height /(Screen.height); //relative height
Vector3 viewPos = Camera.main.WorldToViewportPoint (this.transform.position);
viewPos.x = Mathf.Clamp(viewPos.x, widthRel, 1-widthRel);
viewPos.y = Mathf.Clamp(viewPos.y, heightRel, 1-heightRel);
this.transform.position = Camera.main.ViewportToWorldPoint (viewPos);
Your code works because Clamp01 returns a number between 0 and 1, and the viewport starts at (0,0) and goes to (1,1). My code calculates the relative width of the object, and clamps the valid region to a subset of the screen.
If this doesn't work exactly right, you might need to change the clamps to Mathf.Clamp(viewPos.x, widthRel /2 , 1-(widthRel/2))
because the center of the object is what moves.
float widthRel = width / (Screen.width); //relative width float heightRel= height /(Screen.height); //relative height
What are these for? It isn't a variable?
thats whatever your sprite width and height is (you have to either replace width and height with whatever your sprite's width and height is, or write some script to check out that objects bounds to figure out what its width and height is)
Two issues with the code here. Both are fixable. First, unless you've been very careful to create your scene as pixel perfect, the amount of screen pixels the object takes up will not match the pixel size of the texture. Second, your widthRel and heightRel are twice too big. You need to divide the numbers by two.
As for calculating the size, the first thing to figure out is the world size of your object. That will depend on what plane you are using to display your sprites. The build in plane has a size of 10 x 10 with a scale of (1,1,1). If that is what you are using, I'd switch and use a plane made with the CreatePlane editor script. You can make it a vertical orientation and size of 1 x 1. Then transform.localScale will contain the world width and height.
With the world width and height, you can do a WorldToViewportPoint() on the center point and then one of the corners. Finding the distance between the two will give you the 'widthRe' and 'heightRel' to use in the code above.
float widthRel = this.transform.localScale.y / (Screen.width) / 2; //relative width
float heightRel = this.transform.localScale.x / (Screen.height) / 2; //relative height
Vector3 viewPos = Camera.main.WorldToViewportPoint (this.transform.position);
viewPos.x = $$anonymous$$athf.Clamp (viewPos.x, widthRel, 1 - widthRel);
viewPos.y = $$anonymous$$athf.Clamp (viewPos.y, heightRel, 1 - heightRel);
this.transform.position = Camera.main.ViewportToWorldPoint (viewPos);
This is close, though not perfect. How would i calculate the width & height of the sprite object? (Since localScale isnt accurate enough)