第十五章 角色移动旋转实例
本章节我们创建一个“RoleDemoProject”工程,然后导入我们之前创建地形章节中的“TerrainDemo.unitypackage”资源包,这个场景很大,大家需要调整场景视角才能看清。
接下来,我们添加一个人物模型,操作方式就是将模型文件目录复制到“Assets”下
然后Unity会自动同步该文件,我们查看Project面板
在“Alita”目录下有两个文件:“Alita.fbx”和“alita_d.png”。前者是模型文件,后者是贴图文件。我们接下来要做的就是,将“Alita.fbx”模型文件拖拽到场景中。由于我们的场景太大了,可能无法方便的看到模型。我们这样操作,我们可以在Hierarchy层次面板中找到这个游戏对象(“Alita”),然后我们将鼠标“移动到(不要点击)”到场景视图中,然后按下“F”键就可以在场景视图中显示这个游戏对象了。
当然,我们最好再调整一下这个模型,然其站立到地面上。在移动模型的时候,注意保持模型轴心和本地坐标系的选择。如下所示
当我们切换轴心之后,我们发现模型身上的坐标系指示箭头移动到了模型脚底。一般情况下,人物模型的轴心就是在脚底(本地坐标系的原点)。如果我们是“Center”状态的话,坐标系指示箭头会在模型的中心位置。
我们能够看到模型的下半部分位于地形的下面,我们向上移动一下。
接下来,我们要做的是,让相机跟随模型一起移动和旋转。如果使用代码来完成的话,其原理就是模型如何移动和旋转,就同步调整相机如何移动和旋转。这里介绍一种更加简单的方式,就是将相机设置为模型的子游戏对象。操作非常简单,就是在Hierarchy层次面板中,拖动“Main Camera”到“Alita”上面即可。
拖拽后的样子
这样做的目的,就是“Alita”移动旋转的时候,子对象“Main Camera”自动移动旋转。当然,我们还需要进一步调整相机的位置,让其放置到“Alita”的后上方。首先,我们将相机的Position和Rotation数值清零,如下所示
请注意,此时的相机位于模型的脚下。在Unity中,子游戏对象的移动和旋转都是相对于父对象而言的。我们将相机的Position数值清零,并不是将相机放置到世界坐标系的原点,而是放置到了父对象“Alita”的原点。接下来,我们调整相机的位置,
我们将相机放置到人物模型的后上方,类似于第三人称视角。
接下来,我们保持相机选中状态,我们点击菜单栏“GameObject”->“Align View to Selected”
在之前的移动和旋转案例中,我们忽略了一个重要的特性:时间(Time.deltaTime)。游戏对象的移动有三个因素决定,一个方向,一个是速度,另一就是时间。其中方向和速度可以由向量表示(向量的长度代表速度,方向还是方向),而时间就是Time.deltaTime。为什么时间是Time.deltaTime呢?因为游戏对象是在每一次update方法调用的时候才会进行移动,而两次移动之间的时间就是两个update方法调用的时间差,也就是我们的Time.deltaTime值。因此Translate方法里面第一个参数应该是方向*速度*时间。
接下来,我们来控制角色的前后左右移动。我们创建一个“RoleController.cs”脚本文件,并且附加到“Alita”上面。我们目前使用WASD键来控制角色前后左右移动,代码如下
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class RoleController : MonoBehaviour
{// 移动速度private float moveSpeed = 10.0f;// Update is called once per framevoid Update(){// 向前移动if (Input.GetKeyDown(KeyCode.W)){transform.Translate(Vector3.forward * moveSpeed * Time.deltaTime, Space.Self);}// 向后移动if (Input.GetKeyDown(KeyCode.S)){transform.Translate(Vector3.back * moveSpeed * Time.deltaTime, Space.Self);}// 向左移动if (Input.GetKeyDown(KeyCode.A)){transform.Translate(Vector3.left * moveSpeed * Time.deltaTime, Space.Self);}// 向右移动if (Input.GetKeyDown(KeyCode.D)){transform.Translate(Vector3.right * moveSpeed * Time.deltaTime, Space.Self);}}
}
这里我们使用的是本地坐标系进行移动,大部分游戏开发中,也都是这么做的。
接下来,我们Play当前工程,查看运行后的Gif图
由于我们使用的是GetKeyDown方法,因此每按下一次键盘,才会移动一段距离。如果我们需要长按键盘进行移动的话,可以换成GetKey方法。当我们移动过程中,发现一个小问题,就是我们没有考虑地形的高度。也就是说,模型在移动过程中,可能会移动到地形之下或者地形之上。我们后续在解决这个问题。接下来,我们添加旋转的代码,如下所示。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class RoleController : MonoBehaviour
{// 旋转速度private float rotationSpeed = 20.0f;// Update is called once per framevoid Update(){// 向左旋转if (Input.GetKeyDown(KeyCode.Q)){transform.Rotate(Vector3.down * rotationSpeed * Time.deltaTime, Space.Self);}// 向右旋转if (Input.GetKeyDown(KeyCode.E)){transform.Rotate(Vector3.up * rotationSpeed * Time.deltaTime, Space.Self);}}
}
上面我们忽略了移动的代码。为什么左右旋转使用的是Vector3.up和Vector3.down呢,不应该是Vector3.left和Vector3.right吗?很简单,我们所谓的左右旋转类似于“左右扭头”,它实际上就是围绕Y轴进行旋转的,所以是Vector3.up和Vector3.down上下方向的Y轴。接下来,我们Play当前工程,查看运行Gif效果图
接下来,我们来解决地形高度问题。我们需要借助一个“角色控制器”的组件。我们选中“Alita”,然后在Inspector检视面板中点击“Add Component”按钮。
在弹出的搜索框中输入“ch”,然后在下拉框中选中“Character Controller”角色控制器组件。
此时,在场景中的“Alita”会覆盖一个胶囊体的线框。
这个胶囊体的线框是用来做“碰撞检测”的,因此它最好能够“包裹”住我们的人物模型。当然,默认情况下,它基本上就能够自动“包裹”我们的人物模型。但是,有一个非常重要的注意点,就是胶囊体的线框不能“陷入”到地形的下面。因此,我们需要编辑胶囊体的线框,它的参数调节我们直接给出,大家可以自己修改其中某些值查看效果
接下来,我们还需要修改角色移动代码,如下
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class RoleController : MonoBehaviour
{// 移动速度private float moveSpeed = 10.0f;// 旋转速度private float rotationSpeed = 100.0f;// 角色控制器组件private CharacterController cc;// Start is called before the first frame updatevoid Start(){// 获取角色控制器组件cc = GetComponent<CharacterController>();}// Update is called once per framevoid Update(){// 前后左右方向float v = Input.GetAxis("Vertical");float h = Input.GetAxis("Horizontal");Vector3 direction = new Vector3(h, 0, v);// 前后左右移动cc.SimpleMove(transform.TransformDirection(direction) * moveSpeed);// 向前移动if (Input.GetKeyDown(KeyCode.W)){//transform.Translate(Vector3.forward * moveSpeed * Time.deltaTime, Space.Self);}// 向后移动if (Input.GetKeyDown(KeyCode.S)){//transform.Translate(Vector3.back * moveSpeed * Time.deltaTime, Space.Self);}// 向左移动if (Input.GetKeyDown(KeyCode.A)){//transform.Translate(Vector3.left * moveSpeed * Time.deltaTime, Space.Self);}// 向右移动if (Input.GetKeyDown(KeyCode.D)){//transform.Translate(Vector3.right * moveSpeed * Time.deltaTime, Space.Self);}// 向左旋转,替换GetKey方法if (Input.GetKey(KeyCode.Q)){transform.Rotate(Vector3.down * rotationSpeed * Time.deltaTime, Space.Self);}// 向右旋转,替换GetKey方法if (Input.GetKey(KeyCode.E)){transform.Rotate(Vector3.up * rotationSpeed * Time.deltaTime, Space.Self);}}
}
上面获取键盘输入的代码是:Input.GetAxis("Vertical/Horizontal") ,这个代码兼容WASD键的输入获取。然后使用CharacterController组件的SimpleMove方法进行移动。我们就不过多解释上面的代码了,直接Play运行查看Gif效果图吧。
相关文章:

