对象沿Y轴移动,我需要平滑地移动X轴位置。
void FixedUpdate()
{
playerRigidbody.velocity = new Vector2(0.0f, 2.0f);
if (Input.GetKeyDown(KeyCode.RightArrow))
{
if (newBallPos != 2)
{
Vector3 pos1 = this.transform.position;
Vector3 pos2 = this.transform.position;
pos2.x += 1f;
StartCoroutine(Move_Routine(this.transform, pos1, pos2));
}
}
----
}
----
private IEnumerator Move_Routine(Transform transform, Vector3 from, Vector3 to)
{
float t = 0f;
while (t < 1f)
{
t += Time.deltaTime;
transform.position = Vector3.Lerp(from, to, Mathf.SmoothStep(0f, 1f, t));
yield return null;
}
}
使用此代码。 X轴发生变化,但是随着Y轴的位置变旧,它会随着X轴的移动而产生某种程度的抖动。
单击箭头时,我需要平滑地更改对象X的位置,同时仍沿Y轴移动(我需要将X位置更改1)
感谢您的帮助!
答案 0 :(得分:0)
尝试用这种方法将x轴添加到Time.smoothDeltaTime;
中,将值在几帧上取平均值,以获得更平滑的效果,这是一种偏爱,但有时会产生明显的不同。
pos2.x += Time.smoothDeltaTime;
答案 1 :(得分:0)
首先,据我了解,您只想平滑头寸的X值,所以您宁可这么做
private IEnumerator Move_Routine(Transform transform, float from, float to)
{
float t = 0f;
while (t < 1f)
{
t += Time.deltaTime;
// only lerp the single float value
var currentX = Mathf.SmoothStep(from, to, t);
// let the current other two values unchanged
transform.position.x = currentX;
yield return null;
}
// Just to be sure there is no under/overshooting I would
// always set the fixed value in the end
transform.position.x = to;
}
但是,您遇到的另一个问题是您正在处理RigidBody。
您完全不应该在刚体上使用transform.position =
,而应该使用playerRigidbody.position =
或playerRigidbody.MovePosition(targetPosition)
协程会在每个Update
调用中执行,但您只应在FixedUpdate
=>中更改刚体,才能在协程中使用WaitForFixedUpdate
第三个问题是,如果在完成运动之前再次按下该按钮,则可能同时运行多个协同程序。 =>您可以通过简单的bool标志解决此问题。另外,如果您想允许输入(例如,要向另一个方向移动,则应先StopCoroutine
当前例程)
因此产生了抖动等。
private bool alreadyLerping;
private void FixedUpdate()
{
playerRigidbody.velocity = new Vector2(0.0f, 2.0f);
if (Input.GetKeyDown(KeyCode.RightArrow))
{
// only do if not lerping laready otherwise input is ignored
if (newBallPos != 2 && !alreadyLerping)
{
var currentX = transform.position.x;
var targetX = currentX + 1.0f;
StartCoroutine(Move_Routine(currentX, targetX));
}
}
...
}
// I just added an optional duration value
// if you do not pass it it will be 1 second as you had it
// but this way you can still make it faster or slower without having
// to hardcode
// you also don't have to pass in the transform or if you do you should not call it transform
private IEnumerator Move_Routine(float from, float to, float duration = 1.0f)
{
if(alreadyLerping) yield break;
alreadyLerping = true;
var passedTime = 0f;
do
{
yield return new WaitForFixedUpdate();
var lerpfactor = passedTime / duration;
var currentX = Mathf.SmoothStep(from, to, lerpfactor);
playerRigidbody.MovePosition(new Vector3(currentX, transform.position.y, transform.position.z));
passedTime += Time.deltaTime;
} while (passedTime < duration);
// Just to be sure there is no under/overshooting I would
// always set the fixed value in the end
playerRigidbody.MovePosition(new Vector3(to, transform.position.y, transform.position.z));
// release the flag
alreadyLerping = false;
}
或者如果您想要StopCoroutine
变体
private IEnumerator currentRoutine;
private void FixedUpdate()
{
playerRigidbody.velocity = new Vector2(0.0f, 2.0f);
if (Input.GetKeyDown(KeyCode.RightArrow))
{
// only do if not lerping laready otherwise input is ignored
if (newBallPos != 2)
{
var currentX = transform.position.x;
var targetX = currentX + 1.0f;
if(currentRoutine!=null) StopCoroutine(currentRoutine);
currentRoutine = Move_Routine(currentX, targetX);
StartCoroutine(currentRoutine);
}
}
...
}