Если условное выполнение

Я столкнулся с ситуацией, с которой не сталкивался до использования управляющей структуры IF с дополнительным вложенным IF. Обычно вложенный IF разбивает то, что я проверяю, на более мелкие детали, но в этом случае он фактически конфликтует с внешним условным оператором — я проверяю щелчок мыши.

Вот код -

if (mouseState.LeftButton == ButtonState.Pressed)
{
     if (mouseState.LeftButton == ButtonState.Released)
     {
          //move sprite to clicked position
          spritePos.X = mouseState.X;
          spritePos.Y = mouseState.Y;
     }
}

У меня есть пара вопросов. Меня учили, что условный аргумент проверяется только один раз, и если он оценивается как истинный, выполняются следующие операторы. Это правда или это действительно проверяется перед выполнением каждого оператора в блоке? - поскольку последнее, очевидно, вызовет конфликт с моим вложенным if.

Если это правда, то почему мой метод нажатия кнопки не работает? Спрайт никогда не перемещается, как если бы отпускание мыши никогда не выполнялось. Это потому, что задержка между выполнением проверки обоих условий настолько мала, что я физически не могу отпустить кнопку за это время? Могу ли я быть немного хакерским в этом и преодолеть это с задержкой по времени, которая может быть достаточно большой, чтобы позволить отпустить кнопку мыши во время проверки вложенного условного выражения?

Методы для действий щелчка мыши, которые я видел, используют свойства мыши из предыдущего кадра и сравнивают с новым кадром, чтобы проверить щелчок мыши. Но этот метод должен вводить задержку хотя бы на один кадр для фактической обработки действия. Это может быть незаметно при высокой частоте кадров, но просто ради аргумента скажу, что у меня была игра, отображающая 20 кадров в секунду. UpdateInput() будет вызываться перед рендерингом любого кадра, позиции должны обновляться, а затем кадр должен рендериться последним.

Если бы операция полного щелчка мыши могла выполняться менее чем за 1/20 секунды, не было бы предпочтительнее обрабатывать действие сразу, а не сохранять переменную при первом нажатии и сравнивать состояния в следующем кадре? Это, безусловно, было бы лучше, чем вводить дополнительную задержку ввода.

Я уверен, что это должно было быть рассмотрено другими раньше, и, возможно, я неправильно думаю об операции задержки по времени, фактически приостанавливающей выполнение кода. Могут ли временные задержки приостанавливать выполнение кода процессором или только результат этих исполнений, например рендеринг и прием ввода? У меня нет опыта их использования, и я могу сбить с толку, как будет работать задержка.

Спасибо, Эндрю.


person Drew_StackID    schedule 22.11.2010    source источник
comment
На каком языке вы программируете и какие API используете. Это действительно зависит от того, может ли оценка mouseState.LeftButton иметь ПОБОЧНЫЕ ЭФФЕКТЫ, которые могут изменить состояние mouseState (или дождаться его обновления)   -  person Alex Brown    schedule 22.11.2010
comment
Просто предложение: ваш вопрос больше похож на эссе, чем на технический вопрос. Это не сфокусировано и трудно ответить. Обрежьте его сильно. Фрагмент кода ваш или вы его где-то нашли? Это работает? Если это не сработает, что на самом деле произойдет? Что вы ожидаете? Проблема здесь (если она есть) не в оценке оператора if, это я могу вам сказать.   -  person Jonathon Faust    schedule 22.11.2010
comment
Извините, я думал, что это было достаточно коротко. Я попытался просто упомянуть вещи, о которых я думал, которые могли бы иметь эффект. Фрагмент кода мой - не работает, как указано ниже. В результате мой произвольно анимированный спрайт продолжает двигаться, а не появляется там, где я нажимаю. Это просто вводный курс для изучения ввода. Язык C# с использованием XNA 3.1.   -  person Drew_StackID    schedule 22.11.2010


Ответы (3)


Эндрю, твоя проблема не имеет ничего общего с тем, как работают операторы if. mouseState представляет состояние мыши при вызове GetState(). Он не изменится только потому, что мышь изменит свое состояние. Чтобы ваш фрагмент кода работал так, как вы ожидаете, вам нужно будет вызывать GetState() перед каждым оператором if. Состояние мыши изменяется только при опросе или установке вручную.

person Steve H    schedule 23.11.2010
comment
Я чувствую себя таким глупым, что не заметил этого. Спасибо, что указали мне на это. - person Drew_StackID; 23.11.2010
comment
@Drew: Э-э, вам также нужно будет нажать кнопку мыши и отпустить ее в течение наносекунды между проверкой первого условия и проверкой второго условия, что, я уверен, не то, что вы хотите ... - person BlueRaja - Danny Pflughoeft; 01.07.2011

О, здесь так много неправильного...

Что вы предположительно делаете перед блоком операторов if:

MouseState mouseState = Mouse.GetState();

Теперь функция GetState определяет текущее состояние мыши и упаковывает его в структуру MouseState. С помощью = вы назначаете это состояние переменной mouseState.

Единственный раз, когда mouseState изменится, это когда вы сами его поменяете! Итак, ваше условное выражение выглядит так:

