总结一下今天做的面试题(三):第三人称相机控制

同样是先看需求:

整个地方最难的在于,相机被挤压时要怎么处理。

由于没玩过上面两款游戏,也不知道是怎么处理的,我自己的想法是让相机直接旋转180度。

首先贴一下人物控制脚本,别忘了给人物加上Charactor Controll组件

using UnityEngine;
using System.Collections;

public class move_controll : MonoBehaviour {
    Transform m_transform,m_camera;
    CharacterController controller;
    float MoveSpeed = 1.0f;
    string[] clipName={"idle","shamble"};
    Animation m_animation;
    // Use this for initialization
    void Start () {
        m_transform = this.transform;
        m_camera = GameObject.FindGameObjectWithTag ("MainCamera").transform;
        controller=GetComponent<CharacterController>();
        m_animation = m_transform.GetComponent<Animation> ();
    }
    
    // Update is called once per frame
    void Update () {
        if ((Input.GetKey (KeyCode.W)) || (Input.GetKey (KeyCode.S)) || (Input.GetKey (KeyCode.A)) || (Input.GetKey (KeyCode.D))) {
            m_animation.Play (clipName[1]);
            if (Input.GetKey (KeyCode.W)) {
                controller.transform.eulerAngles = new Vector3 (0, m_camera.transform.eulerAngles.y, 0);//the eulerAngles depend on camera's eulerAngles
            }

            if (Input.GetKey (KeyCode.S)) {
                controller.transform.eulerAngles = new Vector3 (0, m_camera.transform.eulerAngles.y+180f, 0);
            }

            if (Input.GetKey (KeyCode.A)) {
                controller.transform.eulerAngles = new Vector3 (0, m_camera.transform.eulerAngles.y+270f, 0);
            }

            if (Input.GetKey (KeyCode.D)) {
                controller.transform.eulerAngles = new Vector3 (0, m_camera.transform.eulerAngles.y+90f, 0);
            }

            controller.Move(m_transform.forward * Time.deltaTime * MoveSpeed);
        }
        else
            //idle
            m_animation.Play (clipName[0]);
        //gravity
        if (!controller.isGrounded) {
            controller.Move(new Vector3(0,-10f*Time.deltaTime,0));
        }
    }
}

随后是相机控制,这里提供两个版本,一个是用滚轮控制镜头远近的(我从别的地方抄的):

// ====================================================================================================================
// Simple rotation and tilt of camera around a pivot object
// Created by Leslie Young
// http://www.plyoung.com/ or http://plyoung.wordpress.com/
// ====================================================================================================================

using UnityEngine;

public class CameraOrbit : MonoBehaviour 
{
    public Transform pivot;                            // the object being followed
    public Vector3 pivotOffset = Vector3.zero;        // offset from target's pivot
    public Transform target;                        // like a selected object (used with checking if objects between cam and target)

    public float distance = 10.0f; // distance from target (used with zoom)
    public float minDistance = 2f;
    public float maxDistance = 15f;
    public float zoomSpeed = 1f;

    public float xSpeed = 250.0f;
    public float ySpeed = 120.0f;

    public bool allowYTilt = true;
    public float yMinLimit = 30f;
    public float yMaxLimit = 80f;

    private float x = 0.0f;
    private float y = 0.0f;

    private float targetX = 0f;
    private float targetY = 0f;
    private float targetDistance = 0f;
    private float xVelocity = 1f;
    private float yVelocity = 1f;
    private float zoomVelocity = 1f;

    void Start()
    {
        var angles = transform.eulerAngles;
        targetX = x = angles.x;
        targetY = y = ClampAngle(angles.y, yMinLimit, yMaxLimit);
        targetDistance = distance;
    }

    void LateUpdate()
    {
        if (pivot)
        {
            // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
            // scroll wheel used to zoom in/out
            float scroll = Input.GetAxis("Mouse ScrollWheel");

            if (scroll > 0.0f) targetDistance -= zoomSpeed;
            else if (scroll < 0.0f) targetDistance += zoomSpeed;
            targetDistance = Mathf.Clamp(targetDistance, minDistance, maxDistance);

            // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
            // right mouse button must be held down to tilt/rotate cam
            // or player can use the left mouse button while holding Ctr
            if (Input.GetMouseButton(1) || (Input.GetMouseButton(0) && (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl)) ))
            {
                targetX += Input.GetAxis("Mouse X") * xSpeed * 0.02f;
                if (allowYTilt)
                {
                    targetY -= Input.GetAxis("Mouse Y") * ySpeed * 0.02f;
                    targetY = ClampAngle(targetY, yMinLimit, yMaxLimit);
                }
            }
            x = Mathf.SmoothDampAngle(x, targetX, ref xVelocity, 0.3f);
            if (allowYTilt) y = Mathf.SmoothDampAngle(y, targetY, ref yVelocity, 0.3f);
            else y = targetY;
            Quaternion rotation = Quaternion.Euler(y, x, 0);
            distance = Mathf.SmoothDamp(distance, targetDistance, ref zoomVelocity, 0.5f);

            // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
            // apply
            Vector3 position = rotation * new Vector3(0.0f, 0.0f, -distance) + pivot.position + pivotOffset;
            transform.rotation = rotation;
            transform.position = position;

        }
    }

    private float ClampAngle(float angle, float min, float max)
    {
        if (angle < -360) angle += 360;
        if (angle > 360) angle -= 360;
        return Mathf.Clamp(angle, min, max);
    }

    // ====================================================================================================================
}
CameraOrbit

