unity3d(2d!) - 相机在播放器上居中,但从不超过“地图”边界 [英] unity3d (2d!) - Camera to centre on player, but never exceed "map" bounds

查看:3503
本文介绍了unity3d(2d!) - 相机在播放器上居中,但从不超过“地图”边界的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个游戏,它最多有4个正交摄影机(最多4个玩家),这取决于玩家的数量,占据不同数量的屏幕。







我有一个脚本



我想实现的是一个简单的开销运动风格的运动,由此相机将会按照播放器,但不会超出地图的范围。





我已经设法获得边界在左上角的摄像头工作,当摄像头是'播放器布局)。但是,其他相机根本无法正确跟踪,在矩形2播放器模式下,顶部相机仍然向左右过度。我很确定我知道确切的是哪行代码导致问题...但我不知道我需要做什么来解决它...

  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; //我想问题是在这里...但如何解决这个问题?

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; //我想问题是在这里...但如何解决这个问题?

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.statichographicSize;
float horzExtent = vertExtent * Screen.width / Screen.height; //我想问题是在这里...但如何解决这个问题?

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; //我想问题是在这里...但如何解决这个问题?

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);
}

所以我很确定我需要检查相机尺寸和在屏幕上的相对位置,但我失去了我需要做什么。



(编辑)
脚本说明:




  • 脚本是附加到主要相机对象的全局脚本,播放器

  • 四个播放器凸轮(camPlayer1 - camPlayer4)是公共变量,并分配给设计人员的脚本

  • trackPlayer1-trackPlayer4是公共游戏对象

  • 播放器跟踪适用于所有摄像机...例如,如果我更改了 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); camPlayer2.transform.position = trackPlayer2.transform.position; ,代码具有预期的效果,相机跟随播放器。

  • 相机的拼版大小设置为2



代码,用于在启动时将相机放置在屏幕上:

  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 = CamManagerCAMERA_SIZE;

camPlayer4.rect = new Rect(0,0,0,0);
camPlayer4.orthographicSize = CamManager.CAMERA_SIZE;


销毁(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;
}
}

编辑,所以我可以得到第一个相机无论形状如何(因此在双玩家模式下,使用矩形相机,玩家1的凸轮将遵守地图的边界),下面的代码。我猜,那么我需要应用一些偏移到leftBound,rightBound,topBound和bottomBound依赖于其他凸轮的矩形。如何建立和计算这些我不知道

  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; //我想问题是在这里...但如何解决这个问题?


解决方案


您的计算有几个问题。我想这只是运气,它适用于某些情况。虽然你的一般想法是正确的,你计算与错误的属性。基本上你需要了解摄像机的纵横比,地图的边框和摄像机在边界处的行为。



我们需要的纵横比相机计算其宽度或范围。



如图所示, Screen.width Screen.height 指的是游戏的窗口或显示器分辨率,以防万一你运行游戏全屏。您还可以看到,与游戏窗口相比,摄像机可能具有不同的宽高比。好消息是Unity提供了一个属性来获取摄像机的宽高比。

  float camVertExtent = cam.orthograpicSize; 
float camHorzExtent = cam.aspect * camVertExtent;

现在我们有相机的区域,让我们来看看你的地图和它的边界框。



您尝试使用 bounds.size 计算,但您可以看到 bounds.size.x 是边界的宽度框。使用大小只会在地图的左下角从(0,0)开始时在世界空间中起作用。更好的方法是使用已经在世界空间中返回坐标的 bounds.min bounds.max 。 >

您的最终目标是摄像机应该保持在地图的范围内,即其位置受以下四个条件的限制:

 (cam.transform.position.x  -  camHorzExtent)> = bounds.min.x // left 
(cam。 transform.position.x + camHorzExtent)< = bounds.max.x // right
(cam.transform.position.y - camVertExtent)> = bounds.min.y // bottom
cam.transform.position.y + camVertExtent)< = bounds.max.y // top

现在你只需要采取玩家的位置,并限制相机到这些条件:

  float leftBound = bounds.min.x + camHorzExtent; 
float rightBound = bounds.max.x - camHorzExtent;
float bottomBound = bounds.min.y + camVertExtent;
float topBound = bounds.max.y - camVertExtent;

float camX = Mathf.Clamp(player.transform.position.x,leftBound,rightBound);
float camY = Mathf.Clamp(player.transform.position.y,bottomBound,topBound);

cam.transform.position = new Vector3(camX,camY,cam.transform.position.z);

如果所有相机具有相同的大小和宽高比,则可以对所有播放器相机使用相同的边界每个玩家只能计算 camX camY


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

解决方案

There are several issues with your calculations. I guess it's just luck that it works for some situations. While your general idea is correct, you're calculating with the wrong properties. Basically you need to understand the aspect ratio of the cameras, the bounding box of your map and how a camera should behave at the borders.

We need the aspect ratio of the camera to calculate its width or extent.

As you can see in the picture, Screen.width and Screen.height are referring to the game's window or the monitor resolution in case you're running the game fullscreen. You can also see that the cameras may have a different aspect ratio when compared to the game window. The good news is that Unity provides a property to get the camera's aspect ratio.

float camVertExtent = cam.orthograpicSize;
float camHorzExtent = cam.aspect * camVertExtent;

Now that we have the camera's extents, let's take a look at your map and its bounding box.

You tried calculating with bounds.size, but as you can see bounds.size.x is the width of the bounding box. Using the size will only work if your map's bottom-left starts at (0,0) in world space. A better approach is to use bounds.min and bounds.max which already return coordinates in world space.

Your ultimate goal is that the camera should stay within the bounds of the map, i.e., its position is restricted by the following four conditions:

(cam.transform.position.x - camHorzExtent) >= bounds.min.x // left
(cam.transform.position.x + camHorzExtent) <= bounds.max.x // right
(cam.transform.position.y - camVertExtent) >= bounds.min.y // bottom
(cam.transform.position.y + camVertExtent) <= bounds.max.y // top

Now you only need to take the player position and limit the camera to these conditions:

float leftBound   = bounds.min.x + camHorzExtent;
float rightBound  = bounds.max.x - camHorzExtent;
float bottomBound = bounds.min.y + camVertExtent;
float topBound    = bounds.max.y - camVertExtent;

float camX = Mathf.Clamp(player.transform.position.x, leftBound, rightBound);
float camY = Mathf.Clamp(player.transform.position.y, bottomBound, topBound);

cam.transform.position = new Vector3(camX, camY, cam.transform.position.z);

If all cameras have the same size and aspect ratio, you can use the same bounds for all player cameras and only calculate camX and camY for each player.

这篇关于unity3d(2d!) - 相机在播放器上居中,但从不超过“地图”边界的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