我试图用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);
}
我不会详细介绍游戏功能,因为这些功能很好。唯一有问题的一点是睡眠部分。我没有看到我失败的地方。
感谢您的关注。
答案 0 :(得分:1)
这个版本的方法略有不同:
请注意,必须为move_snake()
准备c
为ERR
,表示没有输入,但实际上并不是新约束。另请注意,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