unity实现吃鸡摄像头,自动拉近拉远视距,不被遮挡物遮盖人物效果

实现类似摄像头,遇到遮挡物自动拉近拉远视距,不被遮挡物遮盖人物的效果

效果图

传入的时gif图,帧率有所降低,不过能看清楚
这是旋转时的效果
在这里插入图片描述
这是背后有墙时的效果
在这里插入图片描述

一、简介

全部代码放上来太麻烦了,就只把挂载核心的代码拿出来,代码中不知道是干什么的请自动忽略,其余用到与主题相关的代码都有注释,有需要解释的地方可以留言,废话不多说,客官往下看。

二、基本层级

这个脚本是挂在人物下面用来设置摄像机位置的一个空物体上的,层次结构是这样的:
层级结构图
在代码中的位置:
物体:脚本变量名称
1.Main Camera :private GameObject MainCamera

  • 摄像机身上没有脚本,使用vector3.SmoothDamp()来跟随cameraPos,这样设置,就可以达到很多游戏上摄像平滑移动的效果。
//设置摄像机跟随
        MainCamera.transform.position = Vector3.SmoothDamp(MainCamera.transform.position, transform.position, ref RefCameraForWorld,CameraWorldSpreed);

2.PlayerHand :private GameObject PlayerHand
这个是人物的父物体
3.cameraHand : private GameObject CameraHand
这个是摄像机的父物体,放在人物的头顶,以下几个作用:

  • 使用LookAt函数使摄像机啊始终看向这个物体
- MainCamera.transform.LookAt(CameraHand.transform);   //摄像机始终看向人物
  • 再有就是用来控制摄像机的上下角度的限制和旋转,因为摄像机的位置是这个物体的子物体,所以只要旋转这个物体的X轴也就是旋转了上下的视角,这样更方便的去限制上下角度的大小,代码中用来pi点的所有代码可以理解为键盘操作部分,比如WSAD,详细可以去看[傅老師/Unity教學][4/27中午更新] DarkSouls複刻經典教程#第一季,剩下的horizontalSpeed、verticalSpeed就是鼠标的X轴和Y轴的速度,鼠标XY轴的设置不在这个脚本,就是这两条,请记住这两个命名下面会用pi点出来:
Jup = Input.GetAxis("Mouse Y") * MouseSpeedX;
Jright = Input.GetAxis("Mouse X") * MouseSpeedY;
  • 这个就是鼠标控制左右和上下旋转的代码
//计算摄像机的旋转
    private void CalculateCameraRotate()
    {
        PlayerHand.transform.Rotate(Vector3.up, pi.Jright * horizontalSpeed * Time.fixedDeltaTime);
        tempEulerX -= pi.Jup * verticalSpeed * Time.fixedDeltaTime;
        tempEulerX = Mathf.Clamp(tempEulerX, CameraXMin, CameraXMax);
        CameraHand.transform.localEulerAngles = new Vector3(tempEulerX, 0, 0);
    }

4.CameraPos : 基本都是this.transfrom
接下来就是挂载下面脚本的物体

三、核心脚本

