一直很喜歡仙劍系列遊戲,覺得仙劍的人物控制也很順手,學習了Unity後就很想做一個類似於仙劍的人物控制方案。
又特地重玩了仙劍三,現將仙劍三的人物控制操作羅列如下:
鍵盤A:面向Y軸的順時針旋轉鏡頭,觀察人物;(我這裏的面向Y軸,就是指的從上向下看)
鍵盤D:面向Y軸的逆時針旋轉鏡頭,觀察人物;
鍵盤↑、↓、←、→:前後左右移動人物(需要注意的是:這裏的前後左右是相對於鏡頭當前朝向方向的前後左右,其實就是在鏡頭所在的座標軸下進行移動)
雙擊上述按鍵:跑
鼠標滾軸順時針滾動(從鼠標右側觀察的順時針):效果等同鍵盤A;
鼠標滾軸逆時針滾動(從鼠標右側觀察的逆時針):效果等同鍵盤D;
鼠標左鍵單擊:地圖選點人物向選點走動;
鼠標左鍵雙擊:地圖選點人物向選點跑動;
我對於以上操作做了如下改動:
1.定義W/D來控制鏡頭向下和鏡頭向上轉;
2.用Shitf來代替鍵盤雙擊與鼠標雙擊進行的跑動控制
3.代碼中只考慮人物在X-Z軸平面上的移動,也就是說,人物只會繞着Y軸進行旋轉
以下是兩部分的代碼,所有需要注意的內容都在註釋中也明瞭。
綁定到mainCamera上的代碼:
using UnityEngine;
using System.Collections;
public class mainCameraForXianjian : MonoBehaviour {
//遊戲對象-主角色
private GameObject target = null;
//鏡頭距離主角的距離
public float distance = 2.0f;
//縱向最大觀察角度(相當於限定了俯視的最大角度)
private float maxAngleInXAxis = 80;
//縱向最小觀察角度(相當於限定了仰視的最大角度)
private float minAngleInXAxis = -20;
//橫向鏡頭角度
private float x = 0;
//縱向鏡頭角度
private float y = 0;
// Use this for initialization
void Start () {
//查找主角
target = GameObject.Find ("rule");
if (target == null) {
return;
}
//初始化鏡頭角度
x = target.transform.eulerAngles.y;
y = target.transform.eulerAngles.x;
}
// Update is called once per frame
void LateUpdate () {
if (target == null) {
return;
}
//定義:Ctrl + 鼠標滾軸 爲調整鏡頭距主角距離(從鼠標右側觀察鼠標,滾軸順時針拉近鏡頭,滾軸逆時針拉遠鏡頭)
if (Input.GetKey (KeyCode.LeftControl) || Input.GetKey (KeyCode.RightControl)) {
distance -= Input.GetAxis ("Mouse ScrollWheel") * 2.0f;//從鼠標右側觀察鼠標,滾軸順時針值爲正,逆時針值爲負,之所以“-=”就是想順時針拉近鏡頭
}
//x -= Input.GetAxis ("Mouse X") * 4.0f;
//y += Input.GetAxis ("Mouse Y") * 1.5f;
//定義:DirectikonHorizontal爲方向橫向輸入量,W/A/S/D分別代表鏡頭繞着角色看角色上面、左邊、下面、右邊
x -= Input.GetAxis ("DirectionHorizontal");
y -= Input.GetAxis ("DirectionVertical");
//定義:鼠標滾軸,爲從鼠標右側觀察鼠標,滾軸順時針繞着角色觀察角色左邊
if (!Input.GetKey (KeyCode.LeftControl) && !Input.GetKey (KeyCode.RightControl)) {
x += Input.GetAxis ("Mouse ScrollWheel") * 10;
}
//限定縱向觀察角色的視覺範圍
y = ClaimValue(y, maxAngleInXAxis, minAngleInXAxis);
Quaternion rotation = Quaternion.Euler(new Vector3 (y, x, 0));
//計算鏡頭最新位置
Vector3 position = Quaternion.Euler (y, x, 0) * (new Vector3 (0, 0, -distance)) + target.transform.position;
gameObject.transform.rotation = rotation;
gameObject.transform.position = position;
}
float ClaimValue(float value, float maxValue, float minValue)
{
if (value < -360) {
value += 360;
}
if (value > 360) {
value -= 360;
}
return Mathf.Clamp (value, minValue, maxValue);
}
}
using UnityEngine;
using System.Collections;
public class NewBehaviourScript : MonoBehaviour {
//角色移動方向
public const int HERO_UP = 0;
public const int HERO_RIGHT = 1;
public const int HERO_DOWN = 2;
public const int HERO_LEFT = 3;
public int state = 0;
//角色跑動時的速度
public int runSpeed = 15;
//角色走動時的速度
public int moveSpeed = 10;
//當前角色移動速度(默認爲走動)
private int curSpeed = 10;
//當前角色動畫名稱
private string animState = "walk";
//當前角色是否在進行鼠標點選移動
private bool bMouseMove = false;
//鼠標點選的目標位置
private Vector3 targetPos = Vector3.zero;
public void Awake()
{
state = HERO_UP;
}
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
//定義:Shift 代表移動模式爲run
if (Input.GetKey (KeyCode.LeftShift) || Input.GetKey (KeyCode.RightShift)) {
animState = "run";
curSpeed = runSpeed;
} else {
animState = "walk";
curSpeed = moveSpeed;
}
/*******************************************************************************************/
/**********************************鼠標點選移動模式*******************************************/
//鼠標左鍵:角色向鼠標指向位置移動
if (Input.GetMouseButton(0)) {
Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast (ray, out hit)) {
//設置當前爲鼠標點選移動模式
bMouseMove = true;
targetPos = new Vector3 (hit.point.x, gameObject.transform.position.y, hit.point.z);
//調整角色面向目的地
gameObject.transform.LookAt (targetPos);
}
}
//在鼠標點選移動模式下,角色不停地向目的地前進
if (bMouseMove) {
//播放動畫
gameObject.GetComponent<Animation> ().Play (animState);
//如果角色臨界目的地,則移動角色到目的地,並停止移動
if ((Vector3.Distance (gameObject.transform.position, targetPos)) <= curSpeed * Time.deltaTime) { //Vector3.Distance(gameObject.transform.position, targetPos) < (float)curSpeed
gameObject.transform.position = targetPos;
bMouseMove = false;
} else {
//由於人物方向已經確定好了,所以以自身座標系向目的地前進
gameObject.transform.Translate (Vector3.forward * curSpeed * Time.deltaTime, Space.Self);
}
}
/*******************************************************************************************/
/**********************************鍵盤移動模式**********************************************/
//定義:MoveVertical爲UP/DOWN鍵;MoveHorizontal爲RIGHT/LEFT鍵
float KeyVertical = Input.GetAxis ("MoveVertical");
float KeyHorizontal = Input.GetAxis ("MoveHorizontal");
if (KeyVertical == 1) {
setHeroState (HERO_DOWN);
} else if (KeyVertical == -1) {
setHeroState(HERO_UP);
}
if (KeyHorizontal == 1) {
setHeroState (HERO_RIGHT);
} else if (KeyHorizontal == -1) {
setHeroState(HERO_LEFT);
}
if ((KeyVertical == 0 && KeyHorizontal == 0) && !bMouseMove) {
gameObject.GetComponent<Animation>().Play ();
}
}
//控制角色移動一次
public void setHeroState(int newState)
{
bMouseMove = false;
//gameObject.transform.rotation = Quaternion.Euler(0, Camera.main.transform.eulerAngles.y, 0) ;
gameObject.transform.rotation = Quaternion.Euler(0, Camera.main.transform.eulerAngles.y + (int)newState * 90, 0) ;
int rotateValue = 0;
Vector3 transformValue = new Vector3 ();
gameObject.GetComponent<Animation> ().Play (animState);
//獲取當前鏡頭的歐拉角
Vector3 newVector3 = Camera.main.transform.rotation.eulerAngles;
//將歐拉角的x/z置空,因爲這裏只考慮角色在Y軸上的旋轉
newVector3.x = 0;
newVector3.z = 0;
//將角色旋轉的歐拉角轉換爲四元數,以便對目標向量進行旋轉
Quaternion quter = Quaternion.Euler (newVector3);
switch (newState) {
case HERO_UP:
//quter乘以Vector3.forward的目的是:將角色行進方向旋轉到鏡頭的方向
transformValue = quter * Vector3.forward * Time.deltaTime;
//rotateValue = 0;
break;
case HERO_DOWN:
transformValue = quter * (-Vector3.forward) * Time.deltaTime;
//rotateValue = 180;
break;
case HERO_LEFT:
transformValue = quter * Vector3.left * Time.deltaTime;
//rotateValue = 270;
break;
case HERO_RIGHT:
transformValue = quter * (-Vector3.left) * Time.deltaTime;
//rotateValue = 90;
break;
}
/* 我當是本來想用以下這部分代碼的,但是由於通過Camera.main.transform.TransformDirection得到的方向中還可能含有沿X/Z軸的旋轉量還需要處理,比較麻煩
* 簡單來說,舉個例子:如果鏡頭是在X軸上有個30度的旋轉量,那麼當控制人物向前走的時候,人物就會向前下方30°走
switch (newState) {
case HERO_UP:
//quter乘以Vector3.forward的目的是:將角色行進方向旋轉到鏡頭的方向
transformValue = Camera.main.transform.TransformDirection(Vector3.forward) * Time.deltaTime;
//rotateValue = 0;
break;
case HERO_DOWN:
transformValue = Camera.main.transform.TransformDirection(-Vector3.forward) * Time.deltaTime;
//rotateValue = 180;
break;
case HERO_LEFT:
transformValue = Camera.main.transform.TransformDirection(Vector3.left) * Time.deltaTime;
//rotateValue = 270;
break;
case HERO_RIGHT:
transformValue = Camera.main.transform.TransformDirection(-Vector3.left) * Time.deltaTime;
//rotateValue = 90;
break;
}
*/
//gameObject.GetComponent<Transform> ().Rotate (Vector3.up, rotateValue);
//將角色在指定方向在世界座標下位移
gameObject.GetComponent<Transform> ().Translate (transformValue * curSpeed, Space.World);
state = newState;
}
}