Unity3D 一三人称视角切换鼠标显隐防物体遮挡处理方案

实现的功能

  1. 在两个相机(一人称和三人称)之间切换
  2. 鼠标显示隐藏
  3. 角色位移旋转(视野限制)距离缩放
  4. 第三人称相机防遮挡(将遮挡物体透明化)

前期准备

创建地形(示例使用长宽为100的Terrain)

创建主角(示例使用Sphere)

在主角物体下创建两个相机分别命名为FPS和TPS表示第一人称和第三人称的相机(注意将两个相机的局部坐标修改为(0,0,0),可以将三人称的相机设置为(0,5,-5)旋转x45,确保对着主角即可)

在地形上创建一些遮挡物,便于测试防遮挡功能脚本

在这里插入图片描述

编写脚本

在编写脚本之前,在主角上添加Character Controller组件

下图脚本控制相机的旋转角度和TPS相机缩放

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Mouse_Controller : MonoBehaviour
{
    //第三人称相机设置缩放
    public Camera TpsCamera;
    // 水平视角移动的敏感度
    public float sensitivityHor = 5f;
    // 垂直视角移动的敏感度
    public float sensitivityVer = 5f;
    // 视角向上移动的角度范围,该值越小范围越大 X轴向上
    public float upVer = -45;
    // 视角向下移动的角度范围,该值越大范围越大 X轴向下
    public float downVer = 45;
    // 垂直旋转角度
    private float rotVer;
    // 水平旋转角度
    private float rotHor;        
    //缩放速度
    public float wheelSpeed = 1f;
    //最小距离
    public float MinDistince = 5f;
    //最大距离
    public float MaxDistince = 20f;
    void Start()
    {
        // 初始化当前的垂直角度和水平角度
        rotVer = transform.eulerAngles.x;
        rotHor = transform.localEulerAngles.y;               
    }

    void Update()
    {
        changeRotate();
        changeDistinces();
    }

    void changeRotate() {//旋转
        // 获取鼠标Y轴移动 垂直
        float mouseVer = Input.GetAxis("Mouse Y");
        // 获取鼠标X轴移动 水平
        float mouseHor = Input.GetAxis("Mouse X");
        // 鼠标往上移动,视角其实是往下移,所以要想达到视角也往上移的话,就要减去它
        rotVer -= mouseVer * sensitivityVer;
        // 水平视角
        rotHor += mouseHor * sensitivityHor;
        // 限定上下移动的视角范围,即垂直方向不能360度旋转
        rotVer = Mathf.Clamp(rotVer, upVer, downVer);        
        // 设置视角的移动值
        transform.localEulerAngles = new Vector3(rotVer, rotHor, 0);
    }
    void changeDistinces() {//TPS相机的距离
        if (TpsCamera.isActiveAndEnabled) {
            if (Input.GetAxis("Mouse ScrollWheel") > 0 && Vector3.Distance(TpsCamera.transform.position, transform.position) >= MinDistince)
            {
                TpsCamera.transform.Translate(Vector3.forward * wheelSpeed);
            }
            if (Input.GetAxis("Mouse ScrollWheel") < 0 && Vector3.Distance(TpsCamera.transform.position, transform.position) <= MaxDistince)
            {
                TpsCamera.transform.Translate(Vector3.forward * -1f * wheelSpeed);
            }
        }          
    }
}

下图脚本控制角色移动跳跃以及显示隐藏鼠标(M)和镜头切换(V),快捷键可以自行更改
脚本中包含空气墙的功能,如果需要请按照自身场景的地形大小设置参数.
若不需要此功能可以在脚本组件里将is Open Boundray取消勾选.

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

public class Key_Controller : MonoBehaviour
{  
    public float speed = 6.0F;
    public float jumpSpeed = 8.0F;
    public float gravity = 20.0F;
    private Vector3 moveDirection = Vector3.zero;
    // 角色控制器
    CharacterController controller;
    public Camera FpsCamera, TpsCamera;
    public bool isFps = true;
    public bool isOpenBoundray = true;
    void Start()
    {
        // 获取组件
        controller = GetComponent<CharacterController>();
        //TpsCamera.enabled = false;
        //相机初始化
        FpsOrTpsInit();
        //鼠标显示隐藏初始化
        MouseVisibleInit();
    }
    void Update()
    {
        // 移动
        Key_Move();
        // 鼠标显示隐藏
        Change_MouseIsVisible();
        //相机切换
        Change_FpsOrTps();
    }
    void Key_Move() {        
        // 当角色在地面上
        if (controller.isGrounded)
        {
            moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
            moveDirection = transform.TransformDirection(moveDirection);
            moveDirection *= speed;
            if (Input.GetButton("Jump"))
                moveDirection.y = jumpSpeed;
        }
        moveDirection.y -= gravity * Time.deltaTime;
        controller.Move(moveDirection * Time.deltaTime);
        boundray();
    }

    //空气墙
    void boundray() {
        //Vector3 pos = transform.position;
        if(isOpenBoundray)
        transform.position = new Vector3(Mathf.Clamp(transform.position.x, 0.5f, 99.5f), transform.position.y, Mathf.Clamp(transform.position.z, 0.5f, 99.5f));
    }


    void MouseVisibleInit() {
        Cursor.lockState = CursorLockMode.Locked;
        Cursor.visible = false;
    }