```csharp
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class CameraController : MonoBehaviour {
    [Header("===== 摄像机输入值 =====")]
    public float horizontalSpeed = 100f;            //摄像机水平移动速度
    public float verticalSpeed = 80f;               //摄像机垂直移动速度
    public float MouseCenterSpeed = 200f;           //摄像机中键速度
    public float tempEulerX;                        //限制摄像机上下角度
    public float CameraWorldSpreed;                 //摄像机跟随速度
    public float SaveCameraCenter;                  //储存摄像机的中键值
    public float CameraRotateMax = 3;               //最远的摄像机距离
    public float CameraRotateMin = 0.7f;            //最近的摄像机距离
    public float CameraXMin = -25;                  //最大向下角度
    public float CameraXMax = 30;                   //最大向上角度
    public float distance = 3;                      //当前使用的距离
    private float Mouse2Distance = 3;               //鼠标中键滚动了多少
    private bool IsMouse2 = true;                   //是否允许缩放摄像机
    [Header("===== 组件 =====")]
    public LineRenderer line;                       //画出射线
    //public LineRenderer line2;                    //画出射线

    private PlayerInput pi;                         //人物输入脚本
    private GameObject PlayerHand;                  //玩家碰撞体积
    private GameObject CameraHand;                  //摄像机父亲
    private GameObject MainCamera;                  //主摄像机
    public GameObject model;                        //玩家自身

    private Vector3 RefCameraForWorld;             //暂存摄像机的缓动值
    private Vector3 TempVec;                       //射线时暂存摄像机位置
    private Vector3 Offsetpos;                     //摄像机与人物之间的差值

    private void Awake()
    {
        CameraHand = transform.parent.gameObject;
        PlayerHand = CameraHand.transform.parent.gameObject;
        pi = PlayerHand.GetComponent<PlayerInput>();
        MainCamera = GameObject.FindGameObjectWithTag("MainCamera");
        model = pi.GetComponent<ActorController>().model;
    }
    private void Start()
    {
    //计算出摄像机与人物之间的差值
        Offsetpos = transform.position - CameraHand.transform.position;
    }
    private void FixedUpdate()
    {
        //获取人物的欧拉角
        //(这个是和FixedUpdate最后一句//当前人物的欧拉角对应的,
        //作用是现将人物的方向保存下来,在做完摄像机的一切操作后在赋值给人物)
        Vector3 TempModleEuluer = model.transform.eulerAngles;

        //设置摄像机跟随
        MainCamera.transform.position = Vector3.SmoothDamp(MainCamera.transform.position, transform.position, ref RefCameraForWorld, CameraWorldSpreed);
        MainCamera.transform.LookAt(CameraHand.transform);                               //摄像机始终看向人物
        //调用射射线计算摄像机与人物之间的距离
        CalculateCameraDistance();
        //设置这个的原因:为了保存人物滚轮滚动的距离,也在不滚动滚轮时不用一直去计算摄像机与人物之间的距离
        if (Input.GetAxis("Mouse ScrollWheel") != 0)
        {
            CalculateCameraCenter();
        }
        //限制摄像机的自动旋转,这个设置成input.mouseButton(1)也可以
        if (pi.IsCameraMouseEnable)
        {
            //按下鼠标右键后去调用摄像机旋转的方法
            //并且重新计算差值
            CalculateCameraRotate();
            Offsetpos = transform.position - CameraHand.transform.position;
        }
        //否则就将当前位置确定下来
        else
        {
            transform.position = Offsetpos + CameraHand.transform.position;
        }

        //当前人物的欧拉角(与FixedUpdate第一行代码呼应,上面写了)
        model.transform.eulerAngles = TempModleEuluer;
    }
    //计算摄像机的旋转
    private void CalculateCameraRotate()
    {
        PlayerHand.transform.Rotate(Vector3.up, pi.Jright * horizontalSpeed * Time.fixedDeltaTime);
        tempEulerX -= pi.Jup * verticalSpeed * Time.fixedDeltaTime;
        tempEulerX = Mathf.Clamp(tempEulerX, CameraXMin, CameraXMax);
        CameraHand.transform.localEulerAngles = new Vector3(tempEulerX, 0, 0);
    }
    //发射射线计算摄像机与人物之间的距离
    private void CalculateCameraDistance()
    {
       Ray ray2 = new Ray(CameraHand.transform.position, (this.transform.position - CameraHand.transform.position).normalized);
        RaycastHit hit2;
        int laymask = ~(1 << 10);
        
        if (Physics.Raycast(ray2, out hit2, 100, laymask))
        {
            IsMouse2 = false;
            if (hit2.distance < Mouse2Distance )
            {
                line.SetPositions(new Vector3[] { CameraHand.transform.position, hit2.point });
                if (hit2.distance < CameraRotateMin)
                {
                    CrameraPosition(CameraRotateMin);
                    return;
                }
                CrameraPosition(hit2.distance);
            }
            else
            {
                CrameraPosition(Mouse2Distance);
                IsMouse2 = true;
            }
        }
        else if ( hit2.distance == 0)
        {
            CrameraPosition(Mouse2Distance);
            IsMouse2 = true;
        }
        transform.position = Offsetpos + CameraHand.transform.position;
    }
    //计算摄像机应该拥有的位置
    private void CrameraPosition( float theDistance)
    {
        //1.设置摄像机的位置
        this.Offsetpos = this.Offsetpos.normalized * theDistance;
    }
    //计算鼠标中键调整摄像机的远近
    private void CalculateCameraCenter()
    {
        if (EventSystem.current.IsPointerOverGameObject() != false)
        {
            return;
        }
        distance = Offsetpos.magnitude;
        
        distance -= Input.GetAxis("Mouse ScrollWheel") * MouseCenterSpeed;
        distance = Mathf.Clamp(distance, CameraRotateMin, CameraRotateMax);
        if (Input.GetAxis("Mouse ScrollWheel") != 0)
        {
            Mouse2Distance = distance;
        }
        Offsetpos = Offsetpos.normalized * distance;

    }


}

四、寒暄

呃………………没啥说的了,代码逻辑还不是很好,看不懂给我留言,有更好的建议也希望能留言。谢谢。
对这块比较感兴趣的推荐学习[傅老師/Unity教學][4/27中午更新] DarkSouls複刻經典教程#第一季,大部分逻辑都是跟着学的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值