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

移动和旋转是游戏对象最频繁地操作。我们上个章节简单介绍了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 frame
    void 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 frame
    void 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效果图吧

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/16458.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

B/S 结构系统的 缓存机制(Cookie) 以及基于 cookie 机制实现 oa 十天免登录的功能

B/S 结构系统的 缓存机制(Cookie) 以及基于 cookie 机制实现 oa 十天免登录的功能 文章目录 B/S 结构系统的 缓存机制(Cookie) 以及基于 cookie 机制实现 oa 十天免登录的功能每博一文案1. Cookie 的概述2. session 与 Cookie 之间的联系:3. Cookie 的作用&#xff…

盈泰德带你了解产品表面缺陷检测系统

与前几年相比,机器视觉行业在表面检测方面有了很大的突破。检测产品表面的划痕、污渍不再困难,广泛应用于金属、玻璃、手机屏幕、液晶面板等行业的表面检测。 机器视觉检测有以下四种常用的检查和照明方法: 同轴照明、低角度照明、背光照明…

Python一行命令搭建HTTP服务器并外网访问 - 内网穿透

文章目录 1.前言2.本地http服务器搭建2.1.Python的安装和设置2.2.Python服务器设置和测试 3.cpolar的安装和注册3.1 Cpolar云端设置3.2 Cpolar本地设置 4.公网访问测试5.结语 转载自远程内网穿透的文章:【Python】快速简单搭建HTTP服务器并公网访问「cpolar内网穿透…

Java 基础进阶篇(五)—— 抽象类与模板方法设计模式

文章目录 一、抽象类、抽象方法概述二、抽象类的特征三、模板方法设计模式3.1使用场景3.2 实现步骤3.3 写作文案例 补充:final 和 abstract 是什么关系? 一、抽象类、抽象方法概述 在 Java 中 abstract 是抽象的意思,可以修饰类、成员方法。 abstract …

win10远程桌面控制Ubuntu服务器 - 内网穿透实现公网远程

文章目录 前言视频教程1. ubuntu安装XRDP2.局域网测试连接3. Ubuntu安装cpolar内网穿透4.cpolar公网地址测试访问5.固定域名公网地址 转载自远程穿透文章:Windows通过RDP异地远程桌面Ubuntu【内网穿透】 前言 XRDP是一种开源工具,它允许用户通过Windows…

机械硬盘(HDD)与固态硬盘(SSD)

目录 机械硬盘(HDD) 最小组成单元是扇区 硬盘结构 硬盘工作原理 硬盘上的数据组织 硬盘指标 影响性能的因素 固态硬盘(SSD) 最小存储单元是Cell SSD的特点 SSD架构 NAND Flash 闪存介质 地址映射管理 FTL闪存转换层 机械硬盘&…

JAVA IO 模型详解

什么是IO I/O(Input/Outpu) 即输入/输出 。 从计算机结构的视角来看的话, I/O 描述了计算机系统与外部设备之间通信的过程。 从应用程序的视角来看的话,我们的应用程序对操作系统的内核发起 IO 调用(系统调…

微信小程序定义模板

微信小程序提供模板(template)功能,把一些可以共用的,复用的代码在模板中定义为代码片段,然后在不同的地方调用,可以实现一次编写,多次引用的效果。 首先我们看一下官网是如何操作的 一般的情…

JavaWeb学习--RequestResponse

目录 JavaWeb学习--Request&Response 1,Request和Response的概述 request:获取请求数据 response:设置响应数据 **小结** 2,Request对象 **小结** 2.2 Request获取请求数据 **小结** 2.4 请求参数中文乱码问题 URL编码 2.5 Request请求转…

【前端技术】Vue3 01:初识 Vue.js

Vue 可以说是非常流行了,至少在国内是这样,他是个轻量级的 JavaScript 框架,非常适合构建大型和中小型的 Web 应用程序,如果想和前端打交道,应该绕不过这个框架吧。 目录 1 Vue.js 介绍 2 IDE 选择 2.1 vscode 2.…

Eplan 部件库导入部件的方法

1. 部件宏文件如何下载 1.1 西门子部件宏文件下载 EPLAN 的部件库是可以更新的,一般元器件厂商会提供其部件文件,以 SIEMENS 为例 进入网站,点击EPLAN 的图标 https://www.automation.siemens.com/bilddb/index.aspx?lang=en 在订货号中输入所需部件订货号,点击搜索。点…

【Java笔试强训 27】

🎉🎉🎉点进来你就是我的人了博主主页:🙈🙈🙈戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔🤺🤺🤺 目录 一、选择题 二、编程题 🔥 不用加…

sed编辑器基础命令

shell脚本编程系列 学习sed编辑器 sed编辑器被称作流编辑器(stream editor),与普通的交互式文本编辑器不同,在交互式文本编辑器可以用键盘命令交互式插入、删除或替换文本数据。流编辑器则是根据事先设计好的一组规则编辑数据流。 sed编辑器…

Mybatis 框架 ( 三 ) Mybatis-Plus

4.Mybatis-plus 官网 : https://www.baomidou.com/ MyBatis-Plus 是一个 MyBatis 的增强工具&#xff0c;在 MyBatis 的基础上封装了大量常规操作&#xff0c;减少了SQL的编写量。 4.1.Maven依赖 使用时通常通过Springboot框架整合使用 并且使用Lombok框架简化实体类 <…

django显示echart图表:柱状图、折线图、饼图、地图、词云

django显示echart图表 效果: 示例demo 点我查看 1、urls.py 其中关键代码: urlpatterns = [path("book_chart/", views.book_chart, name="book_cha

【23】linux进阶——linux的软链接和硬链接

大家好&#xff0c;这里是天亮之前ict&#xff0c;本人网络工程大三在读小学生&#xff0c;拥有锐捷的ie和红帽的ce认证。每天更新一个linux进阶的小知识&#xff0c;希望能提高自己的技术的同时&#xff0c;也可以帮助到大家 另外其它专栏请关注&#xff1a; 锐捷数通实验&…

RebbitMQ Windows安装

RabbitMQ是由Erlang语言写的,因此安装前要先安装Erlang Erlang及RabbitMQ安装版本的选择 下载时一定要注意版本兼容性 版本兼容说明地址&#xff1a;RabbitMQ Erlang Version Requirements — RabbitMQ 我们选择的版本 Erlang官网下载:https://www.erlang.org/downloads Ra…

JavaScript 笔记

1 简介 JavaScript 诞生于1995年&#xff0c;是由网景公司发明&#xff0c;起初命名为LiveScript&#xff0c;后来由于SUN公司的介入&#xff0c;更名为 JavaScript。1996年微软在其最新的IE3浏览器中引入了自己对JavaScript的实现JScript&#xff0c;于是市面上就存在两个版本…

Guitar Pro8苹果mac最新版本下载安装教程

Guitar Pro是一款专业的吉他制谱软件&#xff0c;现在已更新至Guitar Pro8&#xff0c;新增了支持添加音频轨道、支持嵌套连音符、直观的效果器视图、让指法一目了然的音阶示意图等实用新功能。下面我们来看Guitar Pro8 Mac如何安装。 guitar pro是一款专业的吉他学习软件&…

【VM服务管家】专题_7.5 异常收集

目录 5.1 信息收集&#xff1a;异常报错信息收集的方法5.2 日志等级&#xff1a;日志等级调低的方法 5.1 信息收集&#xff1a;异常报错信息收集的方法 描述 环境&#xff1a;VM4.0以上VS2013及以上 现象&#xff1a;未知问题、偶发问题、崩溃问题如何收集信息提供给研发排查。…