当前位置: 首页 > news >正文

Unity笔记:相机移动

基础知识

鼠标输入

在Unity中,开发者在“Edit” > “Project Settings” > “Input Manager”中设置输入,如下图所示:

在设置了Mouse X后,Input.GetAxis("Mouse X")返回的是鼠标在X轴上的增量值。这意味着它会返回鼠标在上一帧和当前帧之间的变化量。如果鼠标在X轴上向右移动,返回值将是正数;如果鼠标向左移动,返回值将是负数。

根据Unity官方文档 - Input.GetAxis的说明,这里要强调的是:Input.GetAxis返回由axisName标识的虚拟轴的值(没说是增量)

对于键盘和操纵杆输入设备,该值将在 [ − 1 , 1 ] [-1,1] [1,1]的范围内。

如果将轴映射到鼠标,则值会有所不同,并且不会在 [ − 1 , 1 ] [-1,1] [1,1]的范围内。相反,它将是当前鼠标增量乘以轴灵敏度。通常,正值表示鼠标向右/向下移动,负值表示鼠标向左/向上移动。

这与帧速率无关;使用此值时,不需要担心帧速率的变化。

相机代码及解析

基本代码

using UnityEngine;public class CameraController: MonoBehaviour
{[Tooltip("the object that camera look at")]public Transform targetObject;  // 指定的物体public float distance = 5.0f;   // 相机距离public float rotationSpeed = 2.0f;  // 旋转速度private float currentRotationX = 0.0f;private float currentRotationY = 0.0f;void Start(){if (targetObject == null){Debug.LogError("Please assign a target object to the CameraManager script.");}}void Update(){// 获取鼠标输入float mouseX = Input.GetAxis("Mouse X");float mouseY = Input.GetAxis("Mouse Y");// 计算旋转角度,单位是度currentRotationX -= mouseY * rotationSpeed;currentRotationY += mouseX * rotationSpeed;// 限制垂直旋转角度在-90到90度之间currentRotationX = Mathf.Clamp(currentRotationX, -90.0f, 90.0f);// 计算相机位置Vector3 direction = new Vector3(0, 0, -distance);Quaternion rotation = Quaternion.Euler(currentRotationX, currentRotationY, 0);Vector3 cameraPosition = targetObject.position + rotation * direction;// 应用相机位置和旋转transform.position = cameraPosition;transform.LookAt(targetObject.position);}
}

主要先旋转相机,再通过LookAt方法使之朝向人物就完事了。所以核心就是计算相机位置的三行代码(如下)。

// 计算相机位置
Vector3 direction = new Vector3(0, 0, -distance);
Quaternion rotation = Quaternion.Euler(currentRotationX, currentRotationY, 0);
Vector3 cameraPosition = targetObject.position + rotation * direction;

Quaternion×Vector3的意义:四元数×三维向量会得到一个新的Vector3,表示旋转后的新方向。

首先定义了一个叫做direction的三维向量,这里说实话我本身没想明白,困扰了很久。
在这里插入图片描述
(上图略去了y轴)

但是我查了一下,一个局部坐标系的Vector3变量乘以一个世界坐标系表示旋转操作的四元数,其结果是世界坐标系的Vector3变量

那这样就好理解了,这个direction不是世界坐标系的(不是图中红色箭头),而是上图那个局部坐标系的,它代表了一个从相机朝向目标物体的一个向量,尽管相机是时刻移动的(相应地这个局部坐标系在全局坐标系的位置和方向也在变),但是乘完之后总是能得到一个全局的、经过旋转变换之后的量。

延伸1:Unity默认局部坐标系的Z轴是对象的前方(朝向),X轴是右方,Y轴是上方。

延伸2:在Quaternion乘法中,顺序很重要,因为乘法是不符合交换律的。

相比之下一种看似正确实则错误的写法是如下这种(显然是没理解direction到底是啥):

// 计算相机位置
Vector3 direction = new Vector3(0, 0, -distance);
Quaternion rotation = Quaternion.Euler(currentRotationX, currentRotationY, 0);
Vector3 globalOffset = camTransform.TransformPoint(rotation * direction);
Vector3 cameraPosition = targetObject.position + globalOffset;

碰撞检测与SpringArm