然后我以这个脚本为基础来该,首先是人物被遮挡时,相机要拉近:

采用射线的方式进行检测:

            RaycastHit hit;//ues a ray to make camera not be blocked
            if (Physics.Linecast (position, pivot.position,out hit)) {
                string name = hit.collider.gameObject.tag;
                if (name =="Untagged") {
                    targetDistance=(hit.point-pivot.position).magnitude;//if the hit object's tag is Untagged,change the distance
                }
            }

然后是相机被挤压导致距离极低时的旋转:

            if (distance > distanceLimit) {
                position = rotation * new Vector3 (0.0f, 0.0f, -distance) + pivot.position + pivotOffset;
            } else {
                rotation = Quaternion.Euler(y, x+180f, 0);
                position = rotation * new Vector3 (0.0f, 0.0f, -m_distance) + pivot.position + pivotOffset;
                targetX = targetX + 180;
                x = x + 180;
            }

整个脚本:

using UnityEngine;
using System.Collections;

public class Camera_Controll : MonoBehaviour {
    public Transform pivot;
    public Vector3 pivotOffset = Vector3.zero;    
    public float distance = 10.0f; // distance from target (used with zoom)
    public float distanceLimit=3f;//distance when camera change Angles for 180
    public float zoomSpeed = 1f;
    public float xSpeed = 250.0f;
    public float ySpeed = 120.0f;

    public bool allowYTilt = true;
    public float yMinLimit = -60f;
    public float yMaxLimit = 60f;

    private float x = 0.0f;
    private float y = 0.0f;
    private float targetX = 0f;
    private float targetY = 0f;
    private float targetDistance = 0f;
    private float xVelocity = 1f;
    private float yVelocity = 1f;
    private float zoomVelocity = 1f;
    private float m_distance;
    // Use this for initialization
    void Start () {
        
        var angles = transform.eulerAngles;
        targetX = x = angles.x;
        targetY = y = ClampAngle(angles.y, yMinLimit, yMaxLimit);
        targetDistance = distance;
        m_distance = distance;
    }
    
    // Update is called once per frame
    void LateUpdate () {
        if (pivot)
        {
            targetDistance = m_distance;

            if (Input.GetMouseButton(1) || (Input.GetMouseButton(0) && (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl)) ))
            {
                targetX += Input.GetAxis("Mouse X") * xSpeed * 0.02f;
                if (allowYTilt)
                {
                    targetY -= Input.GetAxis("Mouse Y") * ySpeed * 0.02f;
                    targetY = ClampAngle(targetY, yMinLimit, yMaxLimit);
                }
            }
            x = Mathf.SmoothDampAngle(x, targetX, ref xVelocity, 0.3f);
            if (allowYTilt) y = Mathf.SmoothDampAngle(y, targetY, ref yVelocity, 0.3f);
            else y = targetY;
            Quaternion rotation = Quaternion.Euler(y, x, 0);
            Vector3 position = rotation * new Vector3(0.0f, 0.0f, -m_distance) + pivot.position;//calculate the true camera positon
            RaycastHit hit;//ues a ray to make camera not be blocked
            if (Physics.Linecast (position, pivot.position,out hit)) {
                string name = hit.collider.gameObject.tag;
                if (name =="Untagged") {
                    targetDistance=(hit.point-pivot.position).magnitude;//if the hit object's tag is Untagged,change the distance
                }
            }
            distance = Mathf.SmoothDamp(distance, targetDistance, ref zoomVelocity, 0.5f);
            if (distance > distanceLimit) {
                position = rotation * new Vector3 (0.0f, 0.0f, -distance) + pivot.position + pivotOffset;
            } else {
                rotation = Quaternion.Euler(y, x+180f, 0);
                position = rotation * new Vector3 (0.0f, 0.0f, -m_distance) + pivot.position + pivotOffset;
                targetX = targetX + 180;
                x = x + 180;
            }
            transform.rotation = rotation;
            transform.position = position;
        }
    }
    private float ClampAngle(float angle, float min, float max)
    {
        if (angle < -360) angle += 360;
        if (angle > 360) angle -= 360;
        return Mathf.Clamp(angle, min, max);
    }
}
Camera_Controll.cs
原文地址:https://www.cnblogs.com/Swallowtail/p/6183161.html