第十五章 角色移动旋转实例
本章节我们创建一个“RoleDemoProject”工程,然后导入我们之前创建地形章节中的“TerrainDemo.unitypackage”资源包,这个场景很大,大家需要调整场景视角才能看清。 接下来,我们添加一个人物模型,操作方式就是将模型文…...

数据湖Data Lakehouse支持行级更改的策略:COW、MOR、Delete+Insert
COW:写时复制,MOR:读时合并,Delete+Insert:保证同一个主键下仅存在一条记录,将更新操作转换为Delete操作和Insert操作 COW和MOR的对比如下图,而Delete+Insert在StarRocks主键模型中用到。 目前COW、MOR在三大开源数据湖项目的使用情况,如下图。 写入时复制【Copy-On…...

双亲委派机制的原理和作用
双亲委派机制,就必须弄清楚Java的类加载器。 什么是类加载器 Java类加载器(ClassLoader)是Java运行时环境(JRE)的一部分,负责动态的将Java类加载到Java虚拟机的内存空间。 类加载器有哪些 主要有三个: 引导类加载器(Bootstrap ClassLoade…...

mac免费杀毒软件哪个好用?如何清理mac系统需要垃圾
CleanMyMac x是一款功能强大的Mac系统优化清理工具,使用旨在帮助用户更加方便的清理您系统中的所有垃圾,从而加快电脑运行速度,保持最佳性能,更加稳定、流畅、快速!!! CleanMyMac X无疑是目前m…...

css 实现太极效果
目录 一、简述二、太极效果制作 一、简述 本次主要介绍::after,::before,box-shadow这三个属性。 ::after,::before这两个是伪类选择器,box-shaow是用来设置元素的阴影效果 before:向选定的元素前插入内容 after:向选定的元素后插…...

【前端基础知识】Vue中的变量不是响应式的吗?属性赋值后视图不变化的原因是什么?
目录 🤔问题📝回答🎨使用场景动态添加属性动态添加数组元素 ❌注意事项$set只能在响应式对象上使用$set不能用于根级别的属性$set的性能问题 📄总结 🤔问题 Vue是一款在国内非常流行的框架,采用MVVM架构&a…...

如何完全卸载linux下通过rpm安装的mysql
卸载linux下通过rpm安装的mysql 1.关闭MySQL服务2.使用 rpm 命令的方式查看已安装的mysql3. 使用rpm -ev 命令移除安装4. 查询是否还存在遗漏文件5. 删除MySQL数据库内容 1.关闭MySQL服务 如果之前安装过并已经启动,则需要卸载前请先关闭MySQL服务 systemctl stop…...

[渗透教程]-004-长城防火墙GFW的原理
文章目录 1. baidu.com 请求过程2. GFW原理2.1 GFW拦截方法1:DNS渲染2.2 通过IP黑名单2.3 VPN阻断1. baidu.com 请求过程 家庭的路由器具备了交换机的功能.域名–>ip,优先检测本地的缓存,没有的话就查找DNS服务器,传输层对应该层的数据进行封装增加了端口的信息,网络层对传输…...

LaTeX基础文本排版命令
LaTeX基础文本排版命令 1. 字体大小2. 字体的粗体与斜体2.1. 粗体2.2 斜体2.3 同时启用粗体和斜体 3. 空格长度4. 高度与宽度尺寸 在LaTeX中,文本排版可以通过简单的命令实现,这些命令可以控制字体大小、粗体与斜体、空格、行高和宽度等方面,…...
PLC模糊控制模糊PID(梯形图实现+算法分析)
博途PLC的模糊PID控制详细内容请查看下面的博客文章: Matlab仿真+博途PLC模糊PID控制完整SCL源代码参考(带模糊和普通PID切换功能)_博途怎么实现模糊pid_RXXW_Dor的博客-CSDN博客模糊PID的其它相关数学基础,理论知识大家可以参看专栏的其它文章,这里不再赘述,本文就双容…...
线程池在Java多线程中的应用
前言 随着计算机硬件和软件技术的不断发展,多线程编程在软件开发中变得越来越常见。然而,使用多线程编程时必须小心谨慎,以确保正确性和可维护性。在这个过程中,线程池成为了一个至关重要的工具。本文将介绍其应用场景、注意事项…...

1997-2021年全国30省技术市场成交额(亿元)
1997-2021年全国30省技术市场成交额 1、时间:1997-2021年 2、范围:30省不含西藏 3、来源:国家统计J 4、指标:技术市场成交额 5、缺失情况说明:无缺失 6、指标解释及用途: 技术市场成交额是一个客观、…...

【C++】面向对象之多态
文章内的所有调试都是在vs2022下进行的, 部分小细节可能因编译器不同存在差异。 文章目录 多态的定义和实现概念引入多态的构成条件虚函数重写通过基类的指针或者引用调用虚函数 override和final 抽象类概念实现继承和接口继承 虚函数表单继承中的虚表打印虚表多继…...

卡尔曼滤波器简介——多维卡尔曼滤波
原文:多维卡尔曼滤波 (kalmanfilter.net) 目录 前言 基本背景 状态外推方程 示例 - 飞机 - 无控制输入 示例 - 带控制输入的飞机 示例 – 坠落物体 状态外推方程维度 线性时不变系统 线性动态系统建模 状态外推方程的推导 状态空间表示形式 示例 - 等速…...

如何用 GPT-4 帮你写游戏?
你知道的,GPT-4 发布了。 目前你想要用上 GPT-4,主要的渠道是 ChatGPT Plus 。作为交了订阅费的用户,你可以在对话的时候选择模型来使用。 另一种渠道,就是申请官方 API 的排队。我在申请 New Bing Chat 的时候,耐心被…...

R语言的贝叶斯时空数据模型实践技术应用
时间-空间数据(以下简称“时空数据”)是最重要的观测数据形式之一,很多科学研究的数据都以时空数据的形式得以呈现,而科学研究目的可以归结为挖掘时空数据中的规律。另一方面,贝叶斯统计学作为与传统统计学…...

Lazysysadmin靶机渗透过程
准备工作 下载好靶机到本地后 VMware导入OVA 启动靶机 扫描信息 首先扫描整个C段发现主机 进一步扫描端口 从扫描结果可知: Samba服务MySQLSSH端口网站端口 先对网站进行目录遍历 发现有wordpress网站和phpmyadmin管理系统 出现了非常多遍My name is togie.可能…...

为什么网络安全缺口很大,招聘却很少?
2020年我国网络空间安全人才数量缺口超过了140万,就业人数却只有10多万,缺口高达了93%。这里就有人会问了: 1、网络安全行业为什么这么缺人? 2、明明人才那么稀缺,为什么招聘时招安全的人员却没有那么多呢࿱…...

SpringBoot手册
目录 依赖管理关于各种的 start 依赖关于自动配置关于约定大于配置中的配置SpringBoot 整合 SpringMVC定制化 SpringMVC静态资源处理对上传文件的处理对异常的处理Web原生组件注入(Servlet、Filter、Listener)Interceptor 自定义拦截器DispatcherServlet…...

【Linux】如何实现单机版QQ,来看进程间通信之管道
学会了管道,就可以实现简单的qq哦~ 文章目录 前言一、匿名管道总结 前言 为什么要进行进程间通信呢?因为需要以下这些事: 数据传输:一个进程需要将它的数据发送给另一个进程 资源共享:多个进程之间共享同样的资源。 …...

Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...

20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...

无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...