
曾幾何時(shí)一直癡迷著手游,特別是3D的游戲,繼而在學(xué)過(guò)游戲開發(fā)之后對(duì)其中的技術(shù)實(shí)現(xiàn)也是充滿了好奇。今天帶來(lái)的就是對(duì)游戲角色的至關(guān)重要的相機(jī)系統(tǒng)的基礎(chǔ)實(shí)現(xiàn),當(dāng)然基于目前技術(shù)水平所限制,我分享的其實(shí)也不是很難的東西哈。
相機(jī)系統(tǒng)的大概了解
所謂的相機(jī)系統(tǒng)其實(shí)也就是對(duì)相機(jī)的管理,想想當(dāng)初玩游戲通過(guò)屏幕手勢(shì)對(duì)游戲角色的各方面觀察,這也就是我們普遍意義上的相機(jī)系統(tǒng),當(dāng)然這算是比較簡(jiǎn)單的一種,我們所要實(shí)現(xiàn)的就是通過(guò)屏幕終端手勢(shì)來(lái)控制游戲中的相機(jī)。
效果圖

有童鞋可能不明白我在屏幕上干了啥,這里說(shuō)明下,其實(shí)也就是上下左右滑動(dòng)和鼠標(biāo)滾輪滾動(dòng)而已,然后實(shí)現(xiàn)的結(jié)果就是圖中所示。
實(shí)現(xiàn)原理概括
其實(shí)從效果圖中就能看出,我所做的操作無(wú)非手勢(shì)的不同,所對(duì)應(yīng)的就是相機(jī)的狀態(tài)改變,換作代碼邏輯也很好分析。
首先我需要有監(jiān)聽屏幕上下左右滑動(dòng)的事件,鼠標(biāo)滾輪的觸發(fā)事件,事件有了之后就需要對(duì)相機(jī)進(jìn)行控制,相機(jī)的控制類型無(wú)非旋轉(zhuǎn)和位移兩種。(上下左右滑動(dòng)對(duì)應(yīng)相機(jī)的旋轉(zhuǎn),位移對(duì)應(yīng)著鼠標(biāo)滾輪滾動(dòng))做完這些其實(shí)也就剩不了什么了,這里需要提的一點(diǎn)是,相機(jī)結(jié)構(gòu)的構(gòu)造比較重要,僅僅只依靠一個(gè)相機(jī)我感覺(jué)不好操作,所以這里提供了一個(gè)相機(jī)結(jié)構(gòu)參考,如下圖
相機(jī)結(jié)構(gòu)介紹完了,那么整體的相機(jī)系統(tǒng)的原理也差不多了,接下來(lái)可以看看代碼實(shí)現(xiàn)。
關(guān)鍵代碼演示
首先可以看下整個(gè)系統(tǒng)的事件監(jiān)聽,這里導(dǎo)入了手勢(shì)插件FingerGestures
public class FingerEvent : MonoBehaviour
{
public static FingerEvent Instance;
public enum FingerDir
{
Up,
Down,
Left,
Right
}
/// <summary>
/// 滑動(dòng)委托
/// </summary>
public Action<FingerDir> OnFingerDrag;
public enum ZoomType
{
In,
Out
}
/// <summary>
/// 縮放的委托
/// </summary>
public Action<ZoomType> OnZoom;
private Vector2 m_TempFinger1Pos;
private Vector2 m_TempFinger2Pos;
private Vector2 m_OldFinger1Pos;
private Vector2 m_OldFinger2Pos;
/// <summary>
/// 玩家點(diǎn)擊地面的委托
/// </summary>
public Action OnPlayerClickGround;
/// <summary>
/// 拖動(dòng)的舊位置
/// </summary>
private Vector2 m_OldDragPos;
/// <summary>
/// 拖動(dòng)的方向
/// </summary>
private Vector2 m_DragDir;
/// <summary>
/// 交互參數(shù)
/// </summary>
private int m_PreFinger = -1;
void Awake()
{
Instance = this;
}
void OnEnable()
{
//啟動(dòng)時(shí)調(diào)用,這里開始注冊(cè)手勢(shì)操作的事件。
//按下事件: OnFingerDown就是按下事件監(jiān)聽的方法,這個(gè)名子可以由你來(lái)自定義。方法只能在本類中監(jiān)聽。下面所有的事件都一樣?。?!
FingerGestures.OnFingerDown += OnFingerDown;
//開始拖動(dòng)事件
FingerGestures.OnFingerDragBegin += OnFingerDragBegin;
//拖動(dòng)中事件...
FingerGestures.OnFingerDragMove += OnFingerDragMove;
//拖動(dòng)結(jié)束事件
FingerGestures.OnFingerDragEnd += OnFingerDragEnd;
}
private void Update()
{
if (Input.GetAxis("Mouse ScrollWheel") < 0)
{
if (OnZoom != null)
{
OnZoom(ZoomType.Out);
}
}
else if (Input.GetAxis("Mouse ScrollWheel") > 0)
{
if (OnZoom != null)
{
OnZoom(ZoomType.In);
}
}
}
void OnDisable()
{
//關(guān)閉時(shí)調(diào)用,這里銷毀手勢(shì)操作的事件
//和上面一樣
FingerGestures.OnFingerDown -= OnFingerDown;
FingerGestures.OnFingerDragBegin -= OnFingerDragBegin;
FingerGestures.OnFingerDragMove -= OnFingerDragMove;
FingerGestures.OnFingerDragEnd -= OnFingerDragEnd;
}
//按下時(shí)調(diào)用
void OnFingerDown(int fingerIndex, Vector2 fingerPos)
{
m_PreFinger = 1;
}
//開始滑動(dòng)
void OnFingerDragBegin(int fingerIndex, Vector2 fingerPos, Vector2 startPos)
{
m_PreFinger = 2;
m_OldDragPos = fingerPos;
}
//滑動(dòng)結(jié)束
void OnFingerDragEnd(int fingerIndex, Vector2 fingerPos)
{
m_PreFinger = 4;
}
//滑動(dòng)中
void OnFingerDragMove(int fingerIndex, Vector2 fingerPos, Vector2 delta)
{
m_PreFinger = 3;
m_DragDir = fingerPos - m_OldDragPos;
if (m_DragDir.y < m_DragDir.x && m_DragDir.y > -m_DragDir.x)
{
//向右
if (OnFingerDrag != null)
{
OnFingerDrag(FingerDir.Right);
}
}
else if (m_DragDir.y > m_DragDir.x && m_DragDir.y < -m_DragDir.x)
{
//向左
if (OnFingerDrag != null)
{
OnFingerDrag(FingerDir.Left);
}
}
else if (m_DragDir.y > m_DragDir.x && m_DragDir.y > -m_DragDir.x)
{
//向上
if (OnFingerDrag != null)
{
OnFingerDrag(FingerDir.Up);
}
}
else
{
//向下
if (OnFingerDrag != null)
{
OnFingerDrag(FingerDir.Down);
}
}
}
}
然后就是我們的相機(jī)控制邏輯了,其實(shí)也就是針對(duì)我們之前的相機(jī)結(jié)構(gòu)來(lái)的,運(yùn)用的也就是transform里頭的東西
public class CameraCtr : MonoBehaviour {
public static CameraCtr Instance;
/// <summary>
/// 控制攝像機(jī)上下
/// </summary>
[SerializeField]
private Transform m_CameraUpAndDown;
/// <summary>
/// 控制攝像機(jī)縮放父物體
/// </summary>
[SerializeField]
private Transform m_CameraZoomContainer;
/// <summary>
/// 攝像機(jī)容器
/// </summary>
[SerializeField]
private Transform m_CameraContainer;
void Awake()
{
Instance = this;
}
/// <summary>
/// 初始化
/// </summary>
public void Init()
{
m_CameraUpAndDown.localEulerAngles = new Vector3(0, 0, Mathf.Clamp(m_CameraUpAndDown.localEulerAngles.z, 10f, 80f));
}
/// <summary>
/// 設(shè)置攝像機(jī)旋轉(zhuǎn)
/// </summary>
/// <param name="type">0=左 1=右</param>
public void SetCameraRotate(int type)
{
transform.Rotate(0,80*Time.deltaTime * (type == 1?-1:1),0);
}
/// <summary>
/// 設(shè)置攝像機(jī)上下
/// </summary>
/// <param name="type">0=上 1=下</param>
public void SetCameraUpAndDown(int type)
{
m_CameraUpAndDown.Rotate(0,0, 30 * Time.deltaTime * (type == 1 ? -1 : 1));
m_CameraUpAndDown.localEulerAngles = new Vector3(0,0,Mathf.Clamp(m_CameraUpAndDown.localEulerAngles.z,10f,80f));
}
/// <summary>
/// 設(shè)置攝像機(jī)縮放
/// </summary>
/// <param name="type">0=拉近 1=拉遠(yuǎn)</param>
public void SetCameraZoom(int type)
{
m_CameraContainer.Translate(Vector3.forward * 20 * Time.deltaTime * (type == 1 ? -1 : 1));
m_CameraContainer.localPosition = new Vector3(0, 0, Mathf.Clamp(m_CameraContainer.localPosition.z, -5f, 8f));
}
public void AutoLookAt(Vector3 pos)
{
m_CameraZoomContainer.LookAt(pos);
}
}
然后就沒(méi)有然后了,代碼中有注釋,看不懂可以多看幾遍哈!
代碼地址
具體代碼我已經(jīng)上傳Github,看這里
代碼上可能還存在些問(wèn)題,歡迎提出自己的意見(jiàn)。
總結(jié)
以前其實(shí)對(duì)相機(jī)系統(tǒng)不是很了解,而這篇分享也是基于目前我所學(xué)習(xí)的課程的筆記而已,也希望后面能更多得學(xué)習(xí)新的東西能拿出來(lái)分享。