Unity實現主角移動與攝像機跟隨
在遊戲開發中,主角需要通過跑地圖來通關升級,本章主要介紹主角的移動和攝像跟隨的操作。
主角移動
角色位移通過主角的骨骼動畫控制(後續文章會詳細介紹狀態機的使用),這裡隻需要勾選Animator動畫控制器下Apply Root Motion讓角色的移動受動畫控制。
通過碰撞檢測來判斷哪些位置主角可以移動,哪些位置角色不能行走,這裡需要兩個組件Rigidbody剛體,和Collider碰撞組件
- Rigidbody:為遊戲賦予物理屬性,在遊戲中隻有添加瞭剛體的物體才能模擬物理屬性,如重力等。
如上圖所示,各參數含義如下:
Mass 質量:單位任意。但是官方建議物體的質量差不要超過100倍
Drag 阻力:物體移動時受到的空氣阻力,0表示無阻力
Angular Drag 角阻力:當受扭力時物體旋轉時受到的空氣阻力,同樣0表示無阻力
Use Gravity 使用重力:表示該物體是否受重力影響
Is Kinematic 是否是運動學:遊戲對象是否遵循運動學規律,如果激活不在受物理引擎驅動(動畫控制移動,不勾選)
Interpolate 插值:物體運動的插值模式
Collision Detection 碰撞檢測:碰撞檢測模式。用於避免高速物體穿過其它物體未發生碰撞
Constraint 約束:對剛體運動的約束,可以鎖定位置和旋轉的x、y、z軸
- Collider:碰撞器有很多中,需要根據實際的需要選擇不同的觸發器,這裡隻是簡單的介紹其基礎功能
Is Trigger 觸發器:勾選該選項,碰撞用於觸發事件 OnTriggerEnter、OnTriggerExit、OnTriggerStay並被物理引擎所忽略
Input.GetAxis(args) :獲取移動方位。
float h = Input.GetAxis("Horizontal");//對應鍵盤的上下 float v = Input.GetAxis("Vertical");//對應鍵盤的左右
通過插值運算,控制主角平滑的轉向和移動:
void Update() { role.SetBool(StealthConst.SNEAK, Input.GetKey(KeyCode.LeftShift)); float h = Input.GetAxis("Horizontal"); float v = Input.GetAxis("Vertical"); if (Mathf.Abs(h) > 0.1f || Mathf.Abs(v) > 0.1f) { //5.6由動畫控制器中的參數決定 float currentSpeed = Mathf.Lerp(role.GetFloat(StealthConst.SPEED), 5.6f, moveSpeed * Time.deltaTime); role.SetFloat(StealthConst.SPEED, currentSpeed);//Animator通過速度控制移動的快慢 Vector3 targetDir = new Vector3(h, 0, v); //Vector3.up相當於(0,1,0)繞著Y軸,看向目標位置 Quaternion newRotation = Quaternion.LookRotation(targetDir, Vector3.up); transform.rotation = Quaternion.Lerp(transform.rotation, newRotation, rotateSpeed * Time.deltaTime); } else { role.SetFloat(StealthConst.SPEED, 0); } }
攝像機跟隨
攝像機跟隨的原理十分簡單,在場景設計中將相機和主角的相對位置保持固定,跟隨主角移動即可。但是有種特殊情況,當主角移動到墻邊,被遮擋後如果還是保持原來的相對位置,則視野中將觀察不到主角,這時需要動態的調整攝像機的位置。
這裡將采用射線碰撞的方式來檢查,從相機的位置開始,到主角正上方截止,平均劃分3個點,依次從五個點分別發射一條射線,當射線能直接碰到主角或者沒有碰到說明主角在攝像的范圍內,將攝像機平滑的移動到能夠看到主角的位置即可。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class FollowPlayer : MonoBehaviour { private Vector3 offset; public Transform role; public float moveSpeed = 3; public float rotateSpeed = 3; // Start is called before the first frame update void Start() { offset = transform.position - role.position; offset = new Vector3(0, offset.y, offset.z); } // Update is called once per frame void Update() { Vector3 beginPos = role.position + offset;//攝像機正常偏移位置,起點 Vector3 endPos = role.position + offset.magnitude * Vector3.up;//offset.magnitude向量的長度 ///從起點到終點分別取3個點,通過射線判斷攝像機是否有遮擋 Vector3[] posArr = new Vector3[] { beginPos, Vector3.Lerp(beginPos,endPos,0.25f), Vector3.Lerp(beginPos,endPos,0.5f), Vector3.Lerp(beginPos,endPos,0.75f), endPos }; Vector3 targetPos = posArr[0]; foreach (var pos in posArr) { RaycastHit hitInfo; ///第一個參數射線的起點,第二個參數射線的方向 if (Physics.Raycast(pos, role.position - pos, out hitInfo)) { if (hitInfo.collider.tag == StealthConst.PLAYER) { targetPos = pos; break; } else { continue; } } else { targetPos = pos; break; } } this.transform.position = Vector3.Lerp(transform.position,targetPos,Time.deltaTime*moveSpeed);//通過插值平滑移動 Quaternion nowRotation = transform.rotation; this.transform.LookAt(role.position);//攝像機轉向目標 this.transform.rotation = Quaternion.Lerp(nowRotation, transform.rotation, Time.deltaTime * rotateSpeed);//通過插曲平滑旋轉 } }
以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。