I am creating a game which has up to 4 orthographic cameras (for up to 4 players), which take up various amounts of the screen, depending on the amount of players.
I have a script which controls all the cameras, setting their position relative to the players they are watching.
What I want to achieve is a simple overhead-runner style of movement, whereby the camera will follow the player, but not go outside the bounds of the map.
I have managed to get the boundaries working in the top-left camera, when the cameras are 'square' (as in the 4-player layout). However, the other cameras don't track properly at all, and in the rectangular 2-player mode, the top camera still goes too far left-and right. I'm pretty sure I know exactly which line of code is causing the problem... but I don't know what I need to do to fix it...
SpriteRenderer spriteBounds = GameObject.Find("Map").GetComponentInChildren<SpriteRenderer>();
float leftBound =0;
float rightBound =0;
float bottomBound =0;
float topBound = 0;
if((trackPlayer1 == null))
{
camPlayer1.transform.position = this.transform.position;
}
else
{
float vertExtent = camPlayer1.orthographicSize;
float horzExtent = vertExtent * Screen.width / Screen.height; //I guess the problem is here... but how do I fix this??
leftBound = (float)(horzExtent - spriteBounds.sprite.bounds.size.x / 2.0f);
rightBound = (float)(spriteBounds.sprite.bounds.size.x / 2.0f - horzExtent);
bottomBound = (float)(vertExtent - spriteBounds.sprite.bounds.size.y / 2.0f);
topBound = (float)(spriteBounds.sprite.bounds.size.y / 2.0f - vertExtent);
camPlayer1.transform.position = new Vector3(Mathf.Clamp(trackPlayer1.transform.position.x, leftBound, rightBound), Mathf.Clamp(trackPlayer1.transform.position.y, bottomBound, topBound), camPlayer1.transform.position.z);
}
if((trackPlayer2 == null))
{
camPlayer2.transform.position = this.transform.position;
}
else
{
float vertExtent = camPlayer2.orthographicSize ;
float horzExtent = vertExtent * Screen.width / Screen.height; //I guess the problem is here... but how do I fix this??
leftBound = (float)(horzExtent - spriteBounds.sprite.bounds.size.x / 2.0f);
rightBound = (float)(spriteBounds.sprite.bounds.size.x / 2.0f - horzExtent);
bottomBound = (float)(vertExtent - spriteBounds.sprite.bounds.size.y / 2.0f);
topBound = (float)(spriteBounds.sprite.bounds.size.y / 2.0f - vertExtent);
camPlayer2.transform.position = new Vector3(Mathf.Clamp(trackPlayer2.transform.position.x, leftBound, rightBound), Mathf.Clamp(trackPlayer2.transform.position.y, topBound, bottomBound), camPlayer2.transform.position.z);
}
if((trackPlayer3 == null))
{
camPlayer3.transform.position = this.transform.position;
}
else
{
float vertExtent = camPlayer3.orthographicSize;
float horzExtent = vertExtent * Screen.width / Screen.height; //I guess the problem is here... but how do I fix this??
leftBound = (float)(horzExtent - spriteBounds.sprite.bounds.size.x / 2.0f);
rightBound = (float)(spriteBounds.sprite.bounds.size.x / 2.0f - horzExtent);
bottomBound = (float)(vertExtent - spriteBounds.sprite.bounds.size.y / 2.0f);
topBound = (float)(spriteBounds.sprite.bounds.size.y / 2.0f - vertExtent);
camPlayer3.transform.position = new Vector3(Mathf.Clamp(trackPlayer3.transform.position.x, leftBound, rightBound), Mathf.Clamp(trackPlayer3.transform.position.y, topBound, bottomBound), camPlayer3.transform.position.z);
}
if((trackPlayer4 == null))
{
camPlayer4.transform.position = this.transform.position;
}
else
{
float vertExtent = camPlayer4.orthographicSize;
float horzExtent = vertExtent * Screen.width / Screen.height; //I guess the problem is here... but how do I fix this??
leftBound = (float)(horzExtent - spriteBounds.sprite.bounds.size.x / 2.0f);
rightBound = (float)(spriteBounds.sprite.bounds.size.x / 2.0f - horzExtent);
bottomBound = (float)(vertExtent - spriteBounds.sprite.bounds.size.y / 2.0f);
topBound = (float)(spriteBounds.sprite.bounds.size.y / 2.0f - vertExtent);
camPlayer4.transform.position = new Vector3(Mathf.Clamp(trackPlayer4.transform.position.x, leftBound, rightBound), Mathf.Clamp(trackPlayer4.transform.position.y, topBound, bottomBound), camPlayer4.transform.position.z);
}
So I'm pretty sure that I need to be checking against the cameras size and relative position on the screen, but I am lost as to exactly what I need to be doing.
(edit) Script explanation:
- The script is a global script attached to the main camera object, which is never seen by the player
- The four player cams (camPlayer1 - camPlayer4) are public variables and assigned to the script in the designer
- trackPlayer1-trackPlayer4 are public gameobjects, which are assigned in the designer - they are assigned to the player objects
- Player tracking works on all cams... for example if I change camPlayer2.transform.position = new Vector3(Mathf.Clamp(trackPlayer2.transform.position.x, leftBound, rightBound), Mathf.Clamp(trackPlayer2.transform.position.y, topBound, bottomBound), camPlayer2.transform.position.z); to camPlayer2.transform.position = trackPlayer2.transform.position;, the code has the expected effect, the camera follows the player. It is only the clamping to the bounds of the map that I am having issues with
- The camera's orthographic sizes are set to 2
code which positions the cameras on screen at startup:
switch (playerCount)
{
case 1:
camPlayer1.enabled = true;
camPlayer2.enabled = false;
camPlayer3.enabled = false;
camPlayer4.enabled = false;
camPlayer1.rect = new Rect(0, 0, 1, 1);
camPlayer1.orthographicSize = CamManager.CAMERA_SIZE;
camPlayer2.rect = new Rect(0, 0, 0, 0);
camPlayer2.orthographicSize = CamManager.CAMERA_SIZE;
camPlayer3.rect = new Rect(0, 0, 0, 0);
camPlayer3.orthographicSize = CamManager.CAMERA_SIZE;
camPlayer4.rect = new Rect(0, 0, 0, 0);
camPlayer4.orthographicSize = CamManager.CAMERA_SIZE;
break;
case 2:
camPlayer1.enabled = true;
camPlayer2.enabled = true;
camPlayer3.enabled = false;
camPlayer4.enabled = false;
camPlayer1.rect = new Rect(0, 0.5f, 0.7f, 0.5f);
camPlayer1.orthographicSize = CamManager.CAMERA_SIZE;
camPlayer2.rect = new Rect(0.3f, 0, 0.7f, 0.5f);
camPlayer2.orthographicSize = CamManager.CAMERA_SIZE;
camPlayer3.rect = new Rect(0, 0, 0, 0);
camPlayer3.orthographicSize = CamManager.CAMERA_SIZE;
camPlayer4.rect = new Rect(0, 0, 0, 0);
camPlayer4.orthographicSize = CamManager.CAMERA_SIZE;
Destroy(play3);
Destroy(play4);
break;
case 3:
camPlayer1.enabled = true;
camPlayer2.enabled = true;
camPlayer3.enabled = true;
camPlayer4.enabled = false;
camPlayer1.rect = new Rect(0, 0.5f, 0.5f, 0.5f);
camPlayer1.orthographicSize = CamManager.CAMERA_SIZE;
camPlayer2.rect = new Rect(0.5f, 0.5f, 0.5f, 0.5f);
camPlayer2.orthographicSize = CamManager.CAMERA_SIZE;
camPlayer3.rect = new Rect(0.25f, 0, 0.5f, 0.5f);
camPlayer3.orthographicSize = CamManager.CAMERA_SIZE;
camPlayer4.rect = new Rect(0, 0, 0, 0);
camPlayer4.orthographicSize = CamManager.CAMERA_SIZE;
Destroy(play4);
break;
case 4:
camPlayer1.enabled = true;
camPlayer2.enabled = true;
camPlayer3.enabled = true;
camPlayer4.enabled = true;
camPlayer1.rect = new Rect(0, 0.5f, 0.5f, 0.5f);
camPlayer1.orthographicSize = CamManager.CAMERA_SIZE;
camPlayer2.rect = new Rect(0.5f, 0.5f, 0.5f, 0.5f);
camPlayer2.orthographicSize = CamManager.CAMERA_SIZE;
camPlayer3.rect = new Rect(0, 0, 0.5f, 0.5f);
camPlayer3.orthographicSize = CamManager.CAMERA_SIZE;
camPlayer4.rect = new Rect(0.5f, 0, 0.5f, 0.5f);
camPlayer4.orthographicSize = CamManager.CAMERA_SIZE;
break;
}
}
edit, so I can get the first camera to tract regardless of shape (so in 2-player mode, with a rectangular camera, the player-1 cam will respect the boundaries of the map) with the code below. I'm guessing then that I need to apply some offsets to the leftBound, rightBound, topBound and bottomBound dependent on the rects of the other cams. How to establish and calculate these I have no idea
if((trackPlayer1 == null))
{
camPlayer1.transform.position = this.transform.position;
}
else
{
float vertExtent = camPlayer1.orthographicSize;
float horzExtent = vertExtent * (Screen.width * (camPlayer1.rect.width * 2)) / Screen.height; //I guess the problem is here... but how do I fix this??
orthographicSize
property is half the vertical length of the screen and not the full length? – VermillionScreen.width / Screen.height
but then you obviously don't render to the whole screen area. You need to use the aspect ratio for the camera, which may be different to the aspect ratio of the screen. – Vermillionrect
property of the camera to calculate the aspect ratio for each camera. – VermillionSpriteRenderer::bounds::size
is the dimensions of the AABB and does not take into account the position. You should probably use themin
andmax
properties ofBounds
to obtain the coordinate extends instead. – VermillionMathf.Clamp(trackPlayer2.transform.position.y, topBound, bottomBound)
should beMathf.Clamp(trackPlayer2.transform.position.y, bottomBound, topBound)
. This is probably why your tracking is not working correctly. – Vermillion