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

第十三章 移动和旋转(上)

移动和旋转是游戏对象最频繁地操作。我们上个章节简单介绍了Cube的移动和旋转。移动是修改transform的position属性,旋转是修改transform的eulerAngles(欧拉角)属性,两者属性值均可以使用Vector3向量来实现。需要大家注意的是,transform.forward和Vector3.forward的区别(参考坐标系是不一样的)。接下来,我们使用transform的Translate方法来进行移动。首先,我在重新创建一个“SampleScene4”场景。我们在该创建中同样创建一个“Cube”游戏对象和“CubeTranslate.cs”脚本文件,并附加两者在一起。

 

以下是脚本代码内容

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class CubeTranslate : MonoBehaviour
{// Update is called once per framevoid Update(){if (Input.GetKeyDown(KeyCode.W)){transform.Translate(new Vector3(0, 0, 1));}// 向左旋转45度if (Input.GetKeyDown(KeyCode.Q)){transform.eulerAngles += new Vector3(0, -45, 0);}// 向右旋转45度if (Input.GetKeyDown(KeyCode.E)){transform.eulerAngles += new Vector3(0, 45, 0);}}
}

我们实现的功能还是之前的一样,按下“W”键向前移动。为了方便观察Cube的移动,我们需要将相机放置Cube的正上方“俯视”Cube。摄像机修改参数如下:

为什么要修改成这些数值,我们上一个章节介绍过了,修改后效果如下:

然后,我们Play工程,查看运行结果。

测试结果就是相对于本地坐标系的移动,也就是游戏对象的正前方移动。

 

 

很明显,默认情况下,Translate(Vector3(0, 0, 1))方法与transform.forward是等效的,也就是相对于本地坐标系而言。那么,如何改成世界坐标系的移动呢,不受游戏物体旋转影响呢?

其实该方法还有第二个参数,也就是Space.Self本地坐标系和Space.World世界坐标系。