碰撞检测和弹簧臂是相辅相成的。

如果游戏环境中有障碍物,就得考虑实现碰撞检测,以防止相机穿过物体。(通常需要使用Raycast来检查相机和目标之间的障碍物)。但是硬生生直接变化相机和人物的距离有些生硬,所以还要实现弹簧臂。

弹簧臂的基本原理是将相机连接到一个虚拟的弹簧臂结构上,这个结构允许相机在跟随目标的同时保持一定的弹性。弹簧臂可以有一定的长度,角度和阻尼参数,使相机能够在目标移动时更加平滑地跟随。

在Unity中,可以使用SpringJoint或编写自定义的弹簧臂逻辑来实现这一点。弹簧臂常见的实现及其优缺点如下:

  1. Transform.Lerp:

    • 优点:
      • 实现简单,易于理解。
      • 不需要额外的组件或配置。
    • 缺点:
      • 在快速移动的情况下,可能会感觉到迟滞,因为它只是简单地进行线性插值,可能无法捕捉到加速和减速的变化。
  2. SpringJoint组件:

    • 优点:
      • 使用物理引擎,可以产生更真实的弹簧效果。
      • 不需要手动编写平滑插值逻辑。
    • 缺点:
      • 对性能的影响较大,特别是在移动的物体较多的情况下。
      • 需要调整SpringJoint的参数来获取理想的效果,这可能需要一些调试工作。
  3. Vector3.SmoothDamp:

    • 优点:
      • 提供更高级的平滑插值算法,能够更好地处理加速和减速。
      • 相比Lerp,更适合处理相机跟随玩家运动的场景。
    • 缺点:
      • 可能需要调整参数以适应不同的场景。
      • 对于初学者来说,可能需要一些时间来理解其工作原理。

有时候也可以结合多个方法,根据不同的情况使用不同的技术。例如,在高速移动时使用Vector3.SmoothDamp,在需要物理效果时使用SpringJoint

碰撞检测实现

using UnityEngine;public class CameraController: MonoBehaviour
{[Tooltip("the object that camera look at")]public Transform targetObject;  // 指定的物体[Tooltip("the distance that from the camera to the target")]public float distance = 5.0f;   // 相机距离[Tooltip("碰撞检测平滑过渡的时间")]public float smoothTime = 0.3f;[Tooltip("相机碰撞检测的层")]public LayerMask obstacleLayer;public float rotationSpeed = 2.0f;  // 旋转速度// camera rotateprivate float currentRotationX = 0.0f;private float currentRotationY = 0.0f;private Transform camTransform;// SpringArmprivate Vector3 velocity = Vector3.zero;void Start(){if (targetObject == null){Debug.LogError("Please assign a target object to the CameraManager script.");}camTransform = GetComponent<Transform>();}void Update(){// 获取鼠标输入float mouseX = Input.GetAxis("Mouse X");float mouseY = Input.GetAxis("Mouse Y");// 计算旋转角度,单位是度currentRotationX -= mouseY * rotationSpeed;currentRotationY += mouseX * rotationSpeed;// 限制垂直旋转角度在-85到85度之间currentRotationX = Mathf.Clamp(currentRotationX, -85.0f, 85.0f);// 计算相机位置Vector3 direction = new Vector3(0, 0, -distance);Quaternion rotation = Quaternion.Euler(currentRotationX, currentRotationY, 0);Vector3 desiredCameraPosition = targetObject.position + rotation * direction;// 进行碰撞检测并调整相机位置RaycastHit hit;if (Physics.Raycast(targetObject.position, desiredCameraPosition - targetObject.position, out hit, distance, obstacleLayer)){// 如果碰撞到障碍物,调整相机位置Vector3 adjustedCameraPosition = hit.point;transform.position = Vector3.SmoothDamp(transform.position, adjustedCameraPosition, ref velocity, smoothTime);}else{// 如果没有碰撞,直接移动相机到目标位置// 这里也可以使用SmoothDamp,但是效果有些怪transform.position = desiredCameraPosition;}// 应用相机旋转transform.LookAt(targetObject.position);}
}

