0
\$\begingroup\$

I have a 2D space shooter game. I looked up some questions from unity community and came across this solution. Below is the code for my player's movement:

//horizontal <- || -horizontal ->
//vertical down || -vertical up
float h = -Input.GetAxis ("Horizontal")*speed;
float v = -Input.GetAxis ("Vertical")*speed;

// do not let the ship get out of the camera
Vector3 viewPosition = Camera.main.WorldToViewportPoint(transform.position);
viewPosition.x = Mathf.Clamp01(viewPosition.x);
viewPosition.y = Mathf.Clamp01(viewPosition.y);
transform.position = Camera.main.ViewportToWorldPoint(viewPosition);

transform.Translate (h, v, 0);

I understand these functions as 0,0 being the left bottom of the camera and 1,1 being the right top. Therefore clamp01() is used. But with this code, half of my ship gets out of the screen, which is not what I want. How am I supposed to manipulate the clamp01 function so that the entire ship of the player stays in the camera scene?

Another workaround I thought was using the screen width and height and the regular clamp() function as follows:

transform.Translate (h, v, 0);

Vector3 tmpPos = transform.position;
tmpPos.x = Mathf.Clamp (tmpPos.x, -Screen.width / 2, Screen.width / 2);
tmpPos.y = Mathf.Clamp (tmpPos.y, -Screen.height / 2, Screen.height / 2);
transform.position = tmpPos;

However I get the Screen.height as 428, although the camera sees the interval of [-10, 10]. How am I supposed to clamp the movement independent of the game resolution, i.e. not using global positions but using relative positions so that I will be able to clamp correctly player's ship whatever the resolution of the game is?

\$\endgroup\$
1

1 Answer 1

1
\$\begingroup\$

Your first approach fails to account for the width of the object, while your second approach fails to account for the difference between screen pixels and world coordinates.


I have always converted the extremes of the screen to world coordinates.

Vector3 bottomLeftWorldCoordinates = Camera.main.ViewportToWorldPoint(Vector3.zero);
Vector3 topRightWorldCoordinates = Camera.main.ViewportToWorldPoint(new Vector3(1,1,0));

When you perform your clamping in world coordinates it is easier to apply an offset for the object width.

As the position is (often) the center of the object you will need to calculate half it's width and offset your clamp accordingly. Likewise on the y-axis.

A good source of half-width and half-height values is often renderer.bounds.extents.

Vector3 movementRangeMin = bottomLeftWorldCoordinates + renderer.bounds.extents;
Vector3 movementRangeMax = topRightWorldCoordinates - renderer.bounds.extents;

You can then use these value to clamp the object to the screen.

Vector3 newPosition = transform.position;
newPosition.x = Mathf.Clamp(position.x, movementRangeMin.x, movementRangeMax.x);
newPosition.y = Mathf.Clamp(position.y, movementRangeMin.y, movementRangeMax.y);
transform.Translate(newPosition - transform.position);
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .