Unity第三人称视角、移动控制改进

实现功能:滑动鼠标旋转视角(水平旋转和垂直旋转有范围限制)    滑动滚轮缩放视角(缩放距离有范围限制)

                  鼠标右键锁定视角   WSAD或方向键移动人物 (人物正脸朝向由屏幕向里) 移动时滑动鼠标会改动人物转向(相机朝向与人物转向一致) 

改进:相机解决了穿墙的影响

注意:部分代码因个人项目需求与本文所介绍内容不相关,可自行再做删除修改!!!

相机脚本如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraCtrl : MonoBehaviour {

	//目标物体
    public Transform target;
    //相机与目标物体的距离
    public float distance;
    //横向角度
    public float rotDegree = 0;
    public float rotSpeed = 0.2f;
    float rot; //弧度
    //纵向角度
    public float rollDegree = 30;
    public float rollSpeed = 0.2f;
    public float minRollDegree = -15;
    public float maxRollDegree = 15;
    float roll; //弧度
    //摄像机移动速度(滚轮控制)
    public float zoomSpeed = 1.5f;
    public float minDis = 8;
    public float maxDis = 22;
    //视角锁定
    private bool isLock = false;
    //相机和角色之间的距离
    private float sourceDis;

    // Use this for initialization
    void Start () {
        GetTarget(target.gameObject);
    }
    
    // Update is called once per frame
    void LateUpdate () {
        if (isLock == false)
        {
            Rotate();
            Roll();
            Zoom();
        }
        //角度转换成弧度
        rot = rotDegree * Mathf.PI / 180;
        roll = rollDegree * Mathf.PI / 180;
        //计算相机的地面投影和相机高度
        float d = distance * Mathf.Cos(roll);
        float height = distance * Mathf.Sin(roll);
        Vector3 cameraPos = Vector3.zero;
        //计算相机的坐标
        if (target != null)
        {
            cameraPos.x = target.transform.position.x + d * Mathf.Cos(rot);
            cameraPos.z = target.transform.position.z + d * Mathf.Sin(rot);
            cameraPos.y = target.transform.position.y + height;

            this.transform.position = cameraPos;
            this.transform.LookAt(target.transform.position);
        }
        if (Input.GetMouseButtonDown(1)) {
            isLock = !isLock;
        }
        sourceDis = Vector3.Distance(transform.position, target.position);
        CameraDefend();
    }
    //鼠标水平滑动调整视角
    void Rotate() {
        float value = Input.GetAxis("Mouse X");
        rotDegree -= value * rotSpeed;
    }
    //鼠标垂直方向调整视角
    void Roll() {
        float value = Input.GetAxis("Mouse Y");
        rollDegree += value * rollSpeed;
        rollDegree = Mathf.Clamp(rollDegree, minRollDegree, maxRollDegree);
    }
    //滚轮调整视角的远近
    void Zoom() {
        float value = Input.GetAxis("Mouse ScrollWheel");
        distance -= value * zoomSpeed;
        distance = Mathf.Clamp(distance, minDis, maxDis);
    }

    //让相机始终跟随目标物体身上的某一点
    private void GetTarget(GameObject target) {
        if (target.transform.Find("cameraPoint") != null)
        {
            this.target = target.transform.Find("cameraPoint");
            Debug.Log("找到Target点");
        }
    }
    //恢复默认参数
    public void DefaultValue() {
        distance = 5;
        //横向角度
        rotDegree = 270;
        //纵向角度
        rollDegree = -10;
    }
    public Vector3 temp = new Vector3(0, -0.7f, 0);
    private void CameraDefend() {
        RaycastHit hit;
        //从角色向相机发射一条射线
        if (Physics.Linecast(this.target.position + temp, transform.position, out hit)) {
            string name = hit.collider.gameObject.tag;
            if (name != "MainCamera" || name != "Fire") {
                float currentDistance = Vector3.Distance(target.position, hit.point);
                //如果射线碰撞点小于玩家与相机本来的距离,就说明角色身后是有东西,为了避免穿墙,就把相机拉近
                if (currentDistance < sourceDis) {
                    //transform.position = hit.point;
                    transform.position = Vector3.Lerp(transform.position, hit.point,10);
                }
            }
        }
    }
}

