一、前言

在大部分的Unity游戏开发中,移动是极其重要的一部分,移动的手感决定着游戏的成败,一个优秀的移动手感无疑可以给游戏带来非常舒服的体验。而Unity中有多种移动方法,使用Transform,使用刚体Rigidbody,使用CharacterController,使用NavMesh导航系统等等等等。当然,对于新手来说,最常见的莫过于使用Transform和Rigidbody这两种组件的移动方案。所以,这篇文章将就这两种移动方案进行分析讲解。

注意!!!以下代码均为2D场景,3D同理

二、Transform

Transform组件是GameObject的变换组件,可以操纵GameObject的位置(Position),大小(Scale),旋转(Rotation)等等。所以,使用Transform组件进行物体移动是一个非常不错的选择,以下是通过Transform组件实现的几种移动方式,以及对应的场景。

1.Translate

使用Transform的Translate函数可以在GameObject的本地坐标系下进行平移。可以传入一个位移向量作为参数,指定平移的方向和距离。

[SerializeField] private float moveSpeed; private void Update() { //自动向右移动 transform.Translate(Vector2.right * moveSpeed * Time.deltaTime); } //物体沿向量指向方向移动 //Vector2.right 向右移动向量,也可以写成自己定义的 //moveSpeed 移动速度,通常为float型

Translate方法在游戏中可以用作物体移动,适用简单的移动方式,例如箱子在平面上自动移动等等。

2.MoveTowards

使用Transform的MoveTowards函数可以实现直线移动到目标位置。可以传入当前位置、目标位置和移动速度来控制移动的速度和到达目标位置。

MoveTowards函数对应的三个参数分别为(当前位置,目标位置,移动速度),前两个为Vector类型,最后一个为float类型,也可以写成整型等。

例如:将物体移动到(5,5)的位置

[SerializeField] private float moveSpeed; private void Update() { transform.position = Vector2.MoveTowards(transform.position,new Vector2(5,5),moveSpeed); }

3.Lerp

使用Transform的Lerp函数可以实现平滑插值移动。可以传入起始位置、目标位置和插值比例来控制移动的过渡效果。

Lerp函数对应的三个参数分别为(当前位置,目标位置,插值比例),前两个为Vector类型,最后一个为float型=类型,插值比例范围是[0,1],当lerp取0时,物体不移动,lerp取1时,物体直接移动到目标位置,lerp取值越大,物体移动越快。

例如:将物体移动到(5,5)

[SerializeField] private float moveSpeed; [SerializeField] private float lerp; private void Update() { transform.position = Vector3.Lerp(transform.position, new Vector2(5,5), lerp); }

接下来,将讲解一下Lerp函数的移动原理:

插值系数lerp本质上是物体每次移动距离与物体当前位置到目标位置的比值,物体每次移动后,都会重新重置下一步移动距离,但是比例不变,也就是说,物体朝目标点移动,每次移动的距离都会变短。听起来非常绕口对吧,下面我们用一幅图来讲解一下这个原理。

红色竖线为第一次移动到的位置,那么它的移动距离L1=S1lerp,蓝色竖线第二次移动到的位置,那么第二次移动的距离L2=S2lerp,同理,L3=S3lerp。由图可知,物体每次移动的距离都在缩短,但是,它们每次移动的距离与当前位置到目标位置的距离的比值不变。并且,我们也可以发现,lerp值越大,单次移动距离越大,即速度越快,相反,lerp越小,单词移动距离也就越小。最后,我们不难发现,在Lerp函数中,物体移动的距离永远是当前位置到目标位置的距离lerp,也就是说,物体永远不可能到达目标位置,只会无限接近目标位置。所以,为了使物体可以到达目标位置,我们可以添加一个if条件,当物体的目标位置的距离小于某一值时,物体位置变为目标位置。

if (Vector2.Distance(transform.position, new Vector2(5, 5))<0.1f) { transform.position = new Vector2(5, 5); }

以上便是使用Transform移动物体的几种方案,当然使用Transform组件移动物体的方案有很多种形式,具体可以自行探索。

当然,使用Transform组件移动物体有时会出现一个小小的bug,我们将在Rigidbody中说明。

三、Rigidbody

Rigidbody,刚体组件,在这个组件中,我们可以使用物理学的定义进行物体移动等操作。并且,这也是最经常用的操控玩家移动的组件,。当然刚体组件不仅仅只用来移动GameObject,还有很多操作,在这里,我们只讲移动方面的使用。

上文说了,Transform有一个小小的bug,那就是会引起穿模,也就是说,物体在进行移动时,碰到障碍物继续移动,会导致穿过障碍物,这是一个致命的bug。但是,刚体组件就可以很好的解决这个bug。在这里,我查阅了一些资料,大致便是,Transform组件是位置的改变,也就是一次一次的发生位置变化,也就是相当于每次移动都是一段瞬移闪现,第一时间在一个位置,下一时间又瞬移到下一个位置,这样的话,在和障碍物进行挤压时,就极其容易导致物体和障碍物发生交叉,导致碰撞体检测出现异常,从而导致穿模,而刚体组件相当于拉着物体移动,就不存在这样的bug。对这方面感兴趣可以查阅相关资料。

下面继续讲解Rigidbody组件控制GameObject移动。

1.AddForce

使用AddForce函数给刚体施加力来移动物体,想要朝哪个方向移动,就在哪个方向添加力。

AddForce函数的参数为AddForce(方向向量 * 力的大小);

[SerializeField] private float force; private Rigidbody2D rigidbody2D; private void Start() { //获取挂载脚本的物体的刚体组件 rigidbody2D = GetComponent<Rigidbody2D>(); } private void Update() { //向上施加一个大小为force的力 rigidbody2D.AddForce(Vector2.up * force); }

2.MovePosition

MovePosition函数可以直接设置物体的位置。

MovePosition函数的参数为MovePosition(位置(例如tramsform.position))

下面的代码是物体每次向右闪现/瞬移speed的长度,注意,这个方法也有可能导致穿模

[SerializeField] private float speed; private Rigidbody2D rigidbody2D; private void Start() { //获取挂载脚本的物体的刚体组件 rigidbody2D = GetComponent<Rigidbody2D>(); } private void Update() { //向右移动,2D中为向右/前,X轴正方向 rigidbody2D.MovePosition(transform.position + Vector3.right * speed * Time.deltaTime); }

当然,也可以直接只填入目标位置,使得物体闪现到指定目标位置

[SerializeField] private Transform targetTransform; private Rigidbody2D rigidbody2D; private void Start() { //获取挂载脚本的物体的刚体组件 rigidbody2D = GetComponent<Rigidbody2D>(); } private void Update() { //传送到targetTransform的位置 rigidbody2D.MovePosition(targetTransform.position); }

3.velocity

首先说明的是velocity不是函数,而是一个参数,也就是物体的速度。

所以我们通过对物体将要移动的方向上添加速度,也就可使物体超指定方向以固定的速度进行移动。

[SerializeField] private float moveSpeed_X; [SerializeField] private float moveSpeed_Y; private Rigidbody2D rigidbody2D; private void Start() { //获取挂载脚本的物体的刚体组件 rigidbody2D = GetComponent<Rigidbody2D>(); } private void Update() { //水平方向 float horizontal = Input.GetAxis("Horizontal"); //竖直方向 float vertical = Input.GetAxis("Vertical"); rigidbody2D.velocity=new Vector2 (horizontal*moveSpeed_X*Time.deltaTime, vertical* moveSpeed_Y * Time.deltaTime); //也可以只改变x或y的值 rigidbody2D.velocity = new Vector2(horizontal * moveSpeed_X * Time.deltaTime, rigidbody2D.velocity.y); rigidbody2D.velocity = new Vector2(rigidbody2D.velocity.x, vertical * moveSpeed_Y * Time.deltaTime); }

四、结尾

以上便是几种简单的物体移动方式,当然使物体移动的方法有很多种,这里只列举了几种,感兴趣的小伙伴可以深究一下。

让物体动起来,Unity的几种移动方式的更多相关文章

  1. 【Unity3D基础】让物体动起来①--UGUI鼠标点击移动

    背景 首先还是先声明自己是比较笨的一个人,总是找不到高效的学习方法,目前自己学习Unity3D的方式主要是两种,一种是直接看高质量的源码,另一种是光看不行还要自己动手,自己写一些有代表性的小程序,这也 ...

  2. webgl学习总结画线面及场景和物体动

    WebGL是在浏览器中实现三维效果的一套规范.是浏览器中的3D引擎,是利用js代码来实现加载3D模型,渲染.输出等功能,从而实现在浏览器和微信中浏览三维文件的效果. three.js是基于WebGL的 ...

  3. 关于Unity的两种调试方法

    Unity的两种调试方法 1.Debug.Log()输出语句调试,平时经常用这个 2.把MonoDevelop和Unity进行连接后断点调试 先把编辑器选择为MonoDevelop,Edit----& ...

  4. 基于 Unity 的一种透明通道压缩处理

    由于 Android 平台各种硬件标准的不统一,为了开发的软件项目能够在大部分 Android 机上完美运行,我们需要以较差的硬件支持为基础做准备. Android 平台基本上都支持对不带 Alpha ...

  5. Game Loop的几种实现方式

    http://www.bennychen.cn/2011/06/game-loop-model/ —————————————————————————————— 写这篇博客的目的是为了对game loo ...

  6. Web APi之认证(Authentication)两种实现方式后续【三】(十五)

    前言 之前一直在找工作中,过程也是令人着实的心塞,最后还是稳定了下来,博客也停止更新快一个月了,学如逆水行舟,不进则退,之前学的东西没怎么用,也忘记了一点,不过至少由于是切身研究,本质以及原理上的脉络 ...

  7. LVS三种工作方式八种算法

    一.集群简介 什么是集群 计算机集群简称集群是一种计算机系统,它通过一组松散集成的计算机软件和/或硬件连接起来高度紧密地协作完成计算工作.在某种意义上,他们可以被看作是一台计算机.集群系统中的单个计算 ...

  8. Linux 双线策略路由的三种实现方式总结+端口映射

    Linux 双线策略路由的三种实现方式总结+端口映射 Linux 双线策略路由的三种实现方式总结+端口映射 网络环境 服务器(网关): eth0 为LAN口,IP为 LAN_IP = 192.168. ...

  9. LVS原理详解及部署之二:LVS原理详解(3种工作方式8种调度算法)

    一.集群简介 什么是集群 计算机集群简称集群是一种计算机系统,它通过一组松散集成的计算机软件和/或硬件连接起来高度紧密地协作完成计算工作.在某种意义上,他们可以被看作是一 台计算机.集群系统中的单个计 ...

  10. LVS原理详解(3种工作方式8种调度算法)--老男孩

    一.LVS原理详解(4种工作方式8种调度算法) 集群简介 集群就是一组独立的计算机,协同工作,对外提供服务.对客户端来说像是一台服务器提供服务. LVS在企业架构中的位置: 以上的架构只是众多企业里面 ...

随机推荐

  1. ES插入数据(JAVA代码)

    创建ES连接 // 初始化api客户端 public static RestHighLevelClient client = new RestHighLevelClient( RestClient.b ...

  2. C#选择排序(Selection Sort)算法

    选择排序原理介绍 选择排序(Selection Sort)是一种简单的排序算法,其实现原理如下: 遍历待排序数组,从第一个元素开始. 假设当前遍历的元素为最小值,将其索引保存为最小值索引(minInd ...

  3. ChatGPT变笨了,好在还有自知之明

    大家好,我是老章 好久没有写文章了,顺便向大家汇报一下最近在忙的事情(多数无疾而终): 1 开发了一个IMG2Latex工具(截图一个公式,自动把latex代码塞进剪贴板) 2 开发了一个播客转文字稿 ...

  4. Python将大的csv文件拆分多个小的csv文件

    #ecoding=utf-8 import os import time # 2019/9/8 将大的csv文件拆分多个小的csv文件 def mkSubFile(lines, head, srcNa ...

  5. 探索Java通信面试的奥秘:揭秘IO模型、选择器和网络协议,了解面试中的必备知识点!

    了解常见的TCP/UDP TCP(Transmission Control Protocol)是一种面向连接的可靠的传输协议.类似于打电话,它通过建立一个连接和保证数据的可靠传输来提高通信的可靠性.然 ...

  6. Linux下定时清空某个文件

    问题 在一台单点机器部署完成且运行一段时间后,发现页面接口报错,登上机器发现磁盘满了.通过du -lh --max-depth=1 和 du -sh * 找出是哪个文件. 发现是 项目中 stdout ...

  7. .net开发-心情与效率

    随着现代科技的不断发展,笔记本电脑已经成为我们日常生活中不可或缺的一部分.然而,在使用笔记本电脑的过程中,我们可能会遇到一些问题,例如显示器闪烁.HDMI接口接触不良等,这些问题不仅会影响我们的工作效 ...

  8. AVR汇编(六):分支指令

    AVR汇编(六):分支指令 分支指令用于改变程序的执行流,分为无条件分支和条件分支两类. 无条件分支指令 JMP JMP 指令用于无条件跳转,类似于C中的 goto 关键字, JMP 指令的跳转范围为 ...

  9. 2.go语言基础类型漫游

    本篇前瞻 本篇是go语言的基础篇,主要是帮助大家梳理一下go语言的基本类型,注意本篇有参考go圣经,如果你有完整学习的需求可以看一下,另外,go语言的基本类型比较简单,介绍过程就比较粗暴. 基本类型 ...

  10. 分享1-3年经验的Java面试

    最近的温度真是一路的飙升啊,出个门实属不易,但是还是有所收获滴,趁着今天不忙,赶紧给大家分享一波Java面经,对于想去BAT大公司的面试者来说,我这里可能不太合适,深度或许不够,但是对于刚毕业或者有1 ...