Как сделать так, чтобы что-то происходило на экране даже без нажатия клавиши?

Я делаю Pacman на C ++ с библиотекой Ncurses. Я могу перемещать Pacman с помощью своего кода, но я хочу переместить его так, чтобы pacman продолжал двигаться, даже когда я не нажимаю ни одной клавиши, а когда я нажимаю другую клавишу направления, он меняет направление. Прямо сейчас pacman делает только один шаг, когда я нажимаю клавишу. Также я должен нажать клавишу 2 или 3 раза, прежде чем pacman двинется в этом направлении.

if (ch==KEY_LEFT)
{
    int b,row,column;
    getyx(stdscr,row,column);
    int h; 
    do    // do-whileloop to move the pacman left until it hits the wall
    {
        column-=1;
        mvprintw(row,column,">");  //print the ">" symbol
        refresh();
        waitf(0.1);      //this pauses the game for 0.1sec
        attron(COLOR_PAIR(1));      
        mvprintw(row,column,">");
        attroff(COLOR_PAIR(1));
        refresh();
        waitf(0.1);
        mvprintw(row,(b),"O");  //showing the open mouth of pacman
        refresh();
        waitf(0.1);
        attron(COLOR_PAIR(1));a
        mvprintw(row,column,"O");
        attroff(COLOR_PAIR(1));
        h = getch();
    }
    while(h == KEY_LEFT);
}

right = getch();

цикл для перемещения вправо в условии if

up = getch();

цикл для перемещения вверх в условии if

down = getch();

oop для движения вниз в состоянии if.


person User14229754    schedule 24.09.2012    source источник
comment
Поместите такое условие, что когда пользователь перемещает pacman, он входит в цикл и останавливается и ждет следующей инструкции только тогда, когда он достигает стены.   -  person Coding Mash    schedule 24.09.2012
comment
но я хочу, чтобы при нажатии другой клавиши pacman менял направление.   -  person User14229754    schedule 24.09.2012


Ответы (5)


Стандартным решением этой проблемы является конечный автомат. У персонажа есть шесть или около того возможных состояний: стоя, движение вверх, движение вправо, движение вниз, движение влево, мертвый. Вместо того, чтобы непосредственно перемещать символ, нажатие клавиши должно изменить состояние персонажа.

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

enum PlayerState {
    Standing,
    MovingUp,
    MovingRight,
    MovingDown,
    MovingLeft,
    Dead
};

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

switch(state) {
case Standing:
    break;
case MovingUp:
    player.PositionY += 1;
    break;
// ...
}

Последний шаг - перехватить ввод, что зависит от вашего метода получения ввода. Пример использования обратных вызовов:

void KeyDown(Key k) {
    switch(k) {
    case UpArrow:
        if(state != Dead)
            state = MovingUp;
        break;
    case RightArrow:
        if(state != Dead)
            state = MovingRight;
    // ...
    }
}

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

person Anthony Burleigh    schedule 24.09.2012

Вам понадобится эквивалент kbhit, т.е. неблокирующий getch. Что действительно дает решение, установите на входе O_NONBLOCK. См. Пример здесь. Как только у вас есть это, просто зацикливайтесь непрерывно и просто проверяйте нажатие клавиши, не дожидаясь фактического нажатия клавиши.

person Remus Rusanu    schedule 24.09.2012
comment
+1 для O_NONBLOCK, прошло много времени с тех пор, как я коснулся этих API C. - person Anthony Burleigh; 24.09.2012

Функция getch заблокирована, пока не будет нажата какая-либо клавиша. Если вы не хотите, чтобы вас блокировали, вызовите _kbhit перед getch, также убедитесь, что во входном буфере что-то есть.

РЕДАКТИРОВАТЬ: взгляните на функции ncurses nodelay и cbreak. Они позволяют асинхронный ввод.

person Dialecticus    schedule 24.09.2012
comment
Я не могу использовать kbhit () с ncurses. - person User14229754; 24.09.2012
comment
На какой ОС вы работаете и какой компилятор используете? - person Dialecticus; 24.09.2012
comment
g ++ compiler.Я использую программу putty для подключения к моему университетскому серверу. - person User14229754; 24.09.2012
comment
Вы используете окна для подключения через Putty, но код работает на сервере, и сервер, вероятно, представляет собой какой-то Linux. - person Dialecticus; 24.09.2012

Предлагаю вам взглянуть на модель-представление-контроллер, это поможет вам с этой проблемой и со всеми другими проблемами, которые могут возникнуть, если вы продолжите свою программу таким образом.

Изменить: ярлык

Для непрерывного перемещения вашего pacman вам понадобится отдельный поток, чтобы управлять им и заставлять его двигаться. Взгляните на pthreads для этого.

Если вы сохраните только пользовательский ввод в основном цикле выполнения вашей программы, проблема, связанная с тем, что вам придется нажимать клавиши несколько раз, тоже исчезнет (проблема здесь в том, что процессор должен находиться в строке getch (), когда вы нажимаете клавишу, иначе она не будет обнаружена.

person Minion91    schedule 24.09.2012
comment
Это слишком общий ответ, и на самом деле он не отвечает на вопрос. - person Dialecticus; 24.09.2012
comment
Я новичок, и у меня мало времени. Не могли бы вы подсказать другое решение? - person User14229754; 24.09.2012
comment
можешь мне сказать попроще? - person User14229754; 24.09.2012
comment
вы можете увеличить позицию pacman в основном цикле выполнения, но я не думаю, что ваш профессор будет доволен этим решением. - person Minion91; 24.09.2012

Это довольно просто: для каждого направления сделать 4 функции и внутри функции вставить другие 3 функции направления, которые активируются kbhit.

и поместите оператор else, в котором он будет двигаться вперед, если вы не нажмете кнопку, т.е. (! kbhit ()); а затем сложите все это в петлю.


Если вы сделаете это для всех функций направления, вы сможете получить желаемый результат.

person Jaison Jose    schedule 23.01.2013
comment
Другие ответы, по крайней мере, пытаются ответить на вопрос и предоставить конкретные решения. Вы, с другой стороны, просто вставили тот же плохо отформатированный код из своих (закрытых) вопросов без каких-либо объяснений или указаний. Ознакомьтесь с другими вопросами и ответами по SO, чтобы получить представление о том, как работает сайт. Не принимайте это на свой счет, я знаю, что у вас получится лучше. Ваше здоровье. - person Blastfurnace; 26.01.2013
comment
я не знаю, почему каждый продолжает говорить, что он плохо отформатирован, как я могу сделать его лучше ??? - person Jaison Jose; 27.01.2013
comment
Наиболее очевидными проблемами формата являются отступы и квадратные скобки. Они появляются в кажущихся случайными местах и ​​несовместимы по всему вашему коду. Компилятор не заботится о форматировании, но он помогает (или вредит) способности человека-читателя быстро понять структуру и поток управления. Почему некоторые из ваших функций появляются до main(), а другие тесно связанные функции появляются после? Это похоже на случайный беспорядок без планирования или организации. У вас есть односимвольные имена переменных, которые не дают представления об их назначении, и объявленные переменные, которые никогда не используются. - person Blastfurnace; 27.01.2013