該源代碼轉載自Unity遊戲案例中的TANKS代碼中
------------來自第二次使用Unity3D製作遊戲的遊戲製作新人小白
一、代碼自我解析
二、油管學習地址
三、Unity3D源代碼
一、源代碼自我解析
using UnityEngine;
public class CameraControl : MonoBehaviour
{
public float m_DampTime = 0.2f; // 攝像機延遲移動時間係數
public float m_ScreenEdgeBuffer = 4f; // 在最上面/下面的目標和屏幕邊緣之間的空間(邊緣緩衝區大小)
public float m_MinSize = 6.5f; // 正交攝像機所能看的最小尺寸
/*[HideInInspector]*/ 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<Camera>(); // 遊戲一開始便使m_Camera對象獲取場景中的相機
}
private void FixedUpdate()
{
// 移動相機
Move();
// 改變相機的焦距大小
Zoom();
}
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++)
{
// 如果目標不存在,跳過並繼續執行for循環
if (!m_Targets[i].gameObject.activeSelf)
continue;
// 通過添加到平均值中,並在平均值中增加目標的數量。
averagePos += m_Targets[i].position;
numTargets++;
}
// 檢測目標數是否大於0若是便計算出平均的位置
if (numTargets > 0)
averagePos /= numTargets;
// 保持y值不變,坦克不會飛,所以y一定不能改變
averagePos.y = transform.position.y;
// 計算出來的平均位置就是相機要移動到的位置
m_DesiredPosition = averagePos;
}
private void Zoom()
{
// 根據所需的位置找到所需的大小,並順利過渡到該大小。
float requiredSize = FindRequiredSize();
m_Camera.orthographicSize = Mathf.SmoothDamp(m_Camera.orthographicSize, requiredSize, ref m_ZoomSpeed, m_DampTime);
}
private float FindRequiredSize()
{
// 找到相機設備在其本地空間中移動的位置。
Vector3 desiredLocalPos = transform.InverseTransformPoint(m_DesiredPosition);
// 將相機變焦大小初始值設爲0
float size = 0f;
// 遍歷一遍相機照射目標
for (int i = 0; i < m_Targets.Length; i++)
{
// 如果目標不存在,跳過並繼續執行for循環
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;
}
public void SetStartPositionAndSize()
{
// 找到期望位置
FindAveragePosition();
// 在沒有阻尼時設置相機位置到期望位置(阻尼即相機的緩衝)個人理解類似摩擦力之類的使得相機移動更平滑
transform.position = m_DesiredPosition;
m_Camera.orthographicSize = FindRequiredSize();
}
}
// 以上只是自己對於該代碼的理解,如有誤還望指出讓我及時改正。
二、油管學習Unity地址
https://www.youtube.com/watch?v=paLLfWd2k5A
三、Unity3D中該案例源代碼:
using UnityEngine;
namespace Complete
{
public class CameraControl : MonoBehaviour
{
public float m_DampTime = 0.2f; // Approximate time for the camera to refocus.
public float m_ScreenEdgeBuffer = 4f; // Space between the top/bottom most target and the screen edge.
public float m_MinSize = 6.5f; // The smallest orthographic size the camera can be.
[HideInInspector] public Transform[] m_Targets; // All the targets the camera needs to encompass.
private Camera m_Camera; // Used for referencing the camera.
private float m_ZoomSpeed; // Reference speed for the smooth damping of the orthographic size.
private Vector3 m_MoveVelocity; // Reference velocity for the smooth damping of the position.
private Vector3 m_DesiredPosition; // The position the camera is moving towards.
private void Awake ()
{
m_Camera = GetComponentInChildren<Camera> ();
}
private void FixedUpdate ()
{
// Move the camera towards a desired position.
Move ();
// Change the size of the camera based.
Zoom ();
}
private void Move ()
{
// Find the average position of the targets.
FindAveragePosition ();
// Smoothly transition to that position.
transform.position = Vector3.SmoothDamp(transform.position, m_DesiredPosition, ref m_MoveVelocity, m_DampTime);
}
private void FindAveragePosition ()
{
Vector3 averagePos = new Vector3 ();
int numTargets = 0;
// Go through all the targets and add their positions together.
for (int i = 0; i < m_Targets.Length; i++)
{
// If the target isn't active, go on to the next one.
if (!m_Targets[i].gameObject.activeSelf)
continue;
// Add to the average and increment the number of targets in the average.
averagePos += m_Targets[i].position;
numTargets++;
}
// If there are targets divide the sum of the positions by the number of them to find the average.
if (numTargets > 0)
averagePos /= numTargets;
// Keep the same y value.
averagePos.y = transform.position.y;
// The desired position is the average position;
m_DesiredPosition = averagePos;
}
private void Zoom ()
{
// Find the required size based on the desired position and smoothly transition to that size.
float requiredSize = FindRequiredSize();
m_Camera.orthographicSize = Mathf.SmoothDamp (m_Camera.orthographicSize, requiredSize, ref m_ZoomSpeed, m_DampTime);
}
private float FindRequiredSize ()
{
// Find the position the camera rig is moving towards in its local space.
Vector3 desiredLocalPos = transform.InverseTransformPoint(m_DesiredPosition);
// Start the camera's size calculation at zero.
float size = 0f;
// Go through all the targets...
for (int i = 0; i < m_Targets.Length; i++)
{
// ... and if they aren't active continue on to the next target.
if (!m_Targets[i].gameObject.activeSelf)
continue;
// Otherwise, find the position of the target in the camera's local space.
Vector3 targetLocalPos = transform.InverseTransformPoint(m_Targets[i].position);
// Find the position of the target from the desired position of the camera's local space.
Vector3 desiredPosToTarget = targetLocalPos - desiredLocalPos;
// Choose the largest out of the current size and the distance of the tank 'up' or 'down' from the camera.
size = Mathf.Max(size, Mathf.Abs(desiredPosToTarget.y));
// Choose the largest out of the current size and the calculated size based on the tank being to the left or right of the camera.
size = Mathf.Max(size, Mathf.Abs(desiredPosToTarget.x) / m_Camera.aspect);
}
// Add the edge buffer to the size.
size += m_ScreenEdgeBuffer;
// Make sure the camera's size isn't below the minimum.
size = Mathf.Max (size, m_MinSize);
return size;
}
public void SetStartPositionAndSize ()
{
// Find the desired position.
FindAveragePosition ();
// Set the camera's position to the desired position without damping.
transform.position = m_DesiredPosition;
// Find and set the required size of the camera.
m_Camera.orthographicSize = FindRequiredSize ();
}
}
}