显然,如果我们不填写第二个参数的话,默认就是Space.Self本地坐标系,我们改一下

        if (Input.GetKeyDown(KeyCode.W)){//transform.Translate(new Vector3(0, 0, 1));transform.Translate(new Vector3(0, 0, 1), Space.World);}

接下来,我们在重新测试,发现现在的移动就是相对于世界坐标系的啦,截图就不添加了。总结:游戏对象的移动可以通过在transform.translate()方法实现,也可以直接修改transform.position属性。这里需要区分的是世界坐标系还是自身坐标系。如下:

世界坐标系z轴前进:transform.position += vector3.forward
自身坐标系z轴前进:transform.position += transform.forward
世界坐标系z轴前进:transform.translate(vector3.forward, space.world)
自身坐标系z轴前进:transform.translate(vector3.forward, space.self)

如果是space.world的话,还可以使用transform.forward;但是最好不要将transform.forward应用到space.self上。因此还是建议translate方法+ vector3向量搭配使用进行移动。

接下来,我们来说一说旋转,这个是比较复杂的。我们之前的旋转是通过修改transform的eulerAngles(欧拉角)实现的。但是,在我们的印象中,游戏对象的旋转应该是rotation属性,尤其是在Inspector检视面板中,我们也能够看到这个名字的属性。例如下面的截图就是我们对摄像机对象做的旋转设置,也就是在X轴方向上面旋转90度。请注意,此时的参考坐标系是父对象,如果没有父对象就是世界坐标系。

因此,显而易见这是欧拉角数值。但是在Unity API中,这个rotation属性是一个四元数(Quaternion)。关于四元数的概念以及它相对于欧拉角的优势,我们这里不在介绍,它唯一的缺点就是不如欧拉角简单直观。因此,我们往往借助欧拉角转换成四元数再控制游戏对象旋转。接下来,我们修改一下代码,如下所示:

        // 向左旋转45度if (Input.GetKeyDown(KeyCode.Q)){//transform.eulerAngles += new Vector3(0, -45, 0);transform.rotation = Quaternion.Euler(new Vector3(0, -45, 0));}// 向右旋转45度if (Input.GetKeyDown(KeyCode.E)){//transform.eulerAngles += new Vector3(0, 45, 0);transform.rotation = Quaternion.Euler(new Vector3(0, 45, 0));}

上面的代码实现了“Q”和“E”键分别向左右两方向按照45度单位的旋转。但是当我们运行当前工程的时候,发现它并不能连续旋转,而只是旋转一下就停止了。我们很容易想到使用“+=”操作符,但是很遗憾的是,transform.rotation并不支持这样的运算。因此,我们只能换一种方式来解决这个问题,我们可以使用一个类全局变量来存储游戏对象的旋转数据。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class CubeTranslate : MonoBehaviour
{// Y轴旋转角度值private float y = 0.0f;// Update is called once per framevoid Update(){if (Input.GetKeyDown(KeyCode.W)){//transform.Translate(new Vector3(0, 0, 1));transform.Translate(new Vector3(0, 0, 1), Space.World);}// 向左旋转45度if (Input.GetKeyDown(KeyCode.Q)){//transform.eulerAngles += new Vector3(0, -45, 0);//transform.rotation = Quaternion.Euler(new Vector3(0, -45, 0));y -= 45;transform.rotation = Quaternion.Euler(new Vector3(0, y, 0));}// 向右旋转45度if (Input.GetKeyDown(KeyCode.E)){//transform.eulerAngles += new Vector3(0, 45, 0);//transform.rotation = Quaternion.Euler(new Vector3(0, 45, 0));y += 45;transform.rotation = Quaternion.Euler(new Vector3(0, y, 0));}}
}

重新运行后,我们发现Cube可以进行“连续性”的旋转了,如下Gif图所示:

我们发现使用transform.rotation进行旋转的话,还是比较费劲的。但是,有一点大家要明白,这里的旋转和上面的移动是相同的道理,同样存在世界坐标系和局部坐标系的前提条件。这个当然取决于我们使用Vector3类还是使用Transform类。接下来我们就使用transform提供的Rotate方法来进行旋转,它的参数是欧拉角,比较容易让人直观的理解,而且也提供了坐标系参数的指定(Space.Self或者Space.World,当然默认还是Space.Self)。

        // 向左旋转45度if (Input.GetKeyDown(KeyCode.Q)){//transform.eulerAngles += new Vector3(0, -45, 0);//transform.rotation = Quaternion.Euler(new Vector3(0, -45, 0));//y -= 45;//transform.rotation = Quaternion.Euler(new Vector3(0, y, 0));transform.Rotate(new Vector3(0, -45, 0));}// 向右旋转45度if (Input.GetKeyDown(KeyCode.E)){//transform.eulerAngles += new Vector3(0, 45, 0);//transform.rotation = Quaternion.Euler(new Vector3(0, 45, 0));//y += 45;//transform.rotation = Quaternion.Euler(new Vector3(0, y, 0));transform.Rotate(new Vector3(0, 45, 0));}

我们发现transform.Rotate使用起来就比较简单了。当我们Play当前工程之后,我们就发现效果和之前是一样的(可以连续的旋转,而不是只旋转一下)。但是,请大家明白的是,之前的旋转是相对于世界坐标系的Y轴,现在的旋转是相对于游戏对象本地坐标系的Y轴,之所以效果一样是,是因为两者坐标系重合了而已。

从Scene视图中我们可以看到,Cube对象坐标系和世界坐标系是一致的。接下来,我们调整Cube,让两个坐标系不一致,我们让Cube沿着Z轴顺时针旋转90度,也就是修改Cube的Inspector视图中的Rotation中的Z值为“-90”,效果如下所示:

 

为什么“-90”度是顺时针旋转呢?这个取决于我们的观察方向。在默认的左手坐标系下,负值就是顺时针旋转;当然右手坐标系下,正值是顺时针旋转。此时世界坐标系的Y轴仍然是向上的方向,而游戏对象Cube的Y轴是向右的。那么,此时如果我们让Cube在Y轴上按照两个不同坐标系进行旋转的话,那肯定是不一样了。为了能够看到这个效果,我们修改摄像机的位置参数,从侧面观察cube的旋转。

然后(保持相机选中状态)我们点击菜单栏“GameObject”->“Align View to Selected”

此时,我们的Scene视角与Game视角一致。如果是本地坐标系的话,Y轴是向里的。因此围绕它旋转的话,Cube应该是类似“车轮滚动”的方式进行旋转。

// 向左旋转45度
transform.Rotate(new Vector3(0, -45, 0));// 向右旋转45度
transform.Rotate(new Vector3(0, 45, 0));

然后我们Play工程,查看运行结果,Gif图如下

如果是世界坐标系的话,Y轴是向上的。如果它应该是“陀螺”旋转的方式。

//transform.Rotate(new Vector3(0, -45, 0));
transform.Rotate(new Vector3(0, -45, 0), Space.World);//transform.Rotate(new Vector3(0, 45, 0));
transform.Rotate(new Vector3(0, 45, 0),Space.World);

我们直接Play工程,查看Gif效果图吧

 

相关文章:

第十三章 移动和旋转(上)

移动和旋转是游戏对象最频繁地操作。我们上个章节简单介绍了Cube的移动和旋转。移动是修改transform的position属性,旋转是修改transform的eulerAngles(欧拉角)属性,两者属性值均可以使用Vector3向量来实现。需要大家注意的是&…...

视频文件切片

1.为什么网络点播系统使用m3u8更有优势?为何点播要用M3U8来搞?存成一个文件不更好吗? 一个MP4文件可能几百M或几个G,如果读取整个MP4文件的信息并且需要下载一段内容,首次打开播放超慢(加载时间长)。如果把…...

维生素的缺乏与生理功能,是否需要补充维生素【持续学习】

health & nutrition 学习自河南大学丁勇老师:https://space.bilibili.com/510028707 去医院查体内维生素缺啥:营养科或内科开单子 直接门诊查个维生素就可以。9项不到600块 正常吃饭,保湿和防晒 伤口愈合慢——蛋白质,vc 干燥…...

CUDA下载,以及下载GPU版本的pytorch

一、下载anaconda 因为这步我之前就下好了,主要参考这个链接:史上最全最详细的Anaconda安装教程 二、下载CUDA 1.首先观察自己需要什么版本的CUDA,以及是否安装过CUDA 先cmd,输入命令 nvidia-smi结果如下,所以我们…...

学习笔记:c存储类

✨博文作者:烟雨孤舟 💖 喜欢的可以 点赞 收藏 关注哦~~ ✍️ 作者简介: 一个热爱大数据的学习者 文章目录 目录 文章目录 简介 auto 存储类 register 存储类 static 存储类 extern 存储类 总结 简介 存储类定义 C 程序中变量/函数的的存储位置…...

236. 二叉树的最近公共祖先【190】

难度等级:中等 上一篇算法: 103. 二叉树的锯齿形层序遍历【191】 力扣此题地址: 236. 二叉树的最近公共祖先 - 力扣(Leetcode) 1.题目:236. 二叉树的最近公共祖先 给定一个二叉树, 找到该树中两个指定节点…...

即时配送,即时很重要!商家能不能盈利,“快”是源头

“家里水果没有了,选几样叫个跑腿送来吧。” “现在得囤点布洛芬了,我从网上下单。” “同城配送真是太及时、太方便了。” 最近一段时间,如果要问有什么产业突然兴起的话,即时零售无疑是市场最受欢迎的产业。甚至有种说法&…...

ChatGPT原理剖析

文章目录 ChatGPT常见误解1. 罐头回应2. 网络搜寻重组 ChatGPT真正做的事——文字接龙ChatGPT背后的关键技术——预训练(Pre-train)一般机器是怎样学习的? ChatGPT带来的研究问题1. 如何精准提出需求2. 如何更改错误3. 侦测AI生成的物件4. 不…...

「C/C++」C/C++软件跨平台思维

博客主页:何曾参静谧的博客 文章专栏:「C/C」C/C学习 目录 相关术语一、编写可移植的代码:二、使用跨平台的C库和框架:三、进行兼容性测试:四、用户界面设计: 相关术语 跨平台思维:是指在软件开…...

c# 通过界面上填写的信息输出到对应的word中,并另存为一个新的文件

c# 通过界面上填写的信息输出到对应的word中,并另存为一个新的文件 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tas…...

HTML+CSS+JS 学习笔记(四)———jQuery

🌱博客主页:大寄一场. 🌱系列专栏:前端 🌱往期回顾: 😘博客制作不易欢迎各位👍点赞⭐收藏➕关注​​ 目录 jQuery 基础 jQuery 概述 下载与配置jQuery 2. 配置jQuery jQuery 选…...

TryHackMe-Mnemonic(boot2root)

Mnemonic I hope you have fun. 端口扫描 循例nmap FTP枚举 尝试anonymous Web枚举 进80 gobuster扫 对着webmasters再扫一下 对着backups继续扫 下载zip文件,发现有密码 zip2john john直接爆 查看note.txt, 给出了ftpuser hydra直接爆ftp 进到ftp 用wget下载所…...

Nacos注册中心的使用

文章目录 Nacos注册中心1. 服务注册到nacos1)引入依赖2)配置nacos地址3)重启 2.服务分级存储模型2.1.给user-service配置集群2.2.同集群优先的负载均衡 3.权重配置 Nacos注册中心 国内公司一般都推崇阿里巴巴的技术,比如注册中心…...

