Unity C# Как получать данные о вводе из Update(), если между ними иногда проскакивает по два FixedUpdate()?
В ходе реализации контроллера персонажа столкнулся с тем что персонаж иногда за одно нажатие прыжка в воздухе производит сразу два таких прыжка. У меня довольно запутанная как мне кажется система ввода, которая позволяет сохранять информацию о нажатии до того момента как она будет использована в FixedUpdate, и в итоге это вызывает то, что если между Update успевает произойти два вызова FixedUpdate, то первый раз он использует корректные данные, а второй те же самые, и по сути уже не актуальные. Итак, что вообще можно сделать в такой ситуации? Я по правде говоря совсем не знаю как подступиться к решению этого, поэтому каких либо даже плохих предложений не имею. Код системы ввода прикладываю
public class PlayerInput : MonoBehaviour
{
private bool inputIsLocked = false;
private bool hUsed, jUUsed, jDUsed;
private bool _jumpUp;
public bool jumpUp
{
get
{
jUUsed = true;
if (!inputIsLocked) return _jumpUp;
return false;
}
set
{
if(value)
{
_jumpUp = value;
jUUsed = false;
}
if (jUUsed)
{
_jumpUp = value;
}
}
}
private bool _jumpDown;
public bool jumpDown
{
get
{
jDUsed = true;
if (!inputIsLocked) return _jumpDown;
return false;
}
set
{
if (value)
{
_jumpDown = value;
jDUsed = false;
}
if (jDUsed)
{
_jumpDown = value;
}
}
}
private float _horizontal;
public float horizontal
{
get
{
hUsed = true;
if (!inputIsLocked) return _horizontal;
return 0;
}
set
{
if (value != 0)
{
_horizontal = value;
hUsed = false;
}
if (hUsed)
{
_horizontal = value;
}
}
}
private void Update()
{
jumpUp = UnityEngine.Input.GetButtonUp("Jump");
jumpDown = UnityEngine.Input.GetButtonDown("Jump");
horizontal = UnityEngine.Input.GetAxisRaw("Horizontal");
}
private bool CheckInputAccess()
{
if (inputIsLocked) return false;
return true;
}
public void LockInput(object sender)
{
inputIsLocked = true;
Debug.Log($"The input was locked by the{sender}");
}
public void UnlockInput(object sender)
{
inputIsLocked = false;
Debug.Log($"The input was unlocked by the{sender}");
}
}
Ответы (3 шт):
Вероятно, я мог бы попробовать добавить метод "обнуляющий" все значения, и вызывать его в самом конце FixedUpdate скрипта контроллера, однако звучит это как откровенный костыль. Впрочем, если не найдется ничего иного, воспользуюсь именно этим способом
Сам мало знаю, но вижу 2 решения 1) перенести движение в update и умножать его на Time.deltatime чтобы решить вопрос с кадрами 2) если ну прям сильно хочется в Fixed update(далее FU) сделать, то в настройках снизь частоту вызова FU. А вообще очень странно что у тебя за один update происходит вызов нескольких FU так как FU вызывается 50 раз за секунду, а update перед отрисовкой каждого кадра. Из чего могу сделать 2 вывода 1) ты уже поднял частоту вызова FU и она вызывается чаще update и у тебя не происходит перезапись переменной в update в следствии чего FU успевает забрать 2 и более раз эту переменную 2) у тебя FU вызывается 50 раз, но ты перегрузил update в следствии чего у тебя fps ниже 50 и FU вызывается чаще update. Но эти 2 замечания работают только если у тебя корректно работает код записи и перезаписи так как он у тебя мудрёный может быть ошибка в этом.
Можно попробовать в FixedUpdate проверять было ли уже применение данных ввода в кадре или нет, используя Time.frameCount:
int frame = -1;//последний кадр, в котором применяли пользовательский ввод
void FixedUpdate ()
{
if (Time.frameCount > frame)
{
/* здесь применение пользовательского ввода, обновление физики и вот это всё
...
*/
// запоминаем кадр в котором сделали применение пользовательского ввода,
// чтобы не произошло его повторное применение,
// если FixedUpdate вызовется ещё несколько раз в течение кадра
frame = Time.frameCount;
}
}