三、相机控制
1.在Hierarchy面板创建空物体命名CameraRig作为相机父物体,Position(0,0,0),Rotation(40,60,0);
2.把相机拖到CameraRig物体下作为子物体,Position(0,0,-65),Rotation(0,0,0);
3.确保相机是正交模式
4.拖入CameraControl脚本到相机父物体上,脚本:
using UnityEngine;
public class CameraControl : MonoBehaviour
{
public float m_DampTime = 0.2f; //相机移动时间(缓慢移动而不是直接到达)
public float m_ScreenEdgeBuffer = 4f; //确保坦克们都在屏幕中间
public float m_MinSize = 6.5f;
public Transform[] m_Targets; //相机观察的目标
private Camera m_Camera;
private float m_ZoomSpeed;
private Vector3 m_MoveVelocity;
private Vector3 m_DesiredPosition; //目标位置
private void Awake()
{
m_Camera = GetComponentInChildren();//获取组件
}
private void FixedUpdate()
{
Move(); //移动相机
Zoom();//设置相机size
}
private void Move()
{
//找到相机观察的目标们的中间位置,也就是相机的运动目标位置
FindAveragePosition();
//平缓移动相机到中间位置
transform.position = Vector3.SmoothDamp(transform.position, m_DesiredPosition, ref m_MoveVelocity, m_DampTime);
}
//计算相机观察的目标们的平均位置(中间位置)
private void FindAveragePosition()
{
Vector3 averagePos = new Vector3();
int numTargets = 0;
for (int i = 0; i < m_Targets.Length; i++)
{
if (!m_Targets[i].gameObject.activeSelf)
continue;//退出本次循环开始下次循环
//显示着的所有目标、
averagePos += m_Targets[i].position;
numTargets++;
}
//计算几个目标位置的平均位置(中间位置)
if (numTargets > 0)
averagePos /= numTargets;
//竖直位置保持不变
averagePos.y = transform.position.y;
m_DesiredPosition = averagePos;
}
private void Zoom()
{
//计算需要的相机的size
float requiredSize = FindRequiredSize();
//目标时间内缓慢改变相机的size到目标值
m_Camera.orthographicSize = Mathf.SmoothDamp(m_Camera.orthographicSize, requiredSize, ref m_ZoomSpeed, m_DampTime);
}
//计算需要的相机的size(难点)
private float FindRequiredSize()
{
//世界坐标转为本地坐标
Vector3 desiredLocalPos = transform.InverseTransformPoint(m_DesiredPosition);
float size = 0f;
//遍历所有目标,计算所有需要的size,找出最大size
for (int i = 0; i < m_Targets.Length; i++)
{
if (!m_Targets[i].gameObject.activeSelf)
continue;
Vector3 targetLocalPos = transform.InverseTransformPoint(m_Targets[i].position);
Vector3 desiredPosToTarget = targetLocalPos - desiredLocalPos;
size = Mathf.Max (size, Mathf.Abs (desiredPosToTarget.y));
size = Mathf.Max (size, Mathf.Abs (desiredPosToTarget.x) / m_Camera.aspect);
}
size += m_ScreenEdgeBuffer;
size = Mathf.Max(size, m_MinSize);
return size;
}
//给外部调用,设置相机位置和size
public void SetStartPositionAndSize()
{
FindAveragePosition();
transform.position = m_DesiredPosition;
m_Camera.orthographicSize = FindRequiredSize();
}
}
设置相机size的过程可能难一点,看一下下面的知识点,然后慢慢理解。
----------------------------------------------------------------------------------------------------------------------------------------------------------------
重要点1:关于相机
相机Projection参数区分了相机是透视类型还是正交类型,如下图:
透视类型有近大远小的效果,而正交类型远近一样大。
所谓aspect就是屏幕的横纵比:
重要点2:Transform.InverseTransformPoint
变换位置从世界坐标到自身坐标。获取参数pos相对于物体的坐标位置。
和Transform.TransformPoint相反。
注意,返回位置受缩放影响。如果你是处理方向使用Transform.InverseTransformDirection。
e.g.:
using UnityEngine;
using System.Collections;
//把世界坐标转为相对物体的坐标,然后看相对位置
public class example : MonoBehaviour {
public Transform cam = Camera.main.transform;
public Vector3 cameraRelative = cam.InverseTransformPoint(transform.position);
public void Awake() {
if (cameraRelative.z > 0)
print("The object is in front of the camera");
else
print("The object is behind the camera");
}
}
----------------------------------------------------------------------------------------------------------------------------------------------------------------