项目中别用 “! = null“ 做判空了

问题 为了避免空指针调用,我们经常会看到这样的语句: if (someobject ! null) {someobject.doCalc();}最终,项目中会存在大量判空代码,丑陋繁杂。。。如何避免这种情况?是否滥用了判空? 最终,项目中会存在…...

MySQL数据库——MySQL子查询

子查询是 MySQL 中比较常用的查询方法,通过子查询可以实现多表查询。子查询指将一个查询语句嵌套在另一个查询语句中。子查询可以在 SELECT、UPDATE 和 DELETE 语句中使用,而且可以进行多层嵌套。在实际开发时,子查询经常出现在 WHERE 子句中…...

工具链和其他-超级好用的web调试工具whistle

目录 whistle介绍 整体结构 能力 规则 6个使用场景示例 1.修改Host 2.代理 3.替换文件(线上报错时) 4.替换UA 5.远程调试 6.JS注入 互动 whistle介绍 整体结构 安装: npm install whistle -g cli:whistle help 启动…...

ROS第四十三节——定位

https://download.csdn.net/download/qq_45685327/87725276 1.新建launch文件 关于launch文件的实现,在amcl功能包下的example目录已经给出了示例,可以作为参考,具体实现: roscd amcl ls examples gedit amcl_diff.launch 该目录下会列出两…...

