厦门市建设局政府网站/广东省白云区
基础知识
鼠标输入
在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
或编写自定义的弹簧臂逻辑来实现这一点。弹簧臂常见的实现及其优缺点如下:
-
Transform.Lerp:
- 优点:
- 实现简单,易于理解。
- 不需要额外的组件或配置。
- 缺点:
- 在快速移动的情况下,可能会感觉到迟滞,因为它只是简单地进行线性插值,可能无法捕捉到加速和减速的变化。
- 优点:
-
SpringJoint组件:
- 优点:
- 使用物理引擎,可以产生更真实的弹簧效果。
- 不需要手动编写平滑插值逻辑。
- 缺点:
- 对性能的影响较大,特别是在移动的物体较多的情况下。
- 需要调整SpringJoint的参数来获取理想的效果,这可能需要一些调试工作。
- 优点:
-
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中,开发者在“Edit” > “Project Settings” > “Input Manager”中设置输入,如下图所示: 在设置了Mouse X后,Input.GetAxis("Mouse X")返回的是鼠标在X轴上的增量值。这意味着它会…...

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

计算机网络(第六版)复习提纲30
B HTTP 名词解释:协议HTTP定义了浏览器怎样向万维网服务器请求万维网文档,以及服务器怎样把文档传给浏览器。从层次的角度看,HTTP是面向事务的应用层协议,它是万维网上可靠地交换文件的重要基础,不仅能够传送完成超文本…...

基于SSM的图书管理系统
点击以下链接获取资源: https://download.csdn.net/download/qq_64505944/88820548?spm1001.2014.3001.5503 Java项目-6 librarySystem 开发完毕 万一你要作为课程设计或者毕设,不太会配,可以到下面我博客中私信,我帮你远程部…...

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

《走进科学》灵异事件:Nginx配置改了之后一直报错
想要安装WoWSimpleRegistration,就定下来要用nginxphp8 ,结果nginx那里加上php的支持之后一直报错: $ 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 的值 返回官方看说明: v-model的值为当前被选中的el-option的 value 属性值 value / v-model 绑定值有3种类型 boolean / string / number 根据自身代码猜测是:tableData.bookId 与 item.id 类型不一致导致 &…...

【51单片机Keil+Proteus8.9】门锁控制电路
门锁控制电路 二、设计思路 电路设计 1.电源部分:使用BATTERY为整个电路提供电源,可以在电路中加入一个电 源开关,以便控制电源的开启和关闭。 2.处理器部分:使用AT89C51芯片作为主处理器,通过编写程序实现门锁的 …...

