如何在不停顿蛇游戏的情况下阅读输入?

时间:2012-11-28 06:11:35

标签: ada

这是一项学校作业。创造一个蛇游戏。 所以我创建了两个用于图形的包和一个用于蛇的包。 蛇运动平稳,一切正常。但我需要用键盘控制蛇。这是主要程序:

with Graphics; use Graphics;
with Graphics.Snake; use Graphics.Snake;

procedure Run_Snake is
   B : Buffer (1 .. 24, 1 .. 80);
   S : Snake_Type (1 .. 5) := ((10, 10),
                               (10, 11),
                               (10, 12),
                               (11, 12),
                               (12, 12));
   D : Duration := 0.07;
begin

  loop
      Empty (B);
      Draw_Rect (B, (1, 1), Width  => 80,
                 Height            => 24);
      Draw (B, S);
      Update (B);



      Move (S, 0, -1);
      delay D;

   end loop;

end Run_Snake;

在这行代码中我控制了蛇头旋转:

Move (S, x, y);  

其中x是x值,左边是-1,右边是1 其中y是y值,它可以是-1表示向下,1表示向上;

无论如何,如何在不停止移动蛇的情况下阅读输入? 感谢

2 个答案:

答案 0 :(得分:4)

您可能希望使用多任务系统来克服您的问题。

procedure Snake_Game is

   task Run_Snake is
      entry Input_Received (S : Snake_Type; x : Integer; y : Integer);
   end Run_Snake;

   task body Run_Snake is
      D : constant Duration := 0.07;
      B : Buffer (1 .. 24, 1 .. 80);
   begin
      loop
         select
            accept Input_Received (S : Snake_Type; x : Integer; y : Integer) do
               Move (S, x, y);
            end;
         or
            delay D;
            Empty (B);
            Draw_Rect (B, (1, 1), Width => 80, Height => 24);
            Draw (B, S);
            Update (B);
         end select;
      end loop;
   end Run_Snake;

   S : Snake_Type (1 .. 5) := ((10, 10),
                              (10, 11),
                              (10, 12),
                              (11, 12),
                              (12, 12));

begin
   loop
      Do_Whatever_You_Want_To_Get (x, y)
      Run_Snake.Input_Received(S, x, y);
   end loop;
end Snake_Game;

在这样的系统中,您将绘图过程放在单独的任务中。在“select”行,任务等待对Input_Received()的调用。如果在持续时间D之后没有调用此条目,则任务将执行所有绘图函数,并且循环重新开始。

希望它可以提供帮助。 欢呼声。

答案 1 :(得分:2)

解决此类问题有几种基本方法。

第一种是使用某种检查输入的非阻塞调用,但是立即返回它是否找到任何输入。正如Simon Wright在评论中提到的,Ada提供了这样一个电话:Get_Immediate。这个例程的一点点就是(当我最后检查时)大多数编译器以一种方式实现它,这仍然需要用户在输入可用于该例程之前点击enter键。大多数操作系统也会对此类活动进行系统调用(没有令人烦恼的输入键缺点),但阻塞通常是他们的首选行为,因此设置非阻塞输入通常很困难或晦涩。

我不知道你的Graphics包中有什么内容,但是你可能想看看它是否拥有这样一个电话。我猜这是一个学校编程任务,这是一个用于此任务的包。如果是这样的话,那里可能有一些设施,否则你的教练不会以这种方式描绘你的游戏。

另一种方法是使用不同的控制线程来读取用户输入。这样你就可以在一个线程中使用操作系统喜欢的阻塞调用,让你的游戏的其余部分快乐地在另一个游戏中快速消失。 Ada用任务实现了这一点(如tvuillemin的回答所示)。这里的问题是这两个任务之间的任何交互(例如:将输入传递给游戏任务)必须正确同步。此外,两个任务使用的任何包或设施必须是任务安全的。对于Ada软件包,只要您不尝试共享文件对象或其他内容,就可以非常安全。但对于第三方软件包(如Graphics?),通常最好选择一个任务来“拥有”该软件包。

大多数窗口系统以极其复杂的方式解决了这个问题。他们实现了自己的“主循环”,它应该接管你的控制线程,它将负责平凡的职责,如刷新窗口的内容和轮询输入。如果你想做一些自定义的事情(例如:定期更新游戏状态),你必须把它放在例程中并将其注册为“回调”。