我正在制作一款类似于《太空入侵者》的游戏。
到目前为止,我已经得到了移动和射击,但我遇到了一个问题。
当玩家发射激光时,我使用ussleep调用来延迟激光在屏幕上的移动,这样它就不会从屏幕的一端显示到另一端。
使用ussleep延迟激光的问题意味着当激光在屏幕上移动时,玩家不能四处移动,直到循环退出。
我的问题是,有没有另一种方法来打印激光在屏幕上移动,同时移动播放器/光标与用户输入?
当用户按下'f'键时,下面的代码将线(激光)移动到屏幕上。但是,在激光离开屏幕之前,用户不能再次移动:
void combat(int y, int x)
{
do
{
mvprintw(y -1, x, "|");
refresh();
y--;
usleep(50000);
mvprintw(y , x, " ");
}
while(y>0);
}
如果没有外部线程,这个问题很难解决。通过将激光的运动绑定到输入(这样只有当屏幕应该被外部输入刷新时才更新位置)来删除睡眠功能是行不通的,因为你需要激光独立于其他一切。
一个肮脏的hack可能有:
- 通过
int nodelay(WINDOW *win, bool bf)
的非阻塞输入函数,使输入函数不会阻塞任何东西 - 给定的(足够高的)刷新率,例如10 FPS(睡眠100毫秒)
- 每帧更新一次激光位置,使其移动足够慢,但能够轮询输入足够频繁
最简单的解决方案是用包含一条睡眠指令的循环编写程序,例如:
frame_timer = 0;
while (1) {
if (player_is_alive) {
move_player();
move_aliens();
move_laser_bullets();
check_collisions();
}
else {
draw_explosion();
if (explosion_finished) break;
}
frame_timer++;
usleep(20000); /* Refresh at approximately 50fps */
}
我实际上已经找到了一个体面的解决方案来解决我自己的问题,所以我将把它留在这里,以防将来有人遇到类似的问题。
当我的程序进入战斗功能时,它也进入无延迟模式,使非阻塞getch()。当函数在睡眠中循环时,用户可以在任何时候输入一个字符导致船移动,并且由于它处于无延迟模式,如果用户选择保持静止,getch()不会阻止睡眠函数的执行。
当用户按下'f'时执行的战斗功能:
void combat(int y, int x)
{
int input;
int y2 = y;
int x2 = x;
do
{
mvprintw(y2 -1, x2+1, "|");
refresh();
y2--;
mvprintw(y2 , x2+1, " ");
usleep(50000);
nodelay(stdscr, TRUE);
input = getch();
switch(input)
{
case 'w':
mvprintw(y, x," ");
y--;
mvprintw(y, x,"^V^");
break;
case 'a':
mvprintw(y, x+2," ");
x--;
mvprintw(y, x,"^V^");
break;
case 's':
mvprintw(y, x," ");
y++;
mvprintw(y, x,"^V^");
break;
case 'd':
mvprintw(y, x," ");
x++;
mvprintw(y, x,"^V^");
break;
}
}
while(y2>0);
movement(y,x);
}