比较Kamailio和OpenSIPS的重写contact函数
Kamailio:调用set_contact_alias()之后,在原有的contact的后面增加参数,具体地说,就是网络地址,网络端口和transport,好处是收到后续请求之时可以恢复原有contact的内容(当然也有坏处࿰…...

【ETOJ P1046】斐波那契数列 题解(数学+动态规划)
题目描述 给定一个整数 T T T,表示样例数。 对于每个样例,给定一个整数 n n n,求斐波那契数列的第 n n n 项。 斐波那契数列定义为 f ( 1 ) f ( 2 ) 1 f(1) f(2) 1 f(1)f(2)1, f ( n ) f ( n − 1 ) f ( n − 2 ) f(…...

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

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

【PTA浙大版《C语言程序设计(第4版)》|编程题】习题7-3 判断上三角矩阵(附测试点)
目录 输入格式: 输出格式: 输入样例: 输出样例: 代码呈现 测试点 上三角矩阵指主对角线以下的元素都为0的矩阵;主对角线为从矩阵的左上角至右下角的连线。 本题要求编写程序,判断一个给定的方阵是否…...

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请求 浏览器向网站发送请求时:URL 和 表单的形式提交。 GETPOST 特点:页面刷新。 除此之外,也可以基于Ajax向后台发送请求(偷偷的发送请求)。 依赖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基础_类的封装
一.面向对象编程的引入 写一个简单的程序输出张三,李四的名字 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参数,to的字符串写法--> <router-link :to"/home/message/detail?id${p.id}&title${p.title}"> {{p.title}} </router-link><!-- 跳转路由…...

《MySQL 简易速速上手小册》第1章:MySQL 基础和安装(2024 最新版)
文章目录 1.1 MySQL 概览:版本、特性和生态系统1.1.1 基础知识1.1.2 重点案例:使用 Python 实现 MySQL 数据的 CRUD 操作1.1.3 拓展案例 1:使用 Python 实现 MySQL 数据备份**1.1.4 拓展案例 2:使用 Python 分析 MySQL 数据 1.2 安…...

Linux 软件管理(YUM RPM)
1 YUM yum(全称为 Yellow dog Updater, Modified)是一个在Fedora和RedHat以及CentOS中的Shell前端软件包管理器。基于RPM包管理,能够从指定的服务器自动处理依赖性关系,并且一次安装所有依赖的软件包,无须繁琐地一次次…...

【Makefile语法 05】动静态库编译链接
目录 一、多文件项目源代码 二、静态库编译链接 三、动态库编译链接 一、多文件项目源代码 // include/add.hpp#pragma once int add(int a, int b); // include/sub.hpp#pragma once int sub(int a, int b); // src/add.cpp#include "add.hpp"int add(int a, …...

JS - 处理元素滚动
业务功能中时常有元素滚动的功能,现在就总结一下一些常用的事件。 一、定位滚动元素 做一切滚动操作之前都应该先定位到滚动元素,再做其他操作,如滚动顶部,获取滚动距离、禁止滚动等。 把以下代码复制粘贴到浏览器 Console 面板…...

JavaScript滚动事件
🧑🎓 个人主页:《爱蹦跶的大A阿》 🔥当前正在更新专栏:《VUE》 、《JavaScript保姆级教程》、《krpano》、《krpano中文文档》 ✨ 前言 滚动是网页交互不可或缺的一部分。监听页面和元素的滚动事件,可以帮助…...

4.0 Zookeeper Java 客户端搭建
本教程使用的 IDE 为 IntelliJ IDEA,创建一个 maven 工程,命名为 zookeeper-demo,并且引入如下依赖,可以自行在maven中央仓库选择合适的版本,介绍原生 API 和 Curator 两种方式。 IntelliJ IDEA 相关介绍:…...

C#既然数组长度不可改变,那么如何动态调整集合类型数组大小,以便添加或删除元素?
目录 1.使用动态数组(ArrayList): 2.使用 jagged array(不规则数组): 3.使用 List : 4.使用数组复制: 在C#中,数组的长度是固定的,一旦声明和初始化&…...

3.1 Verilog 连续赋值
关键词:assign, 全加器 连续赋值语句是 Verilog 数据流建模的基本语句,用于对 wire 型变量进行赋值。: 格式如下 assign LHS_target RHS_expression ; LHS(left hand side) 指赋值操作…...

【http】2、http request header Origin 属性、跨域 CORS、同源、nginx 反向代理、预检请求
文章目录 一、Origin 含义二、跨源资源共享:**Cross-Origin Resource Sharing** CORS2.1 跨域的定义2.2 功能概述2.3 场景示例2.3.1 简单请求2.3.2 Preflighted requests:预检请求 2.4 header2.4.1 http request header2.4.1.1 Origin2.4.1.2 Access-Con…...

LangChain pdf的读取以及向量数据库的使用
以下使用了3399.pdf, Rockchip RK3399 TRM Part1 import ChatGLM from langchain.chains import LLMChain from langchain_core.output_parsers import StrOutputParser from langchain_core.prompts import ChatPromptTemplate from langchain.chains import Simp…...

VUE学习——事件修饰符
阻止默认事件 <template><a click"onClickHandle" href"https://www.baidu.com">baidu</a><a click.prevent"onClickHandle" href"https://www.baidu.com">baidu</a> </template> <script>…...