    void Change_MouseIsVisible() {
        if (Input.GetKeyDown(KeyCode.M))
        {
            if (Cursor.visible == false)
            {
                Cursor.lockState = CursorLockMode.Confined;
                Cursor.visible = true;
            }
            else
            {
                Cursor.lockState = CursorLockMode.Locked;
                Cursor.visible = false;
            }
        }
    }

    void FpsOrTpsInit() {
        FpsCamera.gameObject.SetActive(isFps);
        TpsCamera.gameObject.SetActive(!isFps);
    }

    void Change_FpsOrTps() {
        if (Input.GetKeyDown(KeyCode.V)) {
            if (isFps)
            {
                FpsCamera.gameObject.SetActive(false);
                TpsCamera.gameObject.SetActive(true);
                //FpsCamera.enabled = false;
                //TpsCamera.enabled = true;
                isFps = false;
            }
            else {
                FpsCamera.gameObject.SetActive(true);
                TpsCamera.gameObject.SetActive(false);
                //FpsCamera.enabled = true;
                //TpsCamera.enabled = false;
                isFps = true;                              
            }
        }
    }
}

此时主角的检视面板应如下图状态

在这里插入图片描述
Key_Controller脚本的属性为:

Speed:移动速度
Jump Speed:跳跃高度
gravity:重力
FPS Camera:一人称相机,将创建的FPS相机拖入
TPS Camera:三人称相机,将创建的TPS相机拖入
is FPS:勾选在game视图默认是一人称,否则为三人称
is Open Boundray:启用空气墙(我设置的范围为x和z轴从0到100,如开启勿忘记根据自身情况修改)

Mouse_Controller脚本属性为:

TPS Camera:三人称相机,用于缩放功能,将创建的TPS相机拖入
sensitivityHor:水平视角移动的敏感度
sensitivityVer:垂直视角移动的敏感度
upVer:视角向上移动的角度范围
downVer:视角向下移动的角度范围
wheelSpeed:缩放速度
MinDistince:最小缩放距离
MaxDistince:最大缩放距离

此时运行场景,对于主角的位移旋转缩放,相机的切换等功能都是可以正常使用,如果失败,请按照上述仔细核对

防遮挡处理

我采取的方案是将遮挡的物体透明化,引用一位老哥的大部分代码,只针对自己的项目做了一点小小的修改.

原文地址:

https://blog.csdn.net/wl1611102/article/details/86550243

将下面的代码添加到TPS相机

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

public class CollisionHandling : MonoBehaviour
{

    public Transform player_Transform;//玩家角色
    private List<GameObject> collideredObjects;//本次射线hit到的GameObject
    private List<GameObject> bufferOfCollideredObjects;//上次射线hit到的GameObject

    void Start()
    {
        collideredObjects = new List<GameObject>();
        bufferOfCollideredObjects = new List<GameObject>();
    }

    // Update is called once per frame
    void Update()
    {
        bufferOfCollideredObjects.Clear();
        for (int temp = 0; temp < collideredObjects.Count; temp++)
        {
            bufferOfCollideredObjects.Add(collideredObjects[temp]);//得到上次的
        }
        collideredObjects.Clear();

        //发射射线
        Vector3 dir = (player_Transform.position-transform.position ).normalized;
        RaycastHit[] hits;
        hits = Physics.RaycastAll(transform.position, dir, Vector3.Distance(player_Transform.position, transform.position));
        Debug.DrawLine(transform.position, player_Transform.position, Color.red);//让其显示以便观测

        for (int i = 0; i < hits.Length; i++)
        {
            if (hits[i].collider.gameObject.name != "Terrain" && hits[i].collider.gameObject.name != "Sphere")
            {
                collideredObjects.Add(hits[i].collider.gameObject);//得到现在的
            }
        }
        //把上次的还原,这次的透明
        for (int i = 0; i < bufferOfCollideredObjects.Count; i++)
        {
            SetMaterialsColor(bufferOfCollideredObjects[i].GetComponent<Renderer>(), false);
        }
        for (int i = 0; i < collideredObjects.Count; i++)
        {
            SetMaterialsColor(collideredObjects[i].GetComponent<Renderer>(), true);
        }
    }

    //是否搞透明
    void SetMaterialsColor(Renderer r, bool isClear)
    {
        if (isClear)
        {
            int materialsNumber = r.sharedMaterials.Length;
            for (int i = 0; i < materialsNumber; i++)
            {
                r.materials[i].shader = Shader.Find("Transparent/Diffuse");
                Color tempColor = r.materials[i].color;
                tempColor.a = 0.3f;
                r.materials[i].color = tempColor;
            }
        }
        else
        {
            int materialsNumber = r.sharedMaterials.Length;
            Debug.Log("materialsNumber=" + materialsNumber);
            for (int i = 0; i < materialsNumber; i++)
            {
                r.materials[i].shader = Shader.Find("Transparent/Diffuse");
                Color tempColor = r.materials[i].color;
                tempColor.a = 1f;
                r.materials[i].color = tempColor;
            }
        }
    }
}

在这里插入图片描述
这样当有物体挡在镜头和主角之间时,遮挡物会透明.

结语

酌贪泉而觉爽,处涸辙以犹欢

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值