Ncurses蛇等待

时间:2014-11-26 22:26:34

标签: c ncurses

我试图用C和ncurses做一个小小的蛇游戏,我发现目前最难的部分是等待。我认为我的代码会使主循环只进行每秒(至少),但它非常不规则,当getch()重新调用某些东西时更快/更慢。

...
timeout(1000);
...
while(1)
{
    if(!prey)
    {
        prey = TRUE;
        create_prey(s, map);
    }
    clear();
    draw_map(map, s);
    refresh();
    clock_gettime(CLOCK_REALTIME, &start);
    flushinp();
    c = getch();
    clock_gettime(CLOCK_REALTIME, &end);
    if(end.tv_nsec - start.tv_nsec < 1E9)
    {
        wait.tv_sec = end.tv_sec - start.tv_sec;
        wait.tv_nsec = 1E9 - (end.tv_nsec - start.tv_nsec);
        nanosleep(&wait, &wait);
    }
    move_snake(s, c);
}

我不会详细介绍游戏功能,因为这些功能很好。唯一有问题的一点是睡眠部分。我没有看到我失败的地方。

感谢您的关注。

2 个答案:

答案 0 :(得分:1)

这个版本的方法略有不同:

  1. 它通过从整数时钟秒开始执行游戏滴答来简化计时计算。这样可以非常可靠地每秒更新一次,直到并且除非更新开始花费超过一秒的时间进行计算。
  2. 因此,它通过非阻塞读取读取用户击键。出于这个原因,它在获取输入之后刷新输入缓冲区而不是之前。
  3. 请注意,必须为move_snake()准备cERR,表示没有输入,但实际上并不是新约束。另请注意,nanosleep()仅保证最小持续时间,而不是确切的持续时间;这将使基于该函数(或sleep())的任何实现可能有点不规则。

    timeout(0);
    wait.tv_sec = 0;
    
    while(1)
    {
        clock_gettime(CLOCK_REALTIME, &start);
        wait.tv_nsec = 1000000000 - start.tv_nsec;
        nanosleep(&wait, &wait);
        if(!prey)
        {
            prey = TRUE;
            create_prey(s, map);
        }
        clear();
        draw_map(map, s);
        refresh();
        c = getch();
        flushinp();
        move_snake(s, c);
    }
    

答案 1 :(得分:0)

// this code block:

if(end.tv_nsec - start.tv_nsec < 1E9)
{
    wait.tv_sec = end.tv_sec - start.tv_sec;
    wait.tv_nsec = 1E9 - (end.tv_nsec - start.tv_nsec);
    nanosleep(&wait, &wait);
}

contains a logic flaw.  
specifically, if the start time was (for example)
5.9 seconds
and the end time was (for example)
7.1 seconds
then the code would think that less than 1 second
has elapsed, 
where (in reality) 1.2 seconds have elapsed
Therefore the code would setup a nanosleep time

what the code should do is check both the elapsed seconds AND
the elapsed nsec, in series, similar to:


// NOTE: following assumes times are unsigned values
#define ONE_SEC (1E9)

if( ((end.tv_sec - start.tv_sec) == 0)    // not crossed sec boundary
    ||                                    // --or--
    ( ( (end.tv_sec - start.tv_sec) == 1) // not crossed sec boundary > once
      &&                                  // and
      ( end.tv_nsec < start.tv_nsec )     // end fraction not yet crossed start fraction
    )
  )
{ // then one second not yet elapsed

    wait.tv_sec = 0; // not going to wait over 1 sec

    if( end.tv_sec > start.tv_sec )
    { // then still in same sec boundary
        // calc fraction remainder of this second + fraction time into next sec
        wait.tv_nsec = (ONE_SEC - end.tv_nsec) + start.tv_nsec;
    }

    else
    { // else have crossed sec boundary
         // calc fraction sec time between start-end
        wait.tv_nsec =  start.tv_nsec - end.tv_nsec);
    } // end if

    if( 0 < wait.tv_nsec )
    { // then, need to wait a while
        nanosleep(&wait, NULL);
    } // end if
} // end if