RPG遊戲《黑暗之光》流程介紹與程式碼分析之(三):角色控制系統的實現
阿新 • • 發佈:2019-02-12
第三章:角色控制
本篇部落格主要對人物移動及其相關操作進行分析,主要包括主角以及鏡頭的移動。在遊戲介面中,我們使用Camera作為視角。為了方便之後判斷當前tag,我們新建一個Tag指令碼,存入一些tag資訊,之後呼叫就不容易出錯using UnityEngine; using System.Collections; public class Tags : MonoBehaviour { public const string ground = "Ground"; public const string player = "Player"; //新建角色與地面的tag資訊,之後還會新增物品等資訊 }
3.1 點選地板
Map中的Terrain可以判斷滑鼠是否點選到地面,因此我們向Map中拖入一個Magician,為它新增一個指令碼PlayerDirection,實現點選地板產生效果的功能。程式碼如下即可之後將點選效果匯入,即可實現using UnityEngine; using System.Collections; public class PlayerDirection : MonoBehaviour { public GameObject effect_click_prefab; // Update is called once per frame void Update () { if (Input.GetMouseButtonDown (0)) { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); //建立一個射線,將在Camera中點選的點轉化為一條射線 RaycastHit hitInfo; //建立碰撞資訊 bool isCollider = Physics.Raycast(ray,out hitInfo); //isCollider檢測是否碰撞,其中Physics.Raycast中的兩個形參表示射線以及碰撞資訊 if(isCollider && hitInfo.collider.tag == Tags.ground) //發生碰撞且碰撞的物體其Tag為ground { showClickEffect(hitInfo.point); //例項化點選效果 } } } void showClickEffect(Vector3 hitPoint) { hitPoint = new Vector3 (hitPoint.x, hitPoint.y + 0.1f, hitPoint.z); //將碰撞點的y向上移動一些,以完整顯示 GameObject.Instantiate (effect_click_prefab, hitPoint, Quaternion.identity); //建立一個例項,顯示點選資訊 } }
執行後,點選地面時即可產生碰撞效果。
3.2 角色朝向
在獲取點選目標後,我們需要控制角色朝向目標區域。對PlayerDirection修改如下private bool isMoving = false; public Vector3 targetPosition = Vector3.zero; // Update is called once per frame void Update () { if (Input.GetMouseButtonDown (0)) //這裡是判斷是否按下 { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hitInfo; bool isCollider = Physics.Raycast(ray,out hitInfo); if(isCollider && hitInfo.collider.tag == Tags.ground) { isMoving = true; ShowClickEffect(hitInfo.point); LookAtTarget(hitInfo.point); //將朝向設定為一個方法 } } if(Input.GetMouseButtonUp(0)) //是否擡起 { isMoving = false; } if (isMoving) //是否持續按下 { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hitInfo; bool isCollider = Physics.Raycast(ray,out hitInfo); if(isCollider && hitInfo.collider.tag == Tags.ground) { LookAtTarget(hitInfo.point); //持續朝向hitInfo.point } } } void LookAtTarget(Vector3 hitPoint) { targetPosition = hitPoint; //點選的位置資訊傳給 targetPosition targetPosition = new Vector3(targetPosition.x,transform.position.y,targetPosition.z); //不改變y軸資訊,別的資訊參照 targetPosition this.transform.LookAt(targetPosition); //改變朝向 } }
3.3 角色移動
為角色新增一個角色控制器,用以控制移動對Magician新增一個指令碼PlayerMove控制移動
using UnityEngine;
using System.Collections;
public class PlayerMove : MonoBehaviour {
public float speed = 3f;
private PlayerDirection dir;
private CharacterController controller;
void Start(){
dir = this.GetComponent<PlayerDirection> (); //獲取目標位置
controller = this.GetComponent<CharacterController> (); //為controller賦值
}
// Update is called once per frame
void Update () {
float distance = Vector3.Distance (dir.targetPosition, transform.position); //獲取目標位置與當前位置的距離
if (distance >= 0.1f) {
controller.SimpleMove(transform.forward*speed); //這裡的速度應帶有方向
}
}
}
即可,但是剛開始時的targetPosition處於(0,0,0),會直接移動,需要在PlayerDirection初始化targetPositio為初始人物的位置即targetPosition = transform.position;
實現移動效果如下3.4 動畫效果的加入
角色移動時應當有動畫,在Animation中,新增所有素材現在需要在PlayerMove中控制角色的狀態
3.5 角色狀態,站立,運動
在Magician下新建一個指令碼PlayerAnimation控制運動播放,首先在PlayerMove中指定站立或者運動的狀態資訊using UnityEngine;
using System.Collections;
public enum PlayerState{
Moving,
Idle
}
public class PlayerMove : MonoBehaviour {
public float speed = 3f;
public PlayerState state = PlayerState.Idle; //指定預設的Animation狀態是Idle
private PlayerDirection dir;
private CharacterController controller;
// Update is called once per frame
void Update () {
float distance = Vector3.Distance (dir.targetPosition, transform.position);
if (distance >= 0.05f)
{
state = PlayerState.Moving; //運動時state狀態變為Moving
}
else
{
state = PlayerState.Idle; //不運動時狀態為Idle
}
}
}
利用上述狀態的初始化,之後根據狀態變化在PlayerAnimation控制角色移動using UnityEngine;
using System.Collections;
public class PlayerAnimation : MonoBehaviour {
private PlayerMove move;
// Use this for initialization
void Start () {
move = this.GetComponent<PlayerMove> ();
}
// Update is called once per frame
void LateUpdate () {
if (move.state == PlayerState.Moving)
{
PlayAnim ("Run"); //對應下圖Run
}
else if (move.state == PlayerState.Idle)
{
PlayAnim("Idle"); //對應下圖Idle
}
}
void PlayAnim(string animName)
{
animation.CrossFade (animName); //播放對應的Animation
}
}
3.6 讓相機跟隨主角移動以及鏡頭的拉近拉遠
對Camera新增一個指令碼PlayerFollowusing UnityEngine;
using System.Collections;
public class PlayerFollow : MonoBehaviour {
private Transform player;
private Vector3 offsetPosition;
// Use this for initialization
void Start () {
player = GameObject.FindGameObjectWithTag (Tags.player).transform; //得到角色資訊
this.transform.LookAt (player.position); //使player處在Camera中心
offsetPosition = transform.position - player.position; //判斷相機與人物的偏移量,之後用這個偏移量作為參考控制相機移動
}
// Update is called once per frame
void Update () {
transform.position = offsetPosition + player.position; //使用偏移量作為相機位置的更新
}
}
即可為了提高可玩性,需要新增滑鼠滑輪的功能實現拉遠與縮排的功能。在Edit——Project Setting中有一個滑鼠滾輪的控制在Camera中的指令碼PlayerFollow中加入一個方法ScrollView()控制滾輪的拉近拉遠操作
public float scrollSpeed = 10f; //滾輪速度
public float distance = 0f;
void ScrollView()
{
//print (Input.GetAxis("Mouse ScrollWheel")); //Input.GetAxis("Mouse ScrollWheel")表示滑鼠滾輪的滑動值,滑的速度越快,值越大
distance = offsetPosition.magnitude; //用位置偏移表示鏡頭與角色的距離
distance -= Input.GetAxis ("Mouse ScrollWheel") * scrollSpeed; //通過distance的減少拉近(遠)視野
distance = Mathf.Clamp(distance,4f,14f); //限定拉近拉遠的最值
offsetPosition = offsetPosition.normalized * distance; //取得offsetPosition的單位向量,再乘distance表示改變視野後Camera與角色的距離
}
與上類似,我們在Camera中的指令碼PlayerFollow中加入一個方法RotateView()函式控制滑鼠右鍵的左右、上下移動 private bool isRotation = false; //是否旋轉視野的標誌位
public float rotateSpeed = 2f; //旋轉速度
void RotateView()
{
if (Input.GetMouseButtonDown (1)) //如果滑鼠右鍵(1表示右鍵,0表示左鍵,2表示滾輪)按下,旋轉開啟
{
isRotation = true;
}
if (Input.GetMouseButtonUp (1)) //若右鍵擡起,旋轉關閉
{
isRotation = false;
}
if (isRotation)
{
transform.RotateAround(player.position,player.up,rotateSpeed*Input.GetAxis("Mouse X")); //RotateAround表示繞著第一個引數進行旋轉,其中第一個引數表示圍繞player進行旋轉,第二個引數表示旋轉圍繞的軸,在這裡表示垂直主角的軸,第三個表示旋轉速度
transform.RotateAround(player.position,transform.right,-rotateSpeed*Input.GetAxis("Mouse Y")); //圍繞的軸改為水平方向
}
offsetPosition = transform.position - player.position; //旋轉後更新offsetPosition
}
旋轉角度的限定,即Camera中的Rotation對應的x,在 if (isRotation)中修改 if (isRotation)
{
transform.RotateAround(player.position,player.up,rotateSpeed*Input.GetAxis("Mouse X"));
Vector3 originalPos = transform.position; //儲存原始位置資訊
Quaternion originalRotation = transform.rotation; //儲存原始角度資訊
transform.RotateAround(player.position,transform.right ,-rotateSpeed*Input.GetAxis("Mouse Y"));
float x = transform.eulerAngles.x; //對應Camera的Rotation中的x
if(x<10 || x>80) //如果超過限制,返回原始值
{
transform.position = originalPos;
transform.rotation = originalRotation;
}
}
總結:角色控制的大致功能都已實現,有許多細節需要注意,需要花時間研究。之後將對任務、道具等系統進行建立。