即使我在两个对象上都有对撞机,为什么一个对象会穿过另一个对象?
为什么我的角色在移动时会穿过另一个物体然后反弹回来?
如何在 Unity3d 中正确实现角色移动?
为什么经常使用 transform.position 移动,为什么它是错误的?
如果 FPS 下降,为什么我的角色会以不同的速度移动?
为什么分配中使用
transform.position
乘数Time.deltaTime
?为什么通过 shift 移动角色是错误的
transform.position
?为什么使用
Velocity
or时.AddForce()
不使用乘数Time.deltaTime
?如何从地板上跳下来,但让角色无法无休止地起飞
为什么当平台移动时,站在平台上的角色会留在原地?
为什么子弹不总是造成伤害?
事实上,所有这些问题都是初学者中太常见的一个问题。
同时创建了一个标签unity3d-faq
阅读前需要了解的重要信息
在任何情况下,角色都必须挂上 RigidBody - 一个负责角色物理(重力、摩擦力等)的脚本
虽然我在这里拆机,包括。非物理运动,我强烈推荐使用物理运动。只有在特殊情况下才切换到非物质。
代码中不应直接绑定到按钮。应该绑定到 Input Manager参数。可以在以下位置找到:
Edit -> Project Settings -> Input
。你需要接受这作为一个公理并且不要离开,尽管你在那里谷歌搜索。我将在这里使用 2 个术语:“传送”和“平滑移动”。据我了解:
平滑移动 - 在物理框架内重新计算对象的位置,或在调用时与物理并行
FixedUpdate()
。Teleportation - 在大于 的时间间隔内重新计算对象的位置
fixedDeltaTime
。.Translate()
方法改变位置。您可以通过以下方式在游戏引擎中移动对象:
使用物理引擎(由游戏引擎的物理模型驱动的运动)
运动不是物理的。错误的方法是在每一帧上传送的方法。(在
Update()
)运动不是物理的。正确的做法是物体在帧之间的平滑运动(平行于每个物理误算)(还是建议不要用)
通过CharacterController实现运动(这里暂不考虑,因为新人根本不看,也许我以后会签)
初学者经常在每一帧上都使用瞬移,这是一种严重错误的方法。然后在 SO 上有大量问题的克隆,例如“为什么角色在墙附近抽搐?” 或“为什么它会穿墙?” 或“为什么子弹不总是造成伤害?” 之类的。
只有一条规则要记住:您不能在作业中移动/旋转。这会产生问题。
transform.position
transform.rotation
无论如何,它会从侧面出现在你身上。所需要的只是传送到物体的另一个地方,而不是它的移动。
正确实施运动的一个例子:
(以物体球为例)
该脚本基于以下代码:https ://unity3d.com/learn/tutorials/projects/roll-ball-tutorial/moving-player
...
结果示例:
相关概念:
是
Update()
的——在每一帧绘图上调用这个方法。Time.DeltaTime
是绘制两帧之间的估计时间。如果 FPS 在计算机上下降,则此参数与下降成比例增加。是
FixedUpdate()
的 - 这是重新计算物理时调用的方法。Time.FixedDeltaTime
,你猜对了,是通话之间的时间FixedUpdate()
。它可以通过设置手动更改,但取决于启动游戏的机器的物理功能。如果对象没有物理属性(没有 RigidBody),这些参数和方法可以用于非物理运动。
例如,相机旋转。
或者在天空中旋转的立方体。
或者在您无法接近的遥远地方的火车的动态图像。物理学对这样的物体根本没用——只是浪费资源
如果我们正确地执行非物理运动,我们在丢帧时不会得到抖动的图片:
我们分配到一个新的位置:
Time.deltaTime
。因此,即使我们有 60 帧并且有多达 10 帧的下沉,物体的旋转/移动速度也不会改变。毕竟我们是和人员下沉一起考虑的。
关于运动的物理特性。
假设我们移动一个物体通过
rb.Velocity
或通过AddForce()
,那么这就是物体的物理运动。也就是说,它可以在某些物理定律的影响下随时间变化。例如,我们决定做一个角色跳跃:我们设置一次跳转向量。只有一瞬间。但它会随着时间的变化在重力作用下自动均匀递减。直到它变为零(跳跃的上点),然后它变为负数
Y
(下降),然后它落到地面并反弹(再次加上Y
)等等,直到物体的物理速度在地面完全停止。假设我们
transform.Positon
通过按空格键向前移动我们的播放器更改。在某些时候,我们停止按下按钮 - 运动会突然停止并冻结。这是因为我们的运动不是物理的。假设我们来到墙上并尝试爬上它。因为 我们正在对一个物体进行传送,然后我们的角色将首先到达墙壁,然后传送到它里面,然后Collider
它会被推出自己。它向内传送的深度仅取决于我们每帧传送角色的距离。也就是说,实现角色的移动是“坏习惯” 。但同时,也有一种可以接受的非物质运动。这就是使用方法
Transform.Translate()
。这(有点)也是瞬移,但试图使物体平稳地进行非物理运动。但是使用这种方法并不能免除我们使用 deltaTime/fixedDeltaTime 的责任,例如of.documentation。(同样——如果你的对象有一个刚体——你可能无论如何都需要使用物理位移!)
如果装有游戏的设备负载很重,调用方法
Update()
/FixedUpdate()
也会降低速度。如果在物理学中即使没有我们也考虑到这一点,那么现在我们不是在做物理运动,这就是为什么必须通过添加这个因素来考虑这一点。但即使不使用这个乘数,我们也不会有穿墙失败的问题。这只是一个速度修复。
一个简单但良好的非物理实现的移动代码示例,用于角色示例。
如果在前面的示例中我们移动了球,那么可以使用物理模型推动它。也就是说,我们用于
AddForce()
这些目的。假设我们有一个角色——一个人,而不是一个球。让我们创建一个他的肖像而不是一个人 - 一个高立方体 0.8x1.8x0.3 并尝试将我们的球运动脚本附加到它上面。会出来以下内容:
也就是说,当我们尝试移动时,我们的角色会摔倒(我们推他,这是合乎逻辑的!)。当他跌倒时,由于摩擦力,他无法移动。但是我们可以在一个跳跃中移动它。:)
让我们为这个角色更新这个代码。我们将用物体在空间中的非物理但平滑的运动来代替物体的物理推动:
使用此代码,我们将得到以下结果:
С такой реализацией у нас не будет проблем вроде скачков скорости на проседании или повышении количества FPS, проваливаний, дерганости, прохождения сквозь стены или других неожиданностей.
Теперь мы можем занятся украшательствами -- например повороты тела. Довольно приятно реализованы повороты вот здесь: Как сделать управление, как в игре "Overcooked"?
Так же можно добавить анимацию бега на нашего персонажа (ну если бы это был не куб).
Но как же реализация на физике?
Да, можно подобное реализовать и на физике.
Наша прошлая версия скрипта имела несколько недостатков. А именно:
Давайте поместим на наш куб
CapsuleCollider
(минимальное торможение из-за силы трения) и заблочим вrigidBody
rotateX
иrotateZ
(что б наш персонаж не падал на бок).А потом нацепим на него вот этот скрипт:
Вы видите эту плавность, как будто человек бежит, останавливается, бежит в другую сторону? Красота!
А теперь вернитесь к прошлой гифке и присмотритесь... Движение совсем не такое :) Там как буд-то рукой двигают шахматную фигуру по доске.
Ну и описанные выше баги поведения были пофикшены с такой реализацией.
Можно добавить еще физический материал нашему персонажу и откоректировать его поведение.
Вообще улучшать реализацию можно до бесконечности. Но, думаю, основные проблемы СПОСОБОВ ПЕРЕДВИЖЕНИЯ с которыми вы столкнетесь, я затронул :)
Реализация нестандартной физики движений.
Одним из моих любимейших примеров нестандартной физики движения является игра Ori and the Blind Forest
https://www.youtube.com/watch?v=aKLxJTvaVy0
Такое перемещение/такие прыжки невозможно сделать на основе стандартной физики. Вероятнее всего, это делалось через физическое перемещение + костыли для получения нужных эфектов которые противоречат стандартной физике.
Сначала разрабатываются концепты движения. Они делаются в любом видеоредакторе с примитивными фигурами. Вот пример (если станет недоступным искать можно по Ori and the blind forest Enemy Concepts ) :
https://www.youtube.com/watch?v=A8cV-oJfsjk
Обратите внимание на то, то здесь прорисовано не только перемещение обьекта, но и его вытягивания/сжатия. Изменения формы во время любого взаимодействия с внешним миром. В т.ч. выстрелы так же влияют на форму. А так же что указываются радиусы опознавания главного героя каждым отдельным врагом.
Костыли для каждого персонажа/врага свои собственные. Это делается что бы каждый из них обладал своей уникальной физикой. Сделать это на общей физике навряд ли возможно.
Движение реализовано "правильно" но предмет все равно пролетает сквозь стену
ДАЖЕ если вы реализовали физическое передвижение вашего персонажа, все равно может случится такое, что просчет CollisionDetect может проходить с ошибками. Такое бывает.
Для таких случаев есть настройки отвечающие за обработку CollisionDetect в настройках самого RigidBody.
Желательно такого не делать т.к. это негативно сказывается на производительности. Чем на большем количестве обьектов вы меняете эти настройки, тем более вероятно что вы делаете какую-то дичь, которую делать совсем не нужно. Считайте это спасательным кругом, а не панацеей. А если вы так будете делать, то рано или поздно вы прийдете на SO с вопросом почему игра тормозит, вас попросят показать код и ничего не найдут просто потому, что проблема тормозов не в коде. И намучаетесь вы с оптимизациями ой как сильно.
Так делать - не является ошибкой(!). Но чем меньше вы так будете делать - тем лучше. Подходите к изменению этих настроек с умом!
Информация для самостоятельного изучения:
NavMesh
Character Controller
在这个视频(我强烈建议您阅读) https://www.youtube.com/watch?v=puPjNRJMmOc中,已经讲述了一些不同的事情。如果在我上面描述的示例中,我们的角色只在平坦的表面上移动(也就是说,在地形或倾斜的平坦空间上可能会出现困难),那么这里已经描述了角色应该如何在不平坦的表面上移动。