c# - 使用 Vector2.MoveTowards 缓入和缓出
问题描述
我见过很多用Vector2.Lerp
.
但我想使用Vector2.MoveTowards
,因为我正在随机化我的 NPC 行进的距离,并且我希望 NPC 的速度始终保持不变,无论行进的距离如何。理想情况下,AnimationCurve
如果可能的话,希望通过一个平滑的步进函数来精细地控制缓动,但也可以。这是我现在使用的简化代码(使用行为设计器,所以方法有点不同):
private readonly float Speed = 1.5f;
public SharedVector2 BugDirection;
public override void OnStart()
{
BugDirection.Value = new Vector2(Random.Range(0.1f, 0.5f), transform.position.y);
}
public override TaskStatus OnUpdate()
{
if (Vector2.Distance(transform.position, BugDirection.Value) == 0)
{
return TaskStatus.Success;
}
transform.position =
Vector2.MoveTowards(transform.position, BugDirection.Value, Speed * Time.deltaTime);
return TaskStatus.Running;
}
解决方案
好的,所以有一个第一个问题:永远不要用于==
比较两个float
值!
即使是这样的情况也5f * 0.2f / 10f == 1f
可能失败,因为由于浮点精度,它实际上可能是0.9999999
or 1.0000001
。
相反,您通常宁愿检查某个范围,例如
if(Mathf.Abs(a - b) <= someThreshold)
Unity 为此还提供Mathf.Approximately
和使用
if(Mathf.Approximately(a, b))
基本上等于使用
if(Mathf.Abs(a - b) <= Mathf.Epsilon)
Epsilon
在哪里
浮点数可以不同于零的最小值。
就您当前的停止条件而言。
我现在只是假设这发生在 a 之外的某个地方,MonoBehaviour
所以协程不是一个选择。
但是,您基本上想要实现的是具有一个从线性(时间)持续增长的值,0
映射1
到缓入和缓出的运动曲线上。
因此,假设目标位置在运动的开始和结束之间没有更新,我会这样做,例如
private readonly float Speed = 1.5f;
private Vector2 target;
private Vector2 start;
private float timePassed;
private float duration;
public override void OnStart()
{
target = new Vector2(Random.Range(0.1f, 0.5f), transform.position.y);
start = transform.position;
duration = Vector2.Distance(start, target) / speed;
timePassed = 0f;
}
public override TaskStatus OnUpdate()
{
if (timePassed >= duration)
{
transform.position = target;
return TaskStatus.Success;
}
var factor = timePassed / duration;
//MAGIC
transform.position = Vector2.Lerp(start, target, factor);
timePassed += Time.deltaTime;
return TaskStatus.Running;
}
到目前为止,这将是一个线性运动,就像以前一样;)
所以让我们填写MAGIC
.
缓入和缓出的一个非常简单的选择是使用Mathf.SmoothStep
例如
factor = Mathf.SmoothStep(0, 1, factor);
或者你AnimationCurve
现在可以使用
factor = yourAnimationCurve.Evaluate(factor);
这使您可以完全控制运动的平滑度,但总平均速度speed
就像您将其线性应用一样。
推荐阅读
- azure - 适用于应用服务计划和 Application Insights 的 Azure 灾难恢复
- excel-formula - 基于 snother 单元格的条件格式
- android - 每当有人在 Android Studio firebase 中发送消息时,如何防止我的聊天内容重复
- php - 在 php 7.3 中重定向后 PHP 会话丢失
- javascript - 用有距离的随机整数填充数组
- javascript - JS,当一个变量被赋值给另一个变量时,它是持有对该变量的引用还是该变量当时持有的值?
- laravel - 如何在无纸管道中创建 SSO URL
- java - Android 中的未知 Firebase 服务崩溃
- php - 期望第 34 行 /home/pirmansa/laravel/vendor/ramsey/uuid/src/functions.php 中的变量(T_VARIABLE)
- scala - 将获取参数传递给控制器