if (mouseState.LeftButton == ButtonState.Pressed) {
    if (mouseState.LeftButton == ButtonState.Released) { /* "do stuff" */ }
}

Вы проверяете, равно ли mouseState.LeftButton, которое не меняется, двум совершенно разным вещам! Таким образом, очевидно, что «делай что-нибудь» никогда не будет работать.

Теперь я могу проиллюстрировать другую часть проблемы, заставив код работать так, как вы думаете, он должен работать:

if (Mouse.GetState().LeftButton == ButtonState.Pressed) {
    // Some kind of delay, perhaps?
    if (Mouse.GetState().LeftButton == ButtonState.Released) { /* "do stuff" */ }
}

Таким образом, состояние обновляется каждый раз, когда вы его проверяете.

Теперь вот проблема с этим кодом. Ваша мышь должна совершить переход из состояния "Нажато" в состояние "Отпущено" между двумя операторами if. Если это не так, условие не сработает.

Увеличение продолжительности задержки не исправит ситуацию по многим причинам: во-первых, это отнимает время от фактического запуска вашей игры. Во-вторых, его невозможно увеличить до 100% времени кадра, поэтому всегда будет процентная вероятность того, что ваше состояние не сработает.

Поэтому лучший способ обработки ввода — отслеживать состояние состояния между кадрами. И лучший способ сделать это, как показано во всех руководствах, — сохранять MouseState lastMouseState; между вызовами вашей функции Update. Итак, ваш код должен выглядеть примерно так:

MouseState mouseState = Mouse.GetState();
if (lastMouseState.LeftButton == ButtonState.Pressed)
{
    if (mouseState.LeftButton == ButtonState.Released)
    {
        /* "do stuff" */
    }
}
lastMouseState = mouseState;

Теперь вы можете сказать, что это все еще оставляет вам реальную проблему, которую вы упомянули в первую очередь: что, если использование щелкает так быстро, что состояние мыши изменяется, а затем возвращается обратно между вызовами GetState?

Что ж, мой первый ответ на это — «не беспокойтесь об этом». Это является известной проблемой среды ввода XNA. Но на практике вы обнаружите, что люди обычно не нажимают и не печатают так быстро, что это вызывает фактические проблемы при 60 кадрах в секунду.

Если ваша игра работает со скоростью значительно ниже 60 кадров в секунду, вы все равно можете запускать обновления со скоростью 60 кадров в секунду. Чтобы уменьшить скорость прорисовки, вы можете использовать Game.SupressDraw или заставить Game.BeginDraw возвращать false (см. -or-will-display-a-purple-screen/4236431#4236431">здесь и здесь). Если вам также нужно запускать обновления со скоростью менее 60 кадров в секунду, вы все равно можете обновлять ввод со скоростью 60 кадров в секунду (или быстрее!), но это намного больше работы. (Обратите внимание, что ввод XNA должен выполняться в основном потоке.)

(Лично я бы посоветовал вам просто работать со скоростью 60 кадров в секунду и перестать беспокоиться об этом!)

Наконец, если вам этого недостаточно, вы можете возиться с взаимодействием, перехватывать насос сообщений и перехватывать WM_LBUTTONUP сообщений. Это огромное излишество, но это «правильный» способ получить то, что вы хотите.

person Andrew Russell    schedule 23.11.2010
comment
Спасибо, Андрей, информация действительно полезная. Я вряд ли буду пробовать какие-либо более продвинутые вещи, я некоторое время программировал вкл / выкл, и теперь мне трудно вникнуть, поэтому каждый раз, когда я пытаюсь сделать еще один выстрел, это довольно ново для меня, и я забыть вещи. Дал Стиву правильный ответ, потому что он пришел немного раньше, но информация, которую вы предоставили, была отличной, спасибо. - person Drew_StackID; 23.11.2010

это не работает, потому что, если вы нажмете левую кнопку, то нет возможности отпустить ее до того, как программа проверит if (mouseState.LeftButton == ButtonState.Released) условие.

Могут ли временные задержки приостанавливать выполнение процессором кода

Задержка ввода мышью и клавиатурой незаметна.

Я бы использовал переменную для хранения состояния левой кнопки в каждом кадре:

while (1) // ininity loop
{
    if (mouseState.LeftButton == ButtonState.Pressed)
    {
         button_left_pressed = 1; // is pressed
    }
    else // Left Button is not pressed
    {
         if ( button_left_pressed ) // but was pressed (is released)
         {
             spritePos.X = mouseState.X;
             spritePos.Y = mouseState.Y;
             button_left_pressed = 0; // is not pressed
         }
    }
    // do another action        
}
person atlavis    schedule 22.11.2010
comment
Привет, atlavis, я думаю, это должно сработать, это очень похоже на примеры пользовательского ввода, которые я просматривал. Я просто немного не знал, почему это не сработало в моем случае. Спасибо, что ответили на пару моих вопросов. - person Drew_StackID; 22.11.2010
comment
да, любая функция задержки времени останавливает выполнение кода, например задержка (время в миллисекундах) в PASCAL - person atlavis; 22.11.2010
comment
или здесь programmersheaven.com/mb /csharp/355557/355557/ - person atlavis; 22.11.2010