IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> Unity 一种更为简洁明了的环绕相机方案 -> 正文阅读

[游戏开发]Unity 一种更为简洁明了的环绕相机方案

配置方法

创建一个空对象挂载相机控制脚本(在代码中让该对象与角色的位置重合),相机作为其子物体

将相机相对于父物体的距离设定为理想的 相机-人物 距离

指定环绕中心和相机

原理

想要实现环绕,首先就需要获取环绕点和相机的Transform属性。

想要表示相机相对于环绕点的方位,你可能会觉得使用相对位置描述更为方便,其实不然,实际上使用两个欧拉角来描述比使用位置描述更为方便,因为我们后面需要对相机的旋转过程插值,使用位置来描述显然是不便于插值的。

这样,我们就有了相机相对于环绕点的角度,加上距离就可以精确描述相机的位置了。

线性插值

如果要对一个变量进行插值,首先要明确插值的实现。什么是线性插值?

给定两个数,a、b,对a、b进行一次线性插值,再给一个参数t,代表插值的位置。

比如对0、1插值,参数为0.1,那么进行一次插值得到的结果就是0.1。

线性插值的公式是 a + (b-a) * t 。

那么插值有哪些实际应用呢?

- 平滑运动中的相机与角色的距离

- 平滑旋转中的相机与角色的角度,并实现一定时长的惯性旋转效果。

为什么插值会产生延时呢?

因为插值有两个数,一个是当前值,一个是目标值,另外还有一个参数是百分比。

当目标值不再变化之后,当前值逼近目标值需要一定的时间。

两个数之间的差距随着时间的变化曲线,类似于一个方向向下的抛物线。

周围障碍检测

对角色前后左右四个方向进行射线检测,获取返回的距离,取得一个最小值。

如果想要更精确的结果,可以将正交的方向向量分别两两相加,得到四个斜的方向向量,这样就可以做八个方向的距离检测。

相机被遮挡处理

如果相机被遮挡,就将相机距离调整到小于 距离角色水平方向最近的障碍距离 。

在手动调整距离时,记录偏好距离。

如果不再被遮挡,就恢复偏好距离。

代码

using UnityEngine;
using System.Collections;

public class OrbitCamera : MonoBehaviour
{
    public Transform pivot;
    public Transform camera;
    private float distance;

    void Start()
    {
        targetSideRotation = transform.eulerAngles.y;
        currentSideRotation = transform.eulerAngles.y;
        targetUpRotation = transform.eulerAngles.x;
        currentUpRotation = transform.eulerAngles.x;
        distance = -camera.localPosition.z;             //相机局部坐标z值为-1.8,那么相机与距离人物为1.8
    }

    void Update()
    {
        if (!pivot) return;

        Follow();
        DragRotate();
        ScrollScale();
        OcclusionJudge();
    }

    void Follow()
    {
        transform.position = Vector3.Lerp(transform.position, pivot.position, Time.deltaTime * 5);             //相机跟随角色的插值,相机当前帧的实际位置为它们中间10%的位置
        camera.localPosition = -Vector3.forward * distance;                                                     //仅z有值,并且方向为负
    }

    float MinimumDegree = 0;
    float MaximumDegree = 60;
    private float targetSideRotation;
    private float targetUpRotation;
    private float currentSideRotation;
    private float currentUpRotation;
    void DragRotate()
    {
        if (Input.GetMouseButton(0))
        {
            targetSideRotation += Input.GetAxis("Mouse X") * 5;
            targetUpRotation -= Input.GetAxis("Mouse Y") * 5;
        }

        targetUpRotation = Mathf.Clamp(targetUpRotation, MinimumDegree, MaximumDegree);

        currentSideRotation = Mathf.LerpAngle(currentSideRotation, targetSideRotation, Time.deltaTime * 5);
        currentUpRotation = Mathf.Lerp(currentUpRotation, targetUpRotation, Time.deltaTime * 5);
        transform.rotation = Quaternion.Euler(currentUpRotation, currentSideRotation, 0);
    }

    float MinimumDistance = 1;
    float MaximumDistance = 4;
    void ScrollScale()
    {
        distance *= (1 - Input.GetAxis("Mouse ScrollWheel") * 0.2f);        //在原值的基础上调整为原值的百分比
        distance = Mathf.Clamp(distance, MinimumDistance, MaximumDistance);
        if(Input.GetAxis("Mouse ScrollWheel")!=0)
            preferdDistance = distance;
    }

    float preferdDistance = 1;
    bool resumable = false;
    void OcclusionJudge()
    {
        Vector3 perferdCamPos = transform.position - camera.forward * preferdDistance;
        Debug.DrawLine(perferdCamPos, pivot.position, Color.red);

        if (Physics.Raycast(camera.position,camera.forward,distance - MinimumDistance))               
        {
            resumable = true;

            distance = NearestObstacleDistance(pivot);

            while (Physics.Raycast(camera.position, camera.forward, distance - MinimumDistance) && distance > MinimumDistance)
            {
                distance *= 0.99f;
                distance = Mathf.Clamp(distance, MinimumDistance, MaximumDistance);
                float dist = Mathf.Lerp(-camera.transform.localPosition.z, distance, 1f);
                camera.localPosition = -Vector3.forward * dist;
            }
        }

        if (!resumable) return;

        if (resumable && !Physics.Raycast(perferdCamPos, camera.forward, preferdDistance - MinimumDistance))
        {
            distance = preferdDistance;
            float dist = Mathf.Lerp(-camera.transform.localPosition.z, distance, 1f);
            camera.localPosition = -Vector3.forward * distance;
            resumable = false;
        }
    }

    float NearestObstacleDistance(Transform start)
    {
        float dis = float.MaxValue;
        RaycastHit hit;
        Physics.Raycast(start.position, start.forward, out hit);
        if(hit.distance!=0) dis = Mathf.Min(dis, hit.distance);
        Physics.Raycast(start.position, -start.forward, out hit);
        if (hit.distance != 0) dis = Mathf.Min(dis, hit.distance);
        Physics.Raycast(start.position, start.right, out hit);
        if (hit.distance != 0) dis = Mathf.Min(dis, hit.distance);
        Physics.Raycast(start.position, -start.right, out hit);
        if (hit.distance != 0) dis = Mathf.Min(dis, hit.distance);
        return dis;
    }
}

效果就不演示了,比之前写的那个要好不少

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-03-10 22:58:11  更:2022-03-10 22:59:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 14:31:28-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码