unity3d(2d!) - 相机以玩家为中心,但绝不超过“地图”范围

时间:2015-01-03 07:48:59

标签: unity3d camera position orthographic

我正在制作一款游戏,最多可配备4个正交摄像机(最多4个玩家),根据玩家的数量占据不同数量的屏幕。

2 cameras (with 0.7 each)

4 Cameras

我有一个控制所有摄像机的脚本,设置相对于他们正在观看的玩家的位置。

我想要实现的是一种简单的头顶 - 跑步运动风格,相机将跟随玩家,但不会超出地图范围。

required behaviour

当相机是“方形”时,我已设法在左上角的相机中工作。 (如4人布局)。但是,其他相机根本没有正确跟踪,而在矩形双人模式下,顶部相机仍然左右移动太远。我很确定我确切地知道导致问题的代码行...但我不知道我需要做些什么来修复它...

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

所以我非常确定我需要检查屏幕上相机的大小和相对位置,但我完全不知道自己需要做什么。

(编辑) 脚本说明:

  • 该脚本是一个附加到主摄像机对象的全局脚本,播放器永远不会看到该脚本
  • 四个播放器凸轮(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 = 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;
    }
}

编辑,所以无论形状如何,我都能得到第一台相机(所以在双人模式中,使用矩形相机,玩家-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; //I guess the problem is here... but how do I fix this??

4 个答案:

答案 0 :(得分:10)

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

我们需要相机的纵横比来计算其宽度或范围。 aspect ratios and screen size

正如您在图片中看到的那样,Screen.widthScreen.height指的是游戏的窗口或显示器分辨率,以防您全屏运行游戏。您还可以看到,与游戏窗口相比,相机可能具有不同的宽高比。好消息是Unity提供了获取相机宽高比的属性。

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

现在我们有相机的范围,让我们来看看你的地图及其边界框。 bounding box and camera position

您尝试使用bounds.size进行计算,但正如您所看到的,bounds.size.x是边界框的宽度。只有当地图的左下角从世界空间的(0,0)开始时,才能使用大小。更好的方法是使用已经返回世界空间坐标的bounds.minbounds.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);

如果所有相机具有相同的尺寸和宽高比,则可以对所有玩家相机使用相同的边界,并且仅为每个玩家计算camXcamY

答案 1 :(得分:2)

我想建议您解决问题的另一种方法。

您是否可以在地图的边框处添加高对撞机,以及相机的对撞机?然后你可以让相机跟随播放器(使用物理!),当玩家到达边界时,由于对撞机,相机不会过去。

然后,您可以轻松分割屏幕,了解您拥有多少玩家。 一个球员? - &GT;所有屏幕尺寸 两个球员? - &GT;相机1结束广告屏幕高度/ 2,相机2以屏幕高度/ 2 +1开始 等等

答案 2 :(得分:0)

大家好,有些人需要完整的代码才能将游戏对象与许多儿童精灵一起打入Empty Gameobject,如:

Background
--mountains1(sprite)
--mountains2(sprite)
--mountains3(sprite)

本守则将循环进入Background对象,并采取所有儿童精灵的界限:D,由于@Stefan Hoffmann的解释,我制作了一个Frankestein代码hahhaa。我希望这会对别人有所帮助,抱歉我的英语不好:(

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraFollow : MonoBehaviour
{

    private float rightBound;
    private float leftBound;
    private float topBound;
    private float bottomBound;
    private Vector3 pos;
    private Transform target;

    private Camera cam;
    private Bounds bounds;


    // Use this for initialization
    void Start()
    {
        target = GameObject.FindWithTag("Player").transform;


        foreach (SpriteRenderer spriteBounds in GameObject.Find("Background").GetComponentsInChildren<SpriteRenderer>())
        {
            bounds.Encapsulate(spriteBounds.bounds);
        }


        cam = this.gameObject.GetComponent<Camera>();
        float camVertExtent = cam.orthographicSize;
        float camHorzExtent = cam.aspect * camVertExtent;

        Debug.Log(camVertExtent);
        Debug.Log(camHorzExtent);
        Debug.Log(cam.aspect);
        Debug.Log(cam.orthographicSize);



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

        Debug.Log("leftBound=" + leftBound);
        Debug.Log("rightBound=" + rightBound);
        Debug.Log("bottomBound=" + bottomBound);
        Debug.Log("topBound=" + topBound);
    }

    // Update is called once per frame
    void Update()
    {


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

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

}

答案 3 :(得分:-1)

你应该使用这个简单但有用的unity 2d camera follow script
也可以在github上找到。 https://gist.github.com/unity3diy/5aa0b098cb06b3ccbe47


using UnityEngine;
using System.Collections;

public class FollowCamera : MonoBehaviour {

public float interpVelocity;
public float minDistance;
public float followDistance;
public GameObject target;
public Vector3 offset;
Vector3 targetPos;
// Use this for initialization
void Start () {
    targetPos = transform.position;
}

// Update is called once per frame
void FixedUpdate () {
    if (target)
    {
        Vector3 posNoZ = transform.position;
        posNoZ.z = target.transform.position.z;

        Vector3 targetDirection = (target.transform.position - posNoZ);

        interpVelocity = targetDirection.magnitude * 5f;

        targetPos = transform.position + (targetDirection.normalized * interpVelocity * Time.deltaTime); 

        transform.position = Vector3.Lerp( transform.position, targetPos + offset, 0.25f);

    }
  }
 }
相关问题