当前位置: 首页 > 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 安…...

ThinkPad X1 Tablet Gen3 vs Gen2键盘对比:为何Gen3更适合改装Type-C?

ThinkPad X1 Tablet Gen3键盘Type-C改装全解析&#xff1a;为何它成为DIY玩家的终极选择&#xff1f; 在移动办公设备轻量化与模块化设计成为主流的今天&#xff0c;ThinkPad X1 Tablet系列凭借其独特的二合一形态和标志性键盘手感&#xff0c;始终保持着特殊地位。特别是第三代…...

从聊天机器人到业务执行者:Agentic Orchestration 如何重构 Java 后端体系

引言 在 RAG 1.0 时代&#xff0c;我们费尽心思让 AI“说得对、答得准”&#xff1b; 而进入 2026 年的 Agentic Orchestration&#xff08;智能体编排&#xff09; 时代&#xff0c;我们的目标已经变成&#xff1a;让 AI 做得对、跑得稳、能闭环。 用户说“帮我把昨天买贵的衣…...

OpenGOAL编译器实战指南:如何构建你自己的Jak游戏

OpenGOAL编译器实战指南&#xff1a;如何构建你自己的Jak游戏 【免费下载链接】jak-project Reviving the language that brought us the Jak & Daxter Series 项目地址: https://gitcode.com/gh_mirrors/ja/jak-project OpenGOAL编译器是一个强大的工具&#xff0c…...

Python农业物联网开发必踩的5个致命坑,第3个让某省级智慧农场损失87万元(含Grafana+InfluxDB实时告警配置模板)

第一章&#xff1a;Python农业物联网开发必踩的5个致命坑&#xff0c;第3个让某省级智慧农场损失87万元&#xff08;含GrafanaInfluxDB实时告警配置模板&#xff09;传感器数据时间戳漂移导致历史分析全盘失效 Python中若直接使用time.time()或datetime.now()采集温湿度传感器数…...

避坑指南:思科模拟器做链路聚合时,你可能会遇到的5个报错及解决方法

思科模拟器链路聚合实战&#xff1a;5个典型报错分析与精准排错指南 在Packet Tracer中配置链路聚合时&#xff0c;最令人头疼的往往不是基础配置步骤&#xff0c;而是那些突如其来的报错信息。上周有位学员在CCNA备考群里发了一张截图&#xff1a;%EC-5-CANNOT_BUNDLE2: Fa0/2…...

AI_NovelGenerator:如何在7天内完成传统写作需要3个月的长篇小说创作

AI_NovelGenerator&#xff1a;如何在7天内完成传统写作需要3个月的长篇小说创作 【免费下载链接】AI_NovelGenerator 使用ai生成多章节的长篇小说&#xff0c;自动衔接上下文、伏笔 项目地址: https://gitcode.com/GitHub_Trending/ai/AI_NovelGenerator 问题诊断&…...

从Vaihingen数据集到训练样本:高分辨率遥感影像语义分割全流程实战

1. 初识Vaihingen数据集&#xff1a;遥感语义分割的黄金标准 第一次接触Vaihingen数据集时&#xff0c;我被它5厘米的超高分辨率震撼到了。这个由ISPRS提供的基准数据集&#xff0c;虽然只包含38张60006000像素的影像&#xff0c;但每张都清晰地展现了德国小镇Vaihingen的街道、…...

i.MX6ULL开发板无线SSH环境搭建指南

嵌入式开发板远程登录环境搭建指南1. 项目概述本技术文档详细记录了在基于i.MX6ULL处理器的嵌入式Linux开发板上搭建完整远程登录环境的实现方案。该方案包含三个核心组件&#xff1a;WiFi网络驱动移植、无线网络配置工具移植以及SSH服务部署。2. 硬件环境搭建2.1 WiFi模块选型…...

Windows Cleaner:智能存储管理解决方案让C盘空间释放效率提升60%

Windows Cleaner&#xff1a;智能存储管理解决方案让C盘空间释放效率提升60% 【免费下载链接】WindowsCleaner Windows Cleaner——专治C盘爆红及各种不服&#xff01; 项目地址: https://gitcode.com/gh_mirrors/wi/WindowsCleaner 当系统频繁弹出"磁盘空间不足&q…...

YimMenu终极指南:免费GTA5辅助工具完整使用教程

YimMenu终极指南&#xff1a;免费GTA5辅助工具完整使用教程 【免费下载链接】YimMenu YimMenu, a GTA V menu protecting against a wide ranges of the public crashes and improving the overall experience. 项目地址: https://gitcode.com/GitHub_Trending/yi/YimMenu …...