人物移动控制脚本如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CharacterMove : MonoBehaviour {

    Animator anim;
    float speed = 7;
    public bool isCrouch = false;

    public bool isWalk;
    private GameObject camera;

    private float dis = 999999;
    private Transform target;
    //脚步音效组件
    private AudioSource audio;

    // Use this for initialization
    void Start()
    {
        anim = GetComponent();
        camera = GameObject.Find("Main Camera");
        audio = this.gameObject.AddComponent();
        audio.clip = Resources.Load("Sounds/Foot");
    }

    // Update is called once per frame
    void FixedUpdate()
    {
        //if (anim.GetCurrentAnimatorStateInfo(0).IsName("Grounded") == false) return;
        if (Input.GetKey(KeyCode.Space)) {
            RotateCtrl();
        }

        FootStep();

        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        if (Mathf.Abs(h) > 0 || Mathf.Abs(v) > 0)
        {
            transform.Translate(new Vector3(h, 0, v) * speed * Time.deltaTime, Space.Self);
            //transform.rotation = Quaternion.LookRotation(new Vector3(h, 0, v));

            //让角色的朝向跟相机的x-o-z面的朝向保持一致
            RotateCtrl();

            isWalk = true;
            anim.SetBool("IsWalk", isWalk);  
        }
        else {
            isWalk = false;
            anim.SetBool("IsWalk", isWalk);
        }
        //下蹲
        if (Input.GetKeyDown(KeyCode.F))
        {
            isCrouch = !isCrouch;
            anim.SetBool("IsCrouch", isCrouch);
        }
        //拾取火种的操作
        if (Input.GetKeyDown(KeyCode.Space) && target != null && target.GetChild(0).gameObject.activeInHierarchy)
        {
            dis = Vector3.Distance(transform.position, target.transform.position);
            if (dis <= 2.5f)
            {
                string name = target.GetChild(2).name;
                Debug.Log("Name:" + name);
                GameObject.Find("FirePos").GetComponent().SendRequest(name);
                GameFacade.Instance.PlaynormalSound(AudioManager.Sound_Timer);
                //Destroy(target.gameObject);
            }
        }
    }
    private void RotateCtrl() {
        Vector3 tempRot = camera.transform.position;
        tempRot.y = transform.position.y;
        Vector3 targetRot = transform.position - tempRot;
        transform.rotation = Quaternion.LookRotation(targetRot);
    }
    public CharacterMove GetCharacterMove() {
        return this;
    }
    void OnTriggerEnter(Collider other) {
        if (other.tag == "Weapon") {
            target = other.transform;
            dis = Vector3.Distance(transform.position, other.transform.position);
        }
    }
    void FootStep() {
        if (Input.GetKeyDown(KeyCode.W) || Input.GetKeyDown(KeyCode.S) || Input.GetKeyDown(KeyCode.A) || (Input.GetKeyDown(KeyCode.D))
         || Input.GetKeyDown(KeyCode.UpArrow) || Input.GetKeyDown(KeyCode.DownArrow) || Input.GetKeyDown(KeyCode.LeftArrow)
           || Input.GetKeyDown(KeyCode.RightArrow))
        {
            audio.Play();
        }
        else if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.A) || (Input.GetKey(KeyCode.D))
         || Input.GetKey(KeyCode.UpArrow) || Input.GetKey(KeyCode.DownArrow) || Input.GetKey(KeyCode.LeftArrow)
           || Input.GetKey(KeyCode.RightArrow))
        {
            audio.loop = true;
        }
        else {
            audio.loop = false;
        }
    }
}

值得一提的是如下脚本:

void FixedUpdate () {
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");

        Move(h, v);
        RotateCtrl(h, v);
    }

    void Move(float h, float v) {
        pos = new Vector3(h, 0, v);
        transform.Translate(pos * Time.deltaTime * speed,Space.World);
    }
    void RotateCtrl(float h, float v) {
        if (h != 0 || v != 0)
        {
            transform.rotation = Quaternion.LookRotation(pos);
        }

也可以控制人物的移动,Quaternion.LookRotation方法控制人物的旋转,即人物在移动的同时会根据 h、v的变化发生旋转

这是自己目前所总结的方法,努力寻求更好方法中。。。。。。
   

你可能感兴趣的:(Unity组件学习)