Unity學習筆記——俯瞰視角攝像機指令碼

NO IMAGE

 適用於2.5D模擬經營、戰旗策略類遊戲攝像機指令碼,需要獲取主攝像機Main Camera物件和地形terrain物件,攝像機初始位置基於地圖的尺寸設定在地圖上空中心位置,並且x軸旋轉45度俯瞰地圖。

 實現了縮放攝像機(拉遠、拉近)方法、WASD移動攝像機方法、按住滑鼠右鍵旋轉攝像機方法和限制攝像機移動範圍方法。其中限制攝像機移動範圍方法並不準確,需要獲得攝像機視口範圍即視野和地圖相交的座標資訊,因為高度增加攝像機視野會變大,不同高度的攝像機被限制的範圍應和高度建立聯絡,解決這一問題涉及了較深數學知識,先按下不表,使用簡單的範圍限制。

 完成這一指令碼對擴充了我的以下知識點:

 1.Mathf.Sin等三角函式引數為弧度,需要把角度進行轉換後傳入

 2. 地形尺寸獲取即獲取地形的碰撞器的尺寸

 3.攝像機位置只能對position進行賦值、加減等操作,不能單獨對position的x、y、z變數操作,因此需要宣告一個Vector3變數,對此變數進行操作,再傳給攝像機座標

 4.Input.GetAxis(“Vertical”)、Input.GetAxis(“Horizontal”)返回的是1或-1,使用該封裝可以簡化按鍵事件,但如果提供修改鍵位功能還是需要老老實實寫wasd等按鍵的事件

 5.旋轉攝像機後再移動攝像機並不會按照攝像機方向移動,仍然會按照世界座標系移動,因此移動攝像機演算法中,不能使用對攝像機座標的x、y、z直接加減,要使用攝像機座標直接加減Vector3變數,該變數需要乘以transform.forward或transform.right方向向量,考慮到攝像機的x軸旋轉了一定角度,需要把forward、right賦值為另一個Vector3變數,將其y變數賦為0,就使攝像機按照朝向的水平方向移動了

 6.由於攝像機是自由移動的,沒有target作為目標點,縮放就不能使用修改distance的方法,在試過很多錯誤道路後,我發現縮放的實現和移動唯一的不同就是把將y變數賦為0這一步取消

指令碼內容如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraControl : MonoBehaviour {
public GameObject mainCamera;//獲取攝像機
public GameObject terrain;//獲取地圖
public float rollAngle=45;//攝像機傾斜角度
public float height=40f;//攝像機和地圖的高度差
public float moveSpeed = 1.5f;//攝像機移動速度係數
public float maxRangeX;//攝像機x座標變化範圍
public float minRangeX;
public float maxRangeZ;//攝像機z座標變化範圍
public float minRangeZ;
public float maxRangeY = 75f;//縮放最大高度
public float minRangeY = 30f;//縮放最小高度
public float zoomSpeed = 5f;//縮放速度係數
public float rotateAngle = 0;
public float rotateSpeed=100f;//旋轉速度係數
Vector3 cameraPos;//攝像機臨時座標
public float sizeX;//地圖尺寸x
public float sizeZ;//地圖尺寸z
void Start () {
//獲取地圖尺寸
sizeX = terrain.GetComponent<TerrainCollider>().bounds.size.x;
sizeZ = terrain.GetComponent<TerrainCollider>().bounds.size.z;
maxRangeX = terrain.transform.position.x   0.75f * sizeX;
minRangeX = terrain.transform.position.x   0.25f * sizeX;
maxRangeZ = terrain.transform.position.z   0.75f * sizeZ;
minRangeZ = terrain.transform.position.z   0.25f * sizeZ;
//設定攝像機位置
cameraPos.x = terrain.transform.position.x    sizeX/ 2 ;
cameraPos.y = terrain.transform.position.y   height;
cameraPos.z = terrain.transform.position.z    sizeZ/ 2 ;
mainCamera.transform.position = cameraPos;
mainCamera.transform.eulerAngles = new Vector3(rollAngle, 0, 0);
Debug.Log("地圖尺寸為:"   sizeX   "X"   sizeZ);
}
void Update () {
//更新攝像機座標
MoveCamera();
RotateCamera();
ZoomCamera();
LimitRange();
mainCamera.transform.position = cameraPos;
}
void MoveCamera() {
//第一種方法按下WS、AD,Input.GetAxis()會返回1或-1
float moveZ = Input.GetAxis("Vertical");
Vector3 moveDirectionZ = transform.forward;
moveDirectionZ.y = 0;
cameraPos  = moveDirectionZ * moveZ * moveSpeed;
float moveX = Input.GetAxis("Horizontal");
Vector3 moveDirectionX = transform.right;
moveDirectionZ.y = 0;
cameraPos  = moveDirectionX * moveX * moveSpeed;
//按下shift加速移動攝像機
if (Input.GetKey(KeyCode.LeftShift))
moveSpeed = 2.5f;
if (Input.GetKeyUp(KeyCode.LeftShift))
moveSpeed = 1.5f;
}
void ZoomCamera() {
//滾動滑鼠滑輪縮放攝像機
if (Input.GetAxis("Mouse ScrollWheel") > 0) {
if (cameraPos.y < minRangeY)
return;
Vector3 moveDirectionZ = transform.forward;
cameraPos  = moveDirectionZ * zoomSpeed;
}
if (Input.GetAxis("Mouse ScrollWheel") <0) {
if (cameraPos.y > maxRangeY)
return;
Vector3 moveDirectionZ = -transform.forward;
cameraPos  = moveDirectionZ * zoomSpeed;
}
}
void RotateCamera() {
//按下滑鼠右鍵旋轉攝像機
if (Input.GetMouseButton(1)) {
rotateAngle = Input.GetAxis("Mouse X")*rotateSpeed*Time.deltaTime;
mainCamera.transform.Rotate(0,rotateAngle,0,Space.World);
}
}
void LimitRange() {
//攝像機移動範圍限制
if (cameraPos.x > maxRangeX)
cameraPos.x = maxRangeX;
if (cameraPos.x < minRangeX)
cameraPos.x = minRangeX;
if (cameraPos.z > maxRangeZ)
cameraPos.z = maxRangeZ;
if (cameraPos.z < minRangeZ)
cameraPos.z = minRangeZ;
}
}