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

Unity组件开发--相机跟随角色和旋转

1.相机跟随组件,节点:

2.相机跟随组件脚本:

using System;
using System.Collections;
using System.Collections.Generic;
using Unity.Burst.Intrinsics;
using UnityEngine;
using UnityEngine.UI;public class CameraFollow : Singleton<CameraFollow> {public Transform firstAngleTarget; //第一人称跟随的目标public Transform threeAngleTarget; //第三人称跟随的目标public float radius;public float polarDeg;public float elevationDeg;private Transform target;public bool isLookAt;public float lerpSpeed = 0;//是否第一人称视角private bool isFirstAngle = false;LayerMask mask;/// <summary>/// 极坐标转换成笛卡尔坐标/// </summary>/// <param name="radius"></param>/// <param name="angle"></param>/// <returns></returns>/// private bool isDriven;private void Awake() {EventManager.Instance.AddListener(EventName.PlayerDriving, (s, e) => {  //开车事件触发var arg = e as PlayerDrivingEventArgs;if (arg.driveObj && arg.driveObj.GetComponent<VehicleBase>() && arg.driveObj.GetComponent<VehicleBase>().driveCam) {gameObject.SetActive(false);}else {isDriven = true;}});EventManager.Instance.AddListener(EventName.PlayerDown, (s, e) => {  //开车事件触发var arg = e as PlayerDrivingEventArgs;                                              //isDriven = false;if (arg.driveObj && arg.driveObj.GetComponent<VehicleBase>() && arg.driveObj.GetComponent<VehicleBase>().driveCam) {gameObject.SetActive(true);}else {isDriven = false;}});}private void Start(){mask.value = (1 << LayerMask.NameToLayer("Ground")) | (1 << LayerMask.NameToLayer("Wall"));this.target = this.threeAngleTarget;EventManager.Instance.AddListener(EventName.ChangeAngle, changeAngle);var offset = SphericalToCartesian(radius, DegreeToRadian(polarDeg), DegreeToRadian(elevationDeg));//transform.position = Vector3.Lerp(transform.position, target.position + offset, Time.deltaTime * 10);transform.position = target.position + offset;}private void changeAngle(object sender, EventArgs e) {var data = e as AngleChangeEventArgs;if (data != null) {if (data.angleIndex == 1) {this.target = this.firstAngleTarget;this.radius = 0;isFirstAngle = true;transform.position = target.position;transform.forward = target.forward;} else if (data.angleIndex == 3) {this.target = this.threeAngleTarget;this.radius = 6;isFirstAngle = false;}}Debug.Log("摄像机视角改变" + e);}public Vector2 PolarToCartesian(float radius, float angle) {float x = radius * Mathf.Cos(angle);float y = radius * Mathf.Sin(angle);return new Vector2(x, y);}public static float DegreeToRadian(float degree) {return degree * Mathf.Deg2Rad;}public static Vector3 SphericalToCartesian(float radius, float polar, float elevation) {float a = radius * Mathf.Cos(elevation);float x = a * Mathf.Cos(polar);float y = radius * Mathf.Sin(elevation);float z = a * Mathf.Sin(polar);return new Vector3(x, y, z);}public static void CartesianToSpherical(Vector3 cartesian, out float radius, out float polar, out float elevation) {radius = Mathf.Sqrt(Mathf.Pow(cartesian.x, 2) + Mathf.Pow(cartesian.y, 2) + Mathf.Pow(cartesian.z, 2));polar = Mathf.Atan2(cartesian.z, cartesian.x);elevation = Mathf.Asin(cartesian.y / radius);}void LateUpdate() {if (isDriven) {var offset = SphericalToCartesian(6f, DegreeToRadian(270), DegreeToRadian(-15));transform.position = Vector3.Lerp(transform.position, target.TransformPoint(target.localPosition + offset), Time.deltaTime * 3);//transform.position = target.TransformPoint(target.localPosition + offset);transform.LookAt(target);return;}if (isFirstAngle) {//var offset = SphericalToCartesian(radius, DegreeToRadian(polarDeg), DegreeToRadian(elevationDeg));target.eulerAngles = new Vector3(elevationDeg, -polarDeg, 0);transform.forward = target.forward;transform.position = target.position;if (PlayerController.Instance.animator) {var euler = PlayerController.Instance.animator.transform.eulerAngles;PlayerController.Instance.animator.transform.eulerAngles = new Vector3(euler.x, target.eulerAngles.y, euler.z);}}else {Ctrl_Cam_Move();CtrThird();}}void CtrThird() {var offset = SphericalToCartesian(radius, DegreeToRadian(polarDeg), DegreeToRadian(elevationDeg));//更新相机位置//transform.position = target.position + offset;transform.position = target.position + offset;//TODO:做成CAMERA NEAR OBJ,进行隐藏if (PlayerController.Instance.animator != null) PlayerController.Instance.animator.gameObject.SetActive(true);//计算完位置之后处理让镜头不会穿墙Vector3 direction = transform.position - target.position;float distance = direction.magnitude;direction.Normalize();RaycastHit hit;if (Physics.Raycast(target.transform.position, direction, out hit, distance, mask.value)) {var dstPos = hit.point - distance * distance * direction * 0.01f;var offsetDis = target.position - dstPos;CartesianToSpherical(offsetDis, out var compareRadius, out _, out _);if (compareRadius < 1f)  {if (PlayerController.Instance.animator != null)  PlayerController.Instance.animator.gameObject.SetActive(false);}transform.position = dstPos;}transform.eulerAngles = target.eulerAngles;if (isLookAt) {transform.LookAt(target);}}public void Ctrl_Cam_Move(){if (EditorModel.Instance.CurrentUnlock != null) { //解锁其他物体的时候,镜头不动, 要前后移动的是物体return;}if (Input.GetAxis("Mouse ScrollWheel") > 0){//transform.Translate(Vector3.forward * 1f);//速度可调  自行调整radius = Math.Clamp(radius - 1.0f, 2, 15);}if (Input.GetAxis("Mouse ScrollWheel") < 0){//transform.Translate(Vector3.forward * -1f);//速度可调  自行调整radius = Math.Clamp(radius + 1.0f, 2, 15);}}
}

