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??