Unity C# Как получать данные о вводе из Update(), если между ними иногда проскакивает по два FixedUpdate()?

Рейтинг: 1Ответов: 3Опубликовано: 24.04.2023

В ходе реализации контроллера персонажа столкнулся с тем что персонаж иногда за одно нажатие прыжка в воздухе производит сразу два таких прыжка. У меня довольно запутанная как мне кажется система ввода, которая позволяет сохранять информацию о нажатии до того момента как она будет использована в 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}");
        }
    }

Ответы

▲ 0Принят

Можно попробовать в FixedUpdate проверять было ли уже применение данных ввода в кадре или нет, используя Time.frameCount:

int frame = -1;//последний кадр, в котором применяли пользовательский ввод

void FixedUpdate ()
{
    if (Time.frameCount > frame)
    {
        /* здесь применение пользовательского ввода, обновление физики и вот это всё
           ...
        */

        // запоминаем кадр в котором сделали применение пользовательского ввода,
        // чтобы не произошло его повторное применение,
        // если FixedUpdate вызовется ещё несколько раз в течение кадра
        frame = Time.frameCount;
    }
}
▲ 0

Вероятно, я мог бы попробовать добавить метод "обнуляющий" все значения, и вызывать его в самом конце FixedUpdate скрипта контроллера, однако звучит это как откровенный костыль. Впрочем, если не найдется ничего иного, воспользуюсь именно этим способом

▲ 0

Сам мало знаю, но вижу 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 замечания работают только если у тебя корректно работает код записи и перезаписи так как он у тебя мудрёный может быть ошибка в этом.