Прежде всего, общее примечание: это не то, как вы хотите использовать Lerp
.
В настоящее время вы всегда начинаете новую интерполяцию с растущим коэффициентом, но от текущего поворота / масштаба к максимальным значениям. .
Таким образом, в следующем кадре текущие значения уже будут перемещены, поэтому при следующей интерполяции используется другое начальное значение и т. Д. c.
Как правило, для интерполяции существует два варианта использования:
- Интерполировать текущее значение по отношению к цели, используя коэффициент constant . Это приводит к сглаженному движению, когда, например, движение камеры ожидает много дрожания. Это не то, что вы хотите сделать, так как это становится все медленнее и медленнее в конце, вероятно, никогда не достигнув цели.
- Интерполяция между постоянным начальной и конечной точкой с коэффициентом растущим от
0
до 1
. Это приводит к плавному движению в течение контролируемого времени. Это больше похоже на то, что вы хотите.
Mathf.PingPong
использует ввод времени и перемещается вперед и назад между 0
и заданным максимальным параметром.
В вашем случае вы хотите go до 1
, используя значение скорости в качестве множителя для ввода времени.
Как это
void Update()
{
t = Mathf.PingPong(speed * Time.time, 1);
target.localScale = Vector3.Lerp(target.localScale, maxScale, t);
target.localRotation = Quaternion.Lerp(target.localRotation,
Quaternion.Euler(maxRotate.x, maxRotate.y, maxRotate.z), t);
}
Тогда для одноразового нажатия клавиши все становится немного сложнее. Я бы предположил, что на данный момент вы всегда хотите подождать, пока одно нажатие кнопки «анимация» не будет сделано, прежде чем принять следующее нажатие клавиши для возврата.
Я бы использовал для этого Coroutine . Они работают как временные небольшие подпрограммы Update
, но их проще контролировать и поддерживать:
// Flag for blocking input until one routine is done
bool isMoving;
// Flag for deciding in which direction to go next
// Via the Inspector set this to the direction it shall initially go towards
[SerializeField] bool towardsMin;
void Update()
{
if(!isMoving && Input.GetKeyDown(KeyCode.C))
{
StartCoroutine(DoMove());
}
}
// Once started via a StartCoroutine call this will be executed
// every frame until the next yield command
IEnumerator DoMove()
{
// Just in case block concurrent routines
if(isMoving) yield break;
// Block input
isMoving = true;
// Decide if going to Max or min
var targetRot = Quaternion.Euler(towardsMin ? minRotate : maxRotate);
var targetScale = towardsMin ? minScale : maxScale;
// Store Start values
var startRot = target.localRotation;
var startScale = target.localScale;
var duration = 1 / speed;
var timePassed = 0f;
while(timePassed < duration)
{
t = timePassed / duration;
// Optional: add ease-in and ease-out
//t = Mathf.SmoothStep(0, 1, t);
target.localScale = Vector3.Lerp(startScale, targetScale, t);
target.localRotation = Quaternion.Lerp(startRotation, targetRotation, t);
// Increase the time passed since last frame
timePassed += Time.deltaTime;
// This tells Unity to "pause" the routine here,
// render this frame and continue from here
// in the next frame
yield return null;
}
// Just to be sure to end with exact values apply them hard once
target.localScale = targetScale;
target.localRotation = targetRotation;
// Invert direction
towardsMin = !towardsMin;
// Done -> unlock input
isMoving = false;
}
Если вы хотите прервать текущую подпрограмму и сразу же go вернуться, вместо нее используйте
// Flag for deciding in which direction to go next
// Via the Inspector set this to the direction it shall initially go towards
// Since the routine inverts this you have to set the initial value to exactly the opposite
// of what you want to be the first direction!
[SerializeField] bool towardsMin;
void Update()
{
if(Input.GetKeyDown(KeyCode.C))
{
StopAllCoroutines(DoMove());
StartCoroutine(DoMove());
}
}
// Once started via a StartCoroutine call this will be executed
// every frame until the next yield command
IEnumerator DoMove()
{
// Invert direction for the next time
towardsMin = !towardsMin;
// Decide if going to Max or min
var targetRot = Quaternion.Euler(towardsMin ? minRotate : maxRotate);
var targetScale = towardsMin ? minScale : maxScale;
// Store Start values
var startRot = target.localRotation;
var startScale = target.localScale;
var duration = 1 / speed;
var timePassed = 0f;
while(timePassed < duration)
{
t = timePassed / duration;
// Optional: add ease-in and ease-out
//t = Mathf.SmoothStep(0, 1, t);
target.localScale = Vector3.Lerp(startScale, targetScale, t);
target.localRotation = Quaternion.Lerp(startRotation, targetRotation, t);
// Increase the time passed since last frame
timePassed += Time.deltaTime;
// This tells Unity to "pause" the routine here,
// render this frame and continue from here
// in the next frame
yield return null;
}
// Just to be sure to end with exact values apply them hard once
target.localScale = targetScale;
target.localRotation = targetRotation;
}
Короче говоря: Избавьтесь от isMoving
и всех вхождений полностью!
Затем вам нужно будет инвертировать флаг towardsMin
перед 1058 * l oop! Таким образом, вам также нужно будет инвертировать флаг в Инспекторе, поэтому, если вы хотите, чтобы он сначала двигался в направлении максимума, установите для него значение true
=> Инвертировано сопрограммой => При первом перемещении в сторону значений максимума.
Напечатано на смартфоне, но я надеюсь, что идея проясняется