主要就是在应用transform.position的时候前进行碰撞检测并查看其结果,若有碰撞结果就把相机位置改到那里。
当然这样的话碰到障碍物变化起来也有些生硬,可以再观察别的游戏细化,加更多的逻辑。而且这里的碰撞点是很不合适的(随着人物靠近障碍物,相机总是靠近人物脚,所以还得改y轴)

相关文章:

Unity笔记:相机移动

基础知识 鼠标输入 在Unity中&#xff0c;开发者在“Edit” > “Project Settings” > “Input Manager”中设置输入&#xff0c;如下图所示&#xff1a; 在设置了Mouse X后&#xff0c;Input.GetAxis("Mouse X")返回的是鼠标在X轴上的增量值。这意味着它会…...

Java项目管理01-Maven基础

一、Maven的常用命令和生命周期 1.Maven的常用命令使用方式 complie&#xff1a;编译&#xff0c;将java文件编译为class字节码文件 clean&#xff1a;清理&#xff0c;删除字节码文件 test&#xff1a;测试&#xff0c;运行项目中的test类 package&#xff1a;打包&#x…...

计算机网络(第六版)复习提纲30

B HTTP 名词解释&#xff1a;协议HTTP定义了浏览器怎样向万维网服务器请求万维网文档&#xff0c;以及服务器怎样把文档传给浏览器。从层次的角度看&#xff0c;HTTP是面向事务的应用层协议&#xff0c;它是万维网上可靠地交换文件的重要基础&#xff0c;不仅能够传送完成超文本…...

基于SSM的图书管理系统

点击以下链接获取资源&#xff1a; https://download.csdn.net/download/qq_64505944/88820548?spm1001.2014.3001.5503 Java项目-6 librarySystem 开发完毕 万一你要作为课程设计或者毕设&#xff0c;不太会配&#xff0c;可以到下面我博客中私信&#xff0c;我帮你远程部…...

【GAMES101】Lecture 19 相机

目录 相机 视场 Field of View (FOV) 曝光&#xff08;Exposure&#xff09; 感光度&#xff08;ISO&#xff09; 光圈 快门 相机 成像可以通过我们之前学过的光栅化成像和光线追踪成像来渲染合成&#xff0c;也可以用相机拍摄成像 今天就来学习一下相机是如何成像的…...

《走进科学》灵异事件:Nginx配置改了之后一直报错

想要安装WoWSimpleRegistration&#xff0c;就定下来要用nginxphp8 &#xff0c;结果nginx那里加上php的支持之后一直报错&#xff1a; $ sudo service nginx restart Job for nginx.service failed because the control process exited with error code. See "systemctl…...

Select 选择器 el-option 回显错误 value

离谱 回显的内容不是 label 而是 value 的值 返回官方看说明&#xff1a; v-model的值为当前被选中的el-option的 value 属性值 value / v-model 绑定值有3种类型 boolean / string / number 根据自身代码猜测是&#xff1a;tableData.bookId 与 item.id 类型不一致导致 &…...

【51单片机Keil+Proteus8.9】门锁控制电路

门锁控制电路 二、设计思路 电路设计 1.电源部分&#xff1a;使用BATTERY为整个电路提供电源&#xff0c;可以在电路中加入一个电 源开关&#xff0c;以便控制电源的开启和关闭。 2.处理器部分&#xff1a;使用AT89C51芯片作为主处理器&#xff0c;通过编写程序实现门锁的 …...

比较Kamailio和OpenSIPS的重写contact函数

Kamailio&#xff1a;调用set_contact_alias()之后&#xff0c;在原有的contact的后面增加参数&#xff0c;具体地说&#xff0c;就是网络地址&#xff0c;网络端口和transport&#xff0c;好处是收到后续请求之时可以恢复原有contact的内容&#xff08;当然也有坏处&#xff0…...

【ETOJ P1046】斐波那契数列 题解(数学+动态规划)

题目描述 给定一个整数 T T T&#xff0c;表示样例数。 对于每个样例&#xff0c;给定一个整数 n n n&#xff0c;求斐波那契数列的第 n n n 项。 斐波那契数列定义为 f ( 1 ) f ( 2 ) 1 f(1) f(2) 1 f(1)f(2)1&#xff0c; f ( n ) f ( n − 1 ) f ( n − 2 ) f(…...

编码技巧——基于RedisTemplate的RedisClient实现、操作Lua脚本

