首页 > 其他分享 >让物体动起来,Unity的几种移动方式

让物体动起来,Unity的几种移动方式

时间:2023-10-27 19:12:07浏览次数:38  
标签:物体 位置 Transform private 几种 Unity rigidbody2D 移动

一、前言

在大部分的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); }

四、结尾

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

标签:物体,位置,Transform,private,几种,Unity,rigidbody2D,移动
From: https://www.cnblogs.com/CloudAndMist/p/17793002.html

相关文章

  • API - 几种API接口模式 - RESTful、WebSocket、GraphQL、gRPC、Webhook
    总结TODO.....当思考使用哪种API接口时,你将会面临一个重要的决策。RESTful、GraphQL、gRPC、WebSocket和Webhook是当前流行的几种API接口模式。在本文中,我们将介绍这些接口的特点、用途和比较,帮助你选择最适合你应用程序需求的接口。引言随着现代应用程序的复杂性和用户期望的......
  • 如何设置位移贴图模拟物体裂缝?
    1、位移贴图的原理?位移贴图(DisplacementMap)是一种用于增强模型细节的贴图技术,它可以通过改变模型表面的几何形状来实现更加真实的效果。与其他贴图技术不同,位移贴图不仅仅是给模型表面添加纹理和颜色,而是直接改变模型的顶点位置,从而改变模型的形状。位移贴图的原理可以简单地描......
  • 数据库软件有哪几种?
    数据库软件是一种用于管理和存储数据的软件工具,它提供了一套结构化的方式来组织和访问数据。以下是对几种常见的数据库软件的详细介绍。1.关系型数据库软件关系型数据库软件是最常见和广泛使用的数据库类型之一。它使用表格(也称为关系)来存储和管理数据,其中各个表格之间可以通......
  • Unity 3D定点数物理引擎实战系列4
    1.4基于Unity整合BEPUphysicsint物理引擎实战 上一节我们详细的讲解BEPUphysicsint的物理事件。此物理引擎会产生了碰撞事件与非碰撞事件,碰撞事件大家好理解,非碰撞事件例如: 物理Entity的update事件,Entity的activation/deactivation事件等。本节课来实战如何编译BEPUphysics......
  • Unity DOTS系列之Aspect核心机制分析
      最近DOTS发布了正式的版本,我们来分享一下DOTS里面Aspect机制,方便大家上手学习掌握UnityDOTS开发。Aspect 机制概述当我们使用ECS开发的时候,编写某个功能可能需要某个entity的一些组件,如果我们一个个组件的查询出来,可能参数会写很长。如果我们编写某个功能的时候,需要enti......
  • 循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(6) -- 窗口控
    在我们窗口新增、编辑状态下的时候,我们往往会根据是否修改过的痕迹-也就是脏数据状态进行跟踪,如果用户发生了数据修改,我们在用户退出窗口的时候,提供用户是否丢弃修改还是继续编辑,这样在一些重要录入时的时候,可以避免用户不小心关掉窗口,导致窗口的数据要重新录入的尴尬场景。本篇随......
  • 循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(4) -- 实现Da
    在我们设计软件的很多地方,都看到需要对表格数据进行导入和导出的操作,主要是方便客户进行快速的数据处理和分享的功能,本篇随笔介绍基于WPF实现DataGrid数据的导入和导出操作。1、系统界面设计在我们实现数据的导入导出功能之前,我们在主界面需要提供给客户相关的操作按钮,如下界面所示......
  • 循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(5) -- 树列表
    在我们展示一些参考信息的时候,有所会用树形列表来展示结构信息,如对于有父子关系的多层级部门机构,以及一些常用如字典大类节点,也都可以利用树形列表的方式进行展示,本篇随笔介绍基于WPF的方式,使用TreeView来洗实现结构信息的展示,以及对它的菜单进行的设置、过滤查询等功能的实现逻辑......
  • 直播软件源码,java数据分页几种方式
    直播软件源码,java数据分页几种方式1.使用PageUtils Service: /**   *分页查询   *   *@paramparams查询条件   *@returnPageUtils   */  PageUtilsqueryPage(Map<String,Object>params);   ServiceImpl: Page<数据库对象实体>pa......
  • Unity ECS内存分配器原理详解
    ECS为什么会高效,性能好,Entity的内存布局与分配就是非常重要的部分,今天我们一起来分析一下UnityECS架构里面如何来做高效的内存分配器。这种思路也可以给我们做内存分配提供很好的一个思路。1:ECS 里面基本的一些概念UnityECS框架里面有几个重要的概念:Entity,ComponentD......