從零開始的RPG制作6.2-(攝像機障礙物處理。)

首先確定功能。
1.如果攝像機和跟隨物體之間有東西夾著,攝像機自動移動到被夾著的物體的表面。

2.如果攝像機和和跟隨物體直接夾著的東西消失,攝像機自動返回到原來的縮放。

3.如果攝像機和跟隨物體之間有東西夾著,攝像機自動移動到被夾著的物體的表面,這時候攝像機還能進行朝前縮進,一單發(fā)生轉(zhuǎn)向,攝像機繼續(xù)回到原來的縮放大小,但是保持原有的方向。

下面提供一下我的思路:
offset = 攝像機向量-跟隨物體向量;
將offset 拆開,一份用于存儲方向,一份用于存儲距離。
轉(zhuǎn)向,人物移動,這部分我們來修改方向。
而攝像機朝前超后推,遇到阻礙物,來修改距離,最終統(tǒng)一合成一個新向量,接下來放出代碼,修改了許多版本終于感覺可以用了。

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

public class CameraMessage:MonoBehaviour {

    struct CameraChangeData {
        public float ScrollWheel;
        public float RotateX;
        public float RotateY;
    }
    CameraChangeData cameraChangeData;
    static public CameraMessage cm;
    private Vector3 offSetPostion;//從目標指向攝像機的向量
    private float offSetPostionDistance;//offSetPostion的長度
    private float scrollSpeed = 3.0f;//向前向后靠近的速度
    private float rotateSpeed = 2f;//轉(zhuǎn)向速度
    private Vector3 followVector;//需要注視的坐標。
    bool isRotate = false;//是否出于旋轉(zhuǎn)狀態(tài)
    Vector3 lestNewF;//在攝像機發(fā)生旋轉(zhuǎn)的時候,我們不希望角色的方向轉(zhuǎn)化到攝像機的坐標系下,繼而使用沒有轉(zhuǎn)向時候的向量。
    private Transform camareTr;//攝像機
    private Transform followObject;//追隨物
    static public CameraMessage getInstance() {
    static public CameraMessage getInstance() {
        if (cm == null) {
                cm = GameObject.FindObjectOfType<CameraMessage>();
                cm.init();
        }
            return cm;
     }

    void init() {
        camareTr = transform;
        cameraChangeData = new CameraChangeData();
    }
    float? offsetMagnitud;//用于保存出現(xiàn)夾著的物體的時候,攝像機和跟隨物體的長度。

    private bool cameraRay() {//如果中間隔著遮擋物。相機應(yīng)該貼著遮擋物(看了塞爾達的視頻,應(yīng)該也是這么處理的。),如果一旦沒有了遮擋物返回到之前設(shè)定的狀態(tài)。
        Vector3 vt = camareTr.position - followVector;
        RaycastHit rayHit;
        bool rayGround = false;
        if (Physics.Raycast(followVector, vt, out rayHit,100, LayerMask.GetMask("IsGround"))) {
            Vector3 newOffSetPostion = rayHit.point - followVector;
            if (newOffSetPostion.magnitude <offSetPostionDistance) {//如果被地面夾在中間
                if (offsetMagnitud == null) {//如果這時候發(fā)現(xiàn)offSetPostion的長度為空,這就意味著第一次遇到遮擋物。
                    offsetMagnitud = offSetPostionDistance;
                }
                offSetPostionDistance = newOffSetPostion.magnitude;
                rayGround = true;
            }
        } else {
            if (offsetMagnitud != null) {
                offSetPostionDistance = Mathf.Lerp(offSetPostionDistance, (float)offsetMagnitud, 0.2f);//漸漸的返回成第一次遇到遮擋物之前的長度。
                if (Mathf.Abs(offSetPostionDistance - (float)offsetMagnitud) <= 0.01f) {
                    offsetMagnitud = null;
                }
            }
        }
        if (offsetMagnitud != null) {
            rayGround = true;
        }
        IDrawGizmos.drawLine(followVector, camareTr.position, Color.red, 3);
        IDrawGizmos.drawLine(followVector, followObject.position + followObject.up * 5, Color.red, 4);
        return rayGround;
    }

    public void setInitOffsetPosittion(Transform followObject, Vector3 targetPos) {//設(shè)置相機跟隨對象。
        this.followObject = followObject;
        offSetPostion = camareTr.position - targetPos;//計算由角色指向相機的向量
        offSetPostionDistance = offSetPostion.magnitude;
    }
    float lastmd;
    public void setUpdateFollowVector(Vector3 followVector) {
        //如果是PC------
        keyController();
        this.followVector = followVector;//源源不斷的獲取人物坐標。
        bool rayGround = cameraRay();//放入射線
        scrollview(rayGround);//縮放信息在這一幀中起效
                    
        camareTr.position = followVector + offSetPostion.normalized* offSetPostionDistance;

        rotateView();//轉(zhuǎn)向消息在下一幀中起效
    }

    private void keyController() {//將鍵盤操作的部分獨立出來,將來說不定要換平臺呢。
        cameraChangeData.ScrollWheel = Input.GetAxis("Mouse ScrollWheel") * scrollSpeed;
        if (Input.GetMouseButtonDown(1)) {
            isRotate = true;
        } else if (Input.GetMouseButtonUp(1)) {
            isRotate = false;
        }
        cameraChangeData.RotateX = Input.GetAxis("Mouse X") * rotateSpeed;
        cameraChangeData.RotateY = Input.GetAxis("Mouse Y") * rotateSpeed;
    }


    private void scrollview(bool rayGround) {//控制前后縮放
        float  newOffSetPostionDistance = offSetPostionDistance - cameraChangeData.ScrollWheel;
        if (newOffSetPostionDistance < 2 && cameraChangeData.ScrollWheel > 0) {//當(dāng)距離小于2就不能往前推攝像機
            return;
        } else if ((newOffSetPostionDistance > 12 && cameraChangeData.ScrollWheel < 0) || (cameraChangeData.ScrollWheel < 0 && rayGround)) {//當(dāng)距離大于12或者有遮擋物就不能往后推攝像機
            return;
        }
        offSetPostionDistance = Mathf.Lerp(offSetPostionDistance, newOffSetPostionDistance, 0.2f);
    }

    private void rotateView() {//控制轉(zhuǎn)向
        if (isRotate) {
            camareTr.RotateAround(followVector, Vector3.up, cameraChangeData.RotateX);//在以世界的UP轉(zhuǎn)   
            if (Vector3.Angle(followObject.up, offSetPostion) < 30 && cameraChangeData.RotateY < 0) {//向上轉(zhuǎn)的時候和人物的up不能超過30°
                cameraChangeData.RotateY = 0;
            } else if (Vector3.Angle(followObject.up, offSetPostion) > 160 && cameraChangeData.RotateY > 0) {//向下轉(zhuǎn)的時候和人物的up不能超過160°,這里可以添加小姐姐捂裙子的操作- .-
                cameraChangeData.RotateY = 0;
            }

            camareTr.RotateAround(followVector, camareTr.TransformDirection(Vector3.right), -cameraChangeData.RotateY);//以攝像機的right轉(zhuǎn),如果以世界的right轉(zhuǎn),會受到X軸的干擾,所有用角色right.

            offSetPostion = camareTr.position - followVector;//需要重新改變方向
        }
    }


    public Vector3 DisplacementCoordinates(Vector3 targer) {//將控制方向從世界轉(zhuǎn)到攝像機,即,WASD的移動都按照攝像機在標準世界坐標投影上的向量移動。
        if (isRotate)//視角在發(fā)生旋轉(zhuǎn)的時候 人物不應(yīng)該跟著攝像機走。
            return lestNewF;
        Vector3 ct = camareTr.TransformDirection(targer);//將輸入操作轉(zhuǎn)到攝像機坐標
        Vector3 f = Vector3.Project(ct, Vector3.forward);//找到在forward上的投影,
        Vector3 r = Vector3.Project(ct, Vector3.right);//找到在right上的投影
        Vector3 newF = f + r;//兩者相加,就是新的面朝方向。
        lestNewF = newF;
        return newF;
    }

}
效果

上一節(jié)
下一節(jié)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容