1. 背景 在新公司的脚手架中开发&#xff0c;需要用到redis&#xff0c;发现没有封装好一套能集成各种常用命令、包括Lua脚本的方便使用的RedisTemplateClient&#xff0c;于是自己来实现下&#xff1b; springboot整合redis之后&#xff0c;提供了操作redis的简便方式&#…...

Asp .Net Core 系列:Asp .Net Core 集成 Panda.DynamicWebApi

文章目录 简介Asp .Net Core 集成 Panda.DynamicWebApi配置原理什么是POCO Controller&#xff1f;POCO控制器原理ControllerFeatureProvider实现自定义判断规则IApplicationModelConventionPanda.DynamicWebApi中的实现ConfigureApiExplorer()ConfigureSelector()ConfigurePar…...

【PTA浙大版《C语言程序设计(第4版)》|编程题】习题7-3 判断上三角矩阵(附测试点)

目录 输入格式&#xff1a; 输出格式&#xff1a; 输入样例&#xff1a; 输出样例&#xff1a; 代码呈现 测试点 上三角矩阵指主对角线以下的元素都为0的矩阵&#xff1b;主对角线为从矩阵的左上角至右下角的连线。 本题要求编写程序&#xff0c;判断一个给定的方阵是否…...

JVM 性能调优 - 参数调优(3)