3.相机跟随角色视角旋转:


using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;public class CameraRotate : MonoBehaviour
{public float speedH;//public float speedVertical;public bool isMobile;//[Range(0f, 1f)]//public float damping;CameraFollow cameraFollow;private float currentHorizontal;private float currentVertical;private Vector3 lastMousePosition;private bool isDragging;float time;private float velocityY;private float velocityX;PointerEventData eventDataCurrentPosition;//private bool isDragging;public static CameraRotate instance;private void Awake() {instance = this;//UI交互要禁用玩家的控制cameraFollow = Camera.main.GetComponent<CameraFollow>();currentHorizontal = cameraFollow.polarDeg;time = Time.realtimeSinceStartup;}// Start is called before the first frame updatevoid Start() {}public void SetPolarDeg(float degree) {currentHorizontal = degree;cameraFollow.polarDeg = degree;}private bool IsPointerOverUIObject() {//判断是否点击的是UI,有效应对安卓没有反应的情况,true为UIif (eventDataCurrentPosition == null) {eventDataCurrentPosition = new PointerEventData(EventSystem.current);}eventDataCurrentPosition.position = new Vector2(Input.mousePosition.x, Input.mousePosition.y);List<RaycastResult> results = new List<RaycastResult>();EventSystem.current.RaycastAll(eventDataCurrentPosition, results);return results.Count > 0;}// Update is called once per framevoid LateUpdate() {//if (IsPointerOverUIObject()) {//    lastMousePosition = Input.mousePosition;//    return;//点击到UI不处理//}// 检查鼠标左键是否按下如果按下的那一下是在UI之上,则不让其旋转if (PlayerData.Instance.isRunningPC){if (Input.GetMouseButtonDown(0) && IsPointerOverUIObject() == false){// 记录鼠标点击位置lastMousePosition = Input.mousePosition;isDragging = true;}else if (Input.GetMouseButtonUp(0)){// 如果鼠标抬起,则需要重新按下鼠标来记录新的点击位置isDragging = false;}}else {if (Input.GetMouseButtonDown(0)){// 记录鼠标点击位置lastMousePosition = Input.mousePosition;isDragging = true;}else if (Input.GetMouseButtonUp(0)){// 如果鼠标抬起,则需要重新按下鼠标来记录新的点击位置isDragging = false;}}if (isDragging) {float speedHorizontal = speedH;float speedVertical = 0.1f;// 计算鼠标移动的增量Vector3 deltaMousePosition = Input.mousePosition - lastMousePosition;//Debug.Log("deltaMousePosition.x:" + deltaMousePosition.x + "deltaMousePosition.y:" + deltaMousePosition.y);// 计算水平旋转角度// 计算水平旋转角度float deltaHorizontal = speedHorizontal * deltaMousePosition.x;var newHorizontal = currentHorizontal - deltaHorizontal;//newHorizontal = Mathf.SmoothDamp(currentHorizontal, newHorizontal,ref velocityX, Time.unscaledDeltaTime);// 更新摄像机跟随脚本的旋转角度cameraFollow.polarDeg = newHorizontal;//Debug.Log("cameraFollow.polarDeg" + cameraFollow.polarDeg);currentHorizontal = newHorizontal;float deltaVertical = speedVertical * deltaMousePosition.y;var newVertical = currentVertical - deltaVertical;//newHorizontal = Mathf.SmoothDamp(currentVertical, newVertical, ref velocityY, Time.unscaledDeltaTime);// 更新摄像机跟随脚本的旋转角度cameraFollow.elevationDeg = Mathf.Clamp(newVertical, -90f, 89);currentVertical = newVertical;lastMousePosition = Input.mousePosition;}else {}}}

相关文章:

Unity组件开发--相机跟随角色和旋转

1.相机跟随组件&#xff0c;节点&#xff1a; 2.相机跟随组件脚本&#xff1a; using System; using System.Collections; using System.Collections.Generic; using Unity.Burst.Intrinsics; using UnityEngine; using UnityEngine.UI;public class CameraFollow : Singleton&…...

JavaScript系列——Proxy(代理)

文章目录 概要Proxy 语法handler 对象的方法Proxy 示例常用handler 对象的方法的参数handler.get()语法示例 handler.set()语法示例 使用场景验证值修正及附加属性 小结 概要 Proxy 用于创建一个对象的代理&#xff0c;将对原对象上的操作&#xff08;属性获取、赋值、函数调用…...

QT第三天

使用QT完成水果计价界面和功能&#xff0c;如下图&#xff1a; 运行结果&#xff1a; 代码&#xff1a; widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QListWidgetItem>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_N…...

Jetpack Compose -> 声明式UI Modifier

前言 本章主要介绍下 Compose 的声明式 UI 以及初级写法&#xff1b; 什么是声明式UI 传统UI 传统 UI 方式来声明UI <androidx.appcompat.widget.LinearLayoutCompat android:layout_width"match_parent" android:layout_height"match_parent&quo…...

windows10 装docker和docker compose

一.windows环境准备 开启过程中的问题&#xff0c;进入bios修复 二.docker下载安装 1.下载 Docker Desktop: The #1 Containerization Tool for Developers | Docker 下载最新版有问题&#xff0c;下载老版本试试 Docker Desktop release notes | Docker Docs 2.安装 三.do…...

第二次面试总结 - 宏汉科技 - Java后端开发

&#x1f9f8;欢迎来到dream_ready的博客&#xff0c;&#x1f4dc;相信您对专栏 “本人真实面经” 很感兴趣o (ˉ▽ˉ&#xff1b;) 专栏 —— 本人真实面经&#xff0c;更多真实面试经验&#xff0c;中大厂面试总结等您挖掘 目录 总结 (非详细) 面试内容(提问内容) - 带答案…...

GPT-4:人工智能的新纪元与未来的无限可能

在人工智能的发展史上&#xff0c;GPT-4的问世标志着一个新的里程碑。作为最新一代的自然语言处理模型&#xff0c;GPT-4不仅在技术上取得了突破&#xff0c;更在应用层面展现了前所未有的潜力。本文将探讨GPT-4的核心技术、应用场景以及它对未来社会的潜在影响。 GPT-4的技术…...

2.右值引用和移动语义

文章目录 右值引用和移动语义&&的特性右值引用优化性能&#xff0c;避免深拷贝移动(move )语义forward 完美转发emplace_back 减少内存拷贝和移动unordered container 无序容器map和unordered_map的差别内部实现机理不同优缺点以及适用处 小结优缺点以及适用处 小结 代…...

深入浅出线程原理

Linux 中的线程本质 线程接口由 Native POSIX Thread Library 提供&#xff0c;即&#xff1a;NPTL 库函数 线程被称为轻量级进程 (Light Weight Process) 每一个线程在内核中都对应一个调度实体&#xff0c;拥有独立的结构体 (task_struct) 内核设计&#xff1a;一个进程对…...

openssl3.2 - 官方demo学习 - saccept.c

文章目录 openssl3.2 - 官方demo学习 - saccept.cEND openssl3.2 - 官方demo学习 - saccept.c 建立TLSServer(使用了证书, 和证书中的私钥), 接收客户端的连接, 并将客户端发来的信息打印到屏幕 笔记 /*! \file saccept.c */ /*! \brief 建立TLSServer(使用了证书, 和证书中…...

JavaScript基础(26)_dom增删改练习

<!DOCTYPE html> <html lang"zh"><head><meta charset"UTF-8"><title>DOM增删改练习</title><link rel"stylesheet" href"../browser_default_style/reset.css"><style>table {borde…...

mac上部署单体hbase

1. 简介 HBase 是一个开源的、分布式的、版本化的典型非关系型数据库。它是 Google BigTable 的开源实现&#xff0c;并且是 Apache 基金会的 Hadoop 项目的一部分1。HBase 在 Hadoop Distributed File System (HDFS) 上运行&#xff0c;作为一个列式存储非关系数据库管理系统…...

【RV1126 学习】SDK/ U-Boot/kernel/rootfs 编译学习

文章目录 RV1126芯片介绍rv1126 模块代码目录相关说明 SDK 包下的脚本使用build.sh 脚本使用envsetup.sh 脚本使用mkfirmware.sh 脚本使用rkflash.sh 脚本使用 U-Boot 编译和配置uboot 的配置修改编译操作 kernel 的修改编译rootfs 编译和配置buildroot 配置busybox 配置 RV112…...

Golang 使用 AST 获取方法和参数名以及应用举例

背景 在做一些自动生成的代码工作时&#xff0c;有时需要知道方法以及对应的参数名 如果仅是方法&#xff0c;利用反射机制就可以解决 而参数名&#xff0c;程序编译后&#xff0c;已经丢失 可以通过 AST 事先获取方法的参数名 有了方法、参数名&#xff0c;加上反射&…...

DC-DC变换集成电路芯片B34063——工作电压范围宽,静态电流小

B34063为一单片DC-DC变换集成电路&#xff0c;内含温度补偿的参考电压源(1.25V)、比较器、能有效限制电流及控制工作周期的振荡器,驱动器及大电流输出开关管等&#xff0c;外配少量元件&#xff0c;就能组成升压、降压及电压反转型DC-DC变换器。 主要特点&#xff1a; ● 工作…...

强力推荐:本地文件加密软件—超详细加密步骤来了!

在数字化时代&#xff0c;数据安全问题日益受到人们的关注。 为了保护个人和企业的重要信息不被泄露&#xff0c;越来越多的人开始使用文件加密软件。 尤其是常常会有数据泄露风险的企业更是需要一款非常给力的加密工具来保护企业数据安全。 一、选择合适的加密软件 在选择加…...

在qml中,ListModel可以与WorkerScript一起使用,从多个线程访问列表模型

在QML中&#xff0c;您可以使用ListModel和WorkerScript一起实现多线程访问列表模型。以下是一个简单的例子&#xff0c;演示了如何在QML中使用这两个元素&#xff1a; import QtQuick 2.15 import QtQuick.Controls 2.15ApplicationWindow {visible: truewidth: 400height: 3…...

rocketmq实现延迟消息

SpringBoot整合RocketMQ发送延时消息 springboot rocketmq 延迟消息 Windows下RocketMQ安装及可视化界面搭建 Java 客户端 RocketMQ延迟消息 项目背景 项目中有延时消息的需求&#xff0c;综合考量RocketMQ比较适合。 RocketMQ支持多维度的延迟级别 支持多种消息类型 基…...

vue倒计时60秒改变按钮状态效果demo(整理)

你可以使用Vue的计时器和绑定状态的方法来实现这个功能。 首先&#xff0c;在data中添加一个计时器countdown&#xff0c;初始值为0。 data() {return {countdown: 0} }<template><div><button click"startCountdown" :disabled"countdown > …...

多区域isis配置实验

一、预习&#xff1a; IS-IS&#xff1a;Intermediate System to Intermediate System&#xff0c;中间系统到中间系统&#xff0c;是ISO为它的CLNP&#xff08;ConnectionLess Network Protocol&#xff09;设计的一种动态路由协议&#xff0c;后来为了提供对IP路由的支持&…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘

美国西海岸的夏天&#xff0c;再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至&#xff0c;这不仅是开发者的盛宴&#xff0c;更是全球数亿苹果用户翘首以盼的科技春晚。今年&#xff0c;苹果依旧为我们带来了全家桶式的系统更新&#xff0c;包括 iOS 26、iPadOS 26…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

k8s从入门到放弃之Ingress七层负载

k8s从入门到放弃之Ingress七层负载 在Kubernetes&#xff08;简称K8s&#xff09;中&#xff0c;Ingress是一个API对象&#xff0c;它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress&#xff0c;你可…...

React第五十七节 Router中RouterProvider使用详解及注意事项

前言 在 React Router v6.4 中&#xff0c;RouterProvider 是一个核心组件&#xff0c;用于提供基于数据路由&#xff08;data routers&#xff09;的新型路由方案。 它替代了传统的 <BrowserRouter>&#xff0c;支持更强大的数据加载和操作功能&#xff08;如 loader 和…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

视频字幕质量评估的大规模细粒度基准

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用&#xff0c;因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型&#xff08;VLMs&#xff09;在字幕生成方面…...

Redis数据倾斜问题解决

Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中&#xff0c;部分节点存储的数据量或访问量远高于其他节点&#xff0c;导致这些节点负载过高&#xff0c;影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

Spring Security 认证流程——补充

一、认证流程概述 Spring Security 的认证流程基于 过滤器链&#xff08;Filter Chain&#xff09;&#xff0c;核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤&#xff1a; 用户提交登录请求拦…...

Xela矩阵三轴触觉传感器的工作原理解析与应用场景

Xela矩阵三轴触觉传感器通过先进技术模拟人类触觉感知&#xff0c;帮助设备实现精确的力测量与位移监测。其核心功能基于磁性三维力测量与空间位移测量&#xff0c;能够捕捉多维触觉信息。该传感器的设计不仅提升了触觉感知的精度&#xff0c;还为机器人、医疗设备和制造业的智…...

链式法则中 复合函数的推导路径 多变量“信息传递路径”

非常好&#xff0c;我们将之前关于偏导数链式法则中不能“约掉”偏导符号的问题&#xff0c;统一使用 二重复合函数&#xff1a; z f ( u ( x , y ) , v ( x , y ) ) \boxed{z f(u(x,y),\ v(x,y))} zf(u(x,y), v(x,y))​ 来全面说明。我们会展示其全微分形式&#xff08;偏导…...