问题描述
所以我正在尝试创建一个向前奔跑的游戏(类似于 Temple Run),但我希望我的角色能够平滑地左右移动,而不仅仅是传送。我尝试使用 Vector3.Lerp()
,但我无法理解它是如何工作的。
这是我尝试过的,但角色只是传送
void Update()
{
if(Input.GetKeyDown("a")&&lane-1>0)
{
lane-=1;
shouldMove = true;
Vector3 newpos= new Vector3(transform.position.x -2.5f,transform.position.y,transform.position.z);
while (shouldMove)
{
transform.position = Vector3.Lerp(transform.position,newpos,0.1f * Time.deltaTime);
if(transform.position.x>=newpos.x)
{
shouldMove = false;
transform.position = newpos;
}
}
此示例仅用于向左移动。
解决方法
您认为使用 Vector3.Lerp
在开始值和结束值之间逐渐插入是正确的。但是,实现和用例不太适合您尝试执行的操作。
由于您只更改移动的单个轴,因此我不会使用 Vector3.Lerp
,而是使用 Mathf.Lerp
,因为您只更改了位置的 x 轴。
您使用的是 while
循环而不是 Update
意味着程序将停留在该循环内,直到该过程完成。它立即移动到下一点的原因是由于您的 if
条件。您正在从当前位置减去 2.5
的值,然后不断检查您当前的位置 x 是否大于新位置,这总是正确的。它会立即将您的当前位置设置为新位置,然后跳出 while 循环。另一个问题是您使用了 GetKeyDown
,它仅在用户单击键的一帧中发生。 Lerps
应该随着时间的推移完成,而不是立即完成。
我不会将您的逻辑放在 Update
中,而是考虑将实际运动移至名为 Coroutine
的特殊函数中。将 Courtines
视为在多个帧上完成的过程,然后跳回到前一帧中停止的位置。 Coroutines
非常强大,但请在过度使用它们之前仔细阅读文档以深入了解它们的作用。
现在开始实施。我不完全确定您的车道设置,但会假设您有 3 条车道,类似于其他无限跑道游戏。我会将输入检测保留在 Update
内,并允许玩家从中间从一侧跳到另一侧,但不会偏离轨道,也不会在跳跃时跳跃。我还将使用时间而不是速度来控制 Lerp
的跳跃,如果您愿意,可以轻松地将其更改为速度。
[SerializeField] private float TimeForJump = 0.25f;
[SerializeField] private float JumpOffset = 2.5f;
// I am assuming your setup for lanes is -1 | 0 | 1
private int lane = 0;
private Coroutine PlayerJumping = null;
void Update()
{
// no need to detect input if we are already jumping
if(PlayerJumping == null)
{
// instead of 'a' and 'd' you can use GetAxis to allow for arrow key and wasd support
// it is also an easy way to determine direction when adding or subtracting for a goal location
float horzInput = Input.GetAxis("Horizontal");
if (horzInput < 0 && lane > -1)
{
PlayerJumping = StartCoroutine(Jump(-1));
lane--;
}
else if(horzInput > 0 && lane < 1)
{
PlayerJumping = StartCoroutine(Jump(1));
lane++;
}
}
// simulating your movement
transform.position = new Vector3(transform.position.x,transform.position.y + 0.1f,transform.position.z);
}
/// <summary>
/// Horizontally have the player jump
/// </summary>
private IEnumerator Jump(float direction)
{
// store our current position
float currentXPos = transform.position.x;
// our goal position
float goalXPos = currentXPos + (direction * JumpOffset);
// timer for how long it has passed since we started the jump
float jumpTimer = 0.0f;
// continue the lerp for the time we have left
while(jumpTimer <= TimeForJump)
{
transform.position = new Vector3(Mathf.Lerp(currentXPos,goalXPos,jumpTimer / TimeForJump),transform.position.y,transform.position.z);
// increment the time that has passed
jumpTimer += Time.deltaTime;
yield return null;
}
// set our position directly in case of floating point errors
transform.position = new Vector3(goalXPos,transform.position.z);
// set the coroutine to null so we can jump again
PlayerJumping = null;
}
由于我不确定您的实施是如何完成的,因此我对车道和其他一般设置有一些假设。答案非常通用,因此可以根据您的需要进行调整。如果您愿意,您也可以将输入切换回 GetKeyDown
,我使用它的唯一原因是您可以获得箭头键以及 wasd 输入。