2023年第二十届五一数学建模竞赛题目 C题详细思路

详细思路以及发布视频版,大家可以去观看,这里是对应的文字版,内容相差不多。 C题:“双碳”目标下低碳建筑研究 C题的问题设置其实是本次比赛最简单的一道,就是简单的综合评价预测模型。真正提升C题难度的其实是C题的…...

模块化编程原理示意图--CommonJS 模块编程--ES6 模块编程思路分析/图解--三种导出形式--全部代码示例

目录 模块化编程 基本介绍 模块化编程原理示意图 模块化编程分类 CommonJS 模块编程 介绍 应用实例 1. 需求说明 2. 思路分析/图解 3. 代码实现 function.js use.html use.js ES6 模块编程 介绍 需求说明 思路分析/图解 代码实现 common.js use_common.js …...

Ansys Zemax | 如何模拟双折射偏振器件

这篇文章介绍了什么是双折射现象、如何在OpticStudio中模拟双折射 (birefringence)、如何模拟双晶体的双折射偏振器以及如何计算偏振器的消光比。(联系我们获取文章附件) 什么是双折射现象 一般的光学材料都是均匀的各向同性的,也就是说无论光…...

【网络】每天掌握一个Linux命令 - iftop

在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

PHP和Node.js哪个更爽?

先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

FFmpeg 低延迟同屏方案

引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

Linux --进程控制

本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...

Typeerror: cannot read properties of undefined (reading ‘XXX‘)

最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配

目录 一、C 内存的基本概念​ 1.1 内存的物理与逻辑结构​ 1.2 C 程序的内存区域划分​ 二、栈内存分配​ 2.1 栈内存的特点​ 2.2 栈内存分配示例​ 三、堆内存分配​ 3.1 new和delete操作符​ 4.2 内存泄漏与悬空指针问题​ 4.3 new和delete的重载​ 四、智能指针…...

C语言中提供的第三方库之哈希表实现

一. 简介 前面一篇文章简单学习了C语言中第三方库(uthash库)提供对哈希表的操作,文章如下: C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...