0 / 0 / 0
Регистрация: 06.10.2013
Сообщений: 30
1

Очистка входного потока

22.04.2015, 19:04. Показов 4104. Ответов 2
Метки нет (Все метки)

Здравствуйте уважаемые!

Пишу игрушку на C#, возникла проблема: в одном месте (в меню выбора уровней) нужно отобразить уровень, отображается он "в лоб", потому делается это медленно. Хотелось бы улучшить процесс вывода, но ничего лучше пока не придумал, да и не в этом дело. Проблема заключается в том, что меню выбора уровней у меня устроено так, что при нажатии стрелки вверх, номер уровня увеличивается на 1, и соответствующий номеру уровень выводится на экран. Аналогично работает и стрелка вниз. Если зажать любую из них программа начнёт подвисать (т.е. видимо пока программа выводит на экран карту, во входной поток записывается зажатая кнопка снова и снова. Таким образом, даже если после этого отпустить кнопку, программу будет ещё несколько секунд крутить карты). Как можно ограничить входной поток на время вывода карты? То бишь, пока карты выводится на экран во входной поток не должны попадать значения, а потом, когда она выведется, допустить одну. (действо происходит в консоли)

Спасибо тем, кто прочитал
__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
22.04.2015, 19:04
Ответы с готовыми решениями:

Прочитать все из входного потока
Начал учиться программировать на c#, решая задачки на сайте олимпиадного программирования. Сразу же...

Недопустимый двоичный формат входного потока
Всем привет! Возникла такая ошибка: "Недопустимый двоичный формат входного потока." В чем может...

Выловить из входного потока нажатие Enter в незаполненной консоли
Как можно выловить из входного потока нажатие Enter в незаполненной консоли? Т.е. что бы при...

Очистка textBox из другого потока
Как можно попроще очистить textBox из неосновного потока?

2
[Bicycle Reinventor]
331 / 269 / 109
Регистрация: 19.10.2011
Сообщений: 668
Записей в блоге: 2
23.04.2015, 10:05 2
Лучший ответ Сообщение было отмечено DonkeyKong как решение

Решение

Когда изучал паттерн GameLoop, упрощал некоторые куски кода на примере MonoGame, адаптируя их под консоль. Стремления создать полноценную игру не было - интересно было создать лишь консольный игровой движок, на основе которого можно было потом что-то сделать. Тогда же я столкнулся с проблемой, которая имеет те же корни, что и у вас.
В геймдеве всегда есть потребность в обработке длительных и одиночных нажатий клавиш. Например, если мы нажимаем кнопку бега, персонаж должен бежать, пока кнопка нажата. И наоборот - если мы нажимаем кнопку прыжка, персонаж должен прыгнуть лишь один раз и не прыгать снова, пока пользователь не отпустит кнопку и не нажмёт её снова. Для этих целей на каждой итерации игрового цикла состояние пользовательского ввода проверяется с состоянием на предыдущей итерации, чтобы видеть изменения (за счёт этого можно обнаруживать события нажатия и отпускания клавиши). Однако это не работает для консоли, потому что у консоли нет ивентов типа keyDown и keyUp, а именно они используются для реализации этого механизма. Консольное окно - если грубо - просто текстовый редактор. Что будет, если в текстовом редакторе зажать кнопку? В момент нажатия нужная буква появится в тексте, затем последует пауза в секунду, а затем эта буква будет потоком очень быстро набираться в текстовое поле. Поэтому при обработке пользовательского ввода в консоль, мы фактически обрабатываем текстовый ввод.
Какими могут быть решения? Как вариант - можно было бы использовать глобальный хук клавиатуры, но я не знаю, как это работало бы на самом деле с консолью. Я решал проблему по-другому. Для того, чтобы пользовательский ввод был независимым, я вынес обработку пользовательского ввода из основного цикла GameLoop в отдельный поток, чтобы методы отрисовки и игровой логики ему не мешали, реализовал сохранение статуса нажатой кнопки на предыдущей итерации и завёл отдельный флаг, отображающий прочитал ли основной цикл нажатую клавишу или она ещё не обработана.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
        // работает в отдельном потоке
        private void ProcessInput()
        {
            while (true)
            {
                if (Console.KeyAvailable)
                {
                    pressedKey = Console.ReadKey(true);
                    keyReaded = false;
                }
                else if (keyReaded)   // флаг keyReaded выставляется, если основной поток обработал нажатие
                {
                    pressedKey = new ConsoleKeyInfo();   // в таком случае мы очищаем последнюю нажатую клавишу
                }
                Thread.Sleep(1);
            }
        }
И основной игровой цикл:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
        public void Run()
        {
            gameTimer.Start();
            while (true)
            {
                long currentTicks = gameTimer.Elapsed.Ticks;
                elapsedTicks += currentTicks - previousTicks;
                previousTicks = currentTicks;
 
                if (elapsedTicks < targetElapsedTicks)
                {
                    Thread.Sleep((int)TimeSpan.FromTicks(targetElapsedTicks - elapsedTicks).TotalMilliseconds);
                }
 
                if (elapsedTicks > maxElapsedTicks)
                {
                    elapsedTicks = maxElapsedTicks;
                }
 
                gameTime.ElapsedGameTime = targetElapsedTicks;
                int stepCount = 0;
                while (elapsedTicks >= targetElapsedTicks)
                {
                    gameTime.TotalGameTime += targetElapsedTicks;
                    elapsedTicks -= targetElapsedTicks;
                    ++stepCount;
                    Update(gameTime);
                    keyReaded = true;
                }
                gameTime.ElapsedGameTime = targetElapsedTicks * stepCount;
 
                Draw(gameTime);
            }
        }
Гораздо проще дело обстоит в WinForms, и я очень надеюсь, что у вас именно это. В конечном итоге я также перешёл с консоли на WinForms и избавился от проблем пользовательского ввода, адаптировав классы Keyboard, KeyboardState и KeyState из моногейма.

Если вы пишете игру, рекомендую самостоятельно изучить паттерн GameLoop, потому что все игры за последние лет 10-15 написаны с использованием этого паттерна, пошаговые ли, реального времени ли, да хоть рогалики и квесты.

Хорошую статейку по этому поводу можно найти здесь. Я бы даже сказал, что очень хорошая статейка.
Пример с хабра.
Также полезными окажутся исходники MonoGame, которые можно найти здесь. Игровой цикл там реализовал по всем правилам паттерна и идентичен тому, что используется в XNA.
1
0 / 0 / 0
Регистрация: 06.10.2013
Сообщений: 30
23.04.2015, 10:43  [ТС] 3
Большое вам спасибо за советы и полезные ссылки. Прочитал одну из них и уже смог заметно упростить алогритм цикла игры.
К сожалению задание - написать игру (Pac-Man на советский манер) в консоли без использования многопоточного функционала. Поэтому, проблема остаётся не решённой. Буду искать ответ
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
23.04.2015, 10:43
Помогаю со студенческими работами здесь

Записать число в начало потока вернувшись с конца потока после записи нескольких элементов...
public static void Save(List&lt;SomeClass&gt; listSC, String fileName) { using...

Как из одного потока узнать состояние другого потока
Подскажите пожалуйста, как из одного потока узнать, что другой поток еще не запущен. Например,...

Очистка входного потока (cin или stdin)
ПОМОГИТЕ ПОЖАЛУЙСТА!!!! Делаю программу под консоль в линуксе, запрашиваю с клавиатуры имя файла....

Слова входного потока
Вывести самые длинные слова входного потока! если во вх потоке самое длинное слово одно,то...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
3
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2023, CyberForum.ru