查看 JVM 内存的占用情况 编写代码 package com.test;public class PrintMemoryDemo {public static void main(String[] args) {// 堆内存总量long totalMemory Runtime.getRuntime().totalMemory();// jvm 试图使用的最大堆内存long maxMemory Runtime.getRuntime().maxM…...

Django(十)

1. Ajax请求 浏览器向网站发送请求时&#xff1a;URL 和 表单的形式提交。 GETPOST 特点&#xff1a;页面刷新。 除此之外&#xff0c;也可以基于Ajax向后台发送请求&#xff08;偷偷的发送请求&#xff09;。 依赖jQuery编写ajax代码 $.ajax({url:"发送的地址"…...

OpenHarmony开源鸿蒙开发之旅

文章目录 一、op系统架构二、op系统构建1. op源代码目录2. op系统构建3. op开发环境搭建 三、op系统的子系统四、op系统芯片移植五、op系统启动流程六、op系统组件七、驱动框架 一、op系统架构 二、op系统构建 1. op源代码目录 2. op系统构建 3. op开发环境搭建 三、op系统…...

SpringBoot之整合PageHelper分页插件

SpringBoot之整合PageHelper分页插件 文章目录 SpringBoot之整合PageHelper分页插件1. 引入坐标2. application.yml配置3. 基本使用4. 对多个查询执行分页1. 默认第一个Select语句会执行分页2. 让Pagehelper也能执行多个分页的方法3. 完整案例 详细配置请查看官网或MyBatis分页…...

Android java基础_类的封装

一.面向对象编程的引入 写一个简单的程序输出张三&#xff0c;李四的名字 class Person {String name;String getName() {return "guangdong "name;} };public class Oop {public static void main(String args[]) {Person p1 new Person();p1.name "zhangs…...

Vue-57、Vue技术路由的参数如何传递

query参数传递 1、传递参数 <!-- 跳转路由并携带query参数&#xff0c;to的字符串写法--> <router-link :to"/home/message/detail?id${p.id}&title${p.title}"> {{p.title}} </router-link><!-- 跳转路由…...

《MySQL 简易速速上手小册》第1章:MySQL 基础和安装(2024 最新版)

文章目录 1.1 MySQL 概览&#xff1a;版本、特性和生态系统1.1.1 基础知识1.1.2 重点案例&#xff1a;使用 Python 实现 MySQL 数据的 CRUD 操作1.1.3 拓展案例 1&#xff1a;使用 Python 实现 MySQL 数据备份**1.1.4 拓展案例 2&#xff1a;使用 Python 分析 MySQL 数据 1.2 安…...

保姆级教程:用iSYSTEM winIDEA和iC5000给S32K148烧录程序,附完整配置流程

从零掌握iSYSTEM工具链&#xff1a;S32K148开发板烧录与调试全流程实战第一次接触iSYSTEM的winIDEA和iC5000仿真器时&#xff0c;很多嵌入式开发者都会感到无从下手。不同于常见的开源工具链&#xff0c;这套专业级开发环境在汽车电子和工业控制领域有着广泛应用&#xff0c;尤…...

智能检索新范式,让AIAgent自主决策,提升RAG效率100%!

市面上的 RAG 系统&#xff0c;不管叫什么名字&#xff0c;本质上只有两种做法&#xff1a; 第一种&#xff0c;一次性检索。把用户的 query 向量化&#xff0c;从语料库里捞出 Top-K 个文档片段&#xff0c;拼成一个大 prompt 塞给模型。GraphRAG、HippoRAG、LightRAG 都属于…...

告别FTP龟速:用NTFS-3G在CentOS7上直连移动硬盘拷贝200G大文件

告别FTP龟速&#xff1a;用NTFS-3G在CentOS7上直连移动硬盘拷贝200G大文件当面对数百GB的设计素材、日志文件或数据库备份需要迁移时&#xff0c;传统的FTP传输往往会成为效率瓶颈。我曾在一个视频处理项目中&#xff0c;需要将230GB的4K原始素材从移动硬盘导入服务器&#xff…...

从入门到实践:EEG公开数据集分类与应用场景全解析

1. EEG公开数据集入门指南刚接触脑电信号分析的研究者&#xff0c;常常会被一个问题困扰&#xff1a;"我应该从哪里获取可靠的EEG数据&#xff1f;"作为一个在这个领域摸爬滚打多年的研究者&#xff0c;我完全理解这种困惑。记得我第一次接触EEG研究时&#xff0c;光…...

航空航天为什么离不开高强镁合金?国产替代到哪一步了

飞机每减重一千克&#xff0c;全年大约节省四千两百美元的燃油费用——这是航空工程师熟悉的经验值。在商业航空领域&#xff0c;这个数字还只是财务账&#xff1b;在战斗机、导弹和卫星的世界里&#xff0c;减重的收益被换算成更远的航程、更大的载荷、更高的机动性&#xff0…...

0.2毫秒快速启动的操作系统

在工业控制以及航空航天等核心场景&#xff0c;极速启动就是高可靠系统的生命线。0.2毫秒超快启动搭配硬件看门狗&#xff0c;让设备在掉电重启、异常恢复时瞬时归位&#xff0c;关键任务永不延误&#xff01; https://www.bilibili.com/video/BV11mLY6VERt/?spm_id_from333.1…...

当 AI Coding 进入复杂企业系统,为什么提效远没有宣传里那么美好 ?

以 Claude Code、Codex 为代表的自主编码智能体&#xff08;Coding Agents&#xff09;&#xff0c;正在以惊人的速度席卷软件开发者生态。与此同时&#xff0c;类似“10 倍开发效率”“普通人也能随手构建软件”“程序员即将失业”的说法&#xff0c;也随处可见。这种不分场景…...

DeepSeek重复代码识别失效了?5个被90%团队忽略的AST解析盲区及修复清单

更多请点击&#xff1a; https://codechina.net 第一章&#xff1a;DeepSeek代码重复检测失效的真相与影响 DeepSeek-R1 模型在代码理解任务中表现出色&#xff0c;但其内置的代码重复检测机制在特定场景下存在系统性失效。根本原因在于模型对语义等价但语法结构差异显著的代…...

构建智能音乐档案:SoundCloud Downloader 的技术架构与实现哲学

构建智能音乐档案&#xff1a;SoundCloud Downloader 的技术架构与实现哲学 【免费下载链接】scdl Soundcloud Music Downloader 项目地址: https://gitcode.com/gh_mirrors/sc/scdl 在流媒体音乐主导的时代&#xff0c;音乐爱好者面临着一种矛盾&#xff1a;我们享受着…...

遭遇薪酬倒挂后的反向谈判与资产重估策略「蒸汽求职分享」

在 2026 年全球科技大厂与跨国泛金融巨头追求极致人效、频繁进行组织架构重组&#xff08;Reorg&#xff09;的买方市场中&#xff0c;一个让无数海外名校留学生在入职两年后心态瞬间崩塌的现象&#xff0c;正在高频发生——“薪酬倒挂&#xff08;Salary Inversion&#xff09…...