核心都是求出輸出input的移動方向乘以給定的速度乘以時間間隔,以一定角速度進行旋轉來計算。注意這裏的CamCtrl的rotation是和主角的forward前方是一致的。過段時間發Camera的設計試試看。
Unity 三種常用人物移動方式,手機觸屏移動,鍵盤移動,鼠標點擊移動,在不同類型的遊戲中就可能會用到,不過不管是哪種移動方式,都是根據玩家的輸入來獲得主角移動的朝向:x方向,y方向,在根據主角的角速度,移動速度來每幀改變主角的朝向和行走。
ET移動:
//使用ET Move
float axisXValue = _RoleFSMMgr.RoleCtrl.JoyStick.axisX.axisValue;
float axisYValue = _RoleFSMMgr.RoleCtrl.JoyStick.axisY.axisValue;
speed = (Mathf.Abs(axisXValue) >Math.Abs(axisYValue)) ? axisXValue : axisYValue; //選擇按的最大的哪一個按鍵來判斷主角是不是全力衝刺
speed = Mathf.Abs(speed);
if (axisXValue != 0 || axisYValue != 0)
{
Vector3 _Dir = new Vector3(axisXValue, 0, axisYValue);
_Dir = _Dir.normalized; //獲得方向
_Dir = CamCtrl.Instance.transform.rotation * _Dir;
Quaternion q = Quaternion.LookRotation(_Dir);
if (Quaternion.Angle(_RoleFSMMgr.RoleCtrl.transform.rotation, q) > 1)
{
_RotSpeed += 10 * Time.deltaTime;
_RoleFSMMgr.RoleCtrl.transform.rotation = Quaternion.Slerp(_RoleFSMMgr.RoleCtrl.transform.rotation, q, _RotSpeed);
}
else
{
_RotSpeed = 0;
}
_RoleFSMMgr.RoleCtrl.CC.Move(new Vector3(_Dir.x, _Gravity, _Dir.z) * _MoveSpeed * Time.deltaTime*speed);
}
手機上我都是使用EasyTouch的,放在有限狀態機中的RoleStateMove狀態腳本中,可以每幀的隨時更新主角的行動信息。這裏我的角速度是每幀加10*Time.deltaTime到1的時候就朝向一致了,我使用CharacterController的Move方法來控制移動,通過Gravity來讓主角一直處於地面,因爲攝像機也是有旋轉的,爲了讓角度的計算不是始終都是絕對座標軸來算,這裏特地乘以攝像機的旋轉,以攝像機視角爲前方計算。
鍵盤:
//使用KeyBoard Move
if (Input.GetAxis("Horizontal") != 0 || Input.GetAxis("Vertical") != 0)
{
float hh = Input.GetAxis("Horizontal");
float vv = Input.GetAxis("Vertical");
speed = (Mathf.Abs(hh)>Mathf.Abs(vv)) ? hh : vv;
speed = Mathf.Abs(speed);
_Dir = new Vector3(hh, 0, vv);
_Dir = _Dir.normalized;
_Dir = CamCtrl.Instance.transform.rotation * _Dir;
Quaternion q = Quaternion.LookRotation(_Dir);
if (Quaternion.Angle(_RoleFSMMgr.RoleCtrl.transform.rotation, q) > 1)
{
_RotSpeed += 10 * Time.deltaTime;
_RoleFSMMgr.RoleCtrl.transform.rotation = Quaternion.Slerp(_RoleFSMMgr.RoleCtrl.transform.rotation, q, _RotSpeed);
}
else
{
_RotSpeed = 0;
}
_RoleFSMMgr.RoleCtrl.CC.Move(new Vector3(_Dir.x,_Gravity,_Dir.z)*_MoveSpeed*Time.deltaTime*speed);
}
鍵盤除了獲得X,Y方向的方法不一樣以外,其餘都是和EasyTouch一樣的。
鼠標點擊:
//使用A* Path Auto Move
if (_RoleFSMMgr.RoleCtrl.APath!=null)
{
speed = 1;
if (_RoleFSMMgr.RoleCtrl.CurWayPointIndex>=_RoleFSMMgr.RoleCtrl.APath.vectorPath.Count)
{
_RoleFSMMgr.RoleCtrl.ToIdle();
_RoleFSMMgr.RoleCtrl.CurWayPointIndex = 1;
_RoleFSMMgr.RoleCtrl.APath = null;
return;
}
else
{
_NextPos = new Vector3(_RoleFSMMgr.RoleCtrl.APath.vectorPath[_RoleFSMMgr.RoleCtrl.CurWayPointIndex].x, _RoleFSMMgr.RoleCtrl.transform.position.y, _RoleFSMMgr.RoleCtrl.APath.vectorPath[_RoleFSMMgr.RoleCtrl.CurWayPointIndex].z);
_Dir = _NextPos - _RoleFSMMgr.RoleCtrl.transform.position;
_Dir = _Dir.normalized;
Quaternion q = Quaternion.LookRotation(_Dir);
if (Quaternion.Angle(_RoleFSMMgr.RoleCtrl.transform.rotation,q)>1)
{
_RotSpeed += 10 * Time.deltaTime;
_RoleFSMMgr.RoleCtrl.transform.rotation = Quaternion.Slerp(_RoleFSMMgr.RoleCtrl.transform.rotation,q,_RotSpeed);
}
else
{
_RotSpeed = 0;
}
_RoleFSMMgr.RoleCtrl.CC.Move(new Vector3(_Dir.x, _Gravity, _Dir.z) * _RoleFSMMgr.RoleCtrl.RoleInfo.MoveSpeed * Time.deltaTime * speed);
if (Vector3.Distance(_NextPos, _RoleFSMMgr.RoleCtrl.transform.position) < _RoleFSMMgr.RoleCtrl.RoleInfo.MoveSpeed * Time.deltaTime + .2f)
{
_RoleFSMMgr.RoleCtrl.CurWayPointIndex++;
}
}
}
鼠標點擊自然是要先通過A*計算出路徑來,根據下一個要行走的點和角色當前的位置算出移動的向量方向,再向前面說的那樣移動就好了,等到了目標點之後就要切換下一個目標點,直到終點讓路徑爲NULL。