2

これは学校の課題です。ヘビのゲームを作成します。そこで、グラフィック用とスネーク用の 2 つのパッケージを作成しました。ヘビはスムーズに動き、すべてが機能します。しかし、ヘビをキーボードで制御する必要があります。これが主な手順です。

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 です。

とにかく、ヘビの動きを一時停止せずに入力を読み取るにはどうすればよいですか? ありがとう

4

2 に答える 2

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 の後に呼び出されない場合、タスクはすべての描画関数を実行し、ループが新たに開始されます。

それが役立つことを願っています。乾杯。

于 2012-11-28T09:38:05.090 に答える
2

この種の問題を解決するには、いくつかの基本的なアプローチがあります。

1 つ目は、入力をチェックするノンブロッキング呼び出しを使用することですが、入力があるかどうかはすぐに返されます。Simon Wright がコメントで述べたように、Ada は次のような呼び出しを提供します: Get_Immediate。このルーチンのちょっとした欠点は、(最後に確認したとき)ほとんどのコンパイラが、enterそのルーチンで入力を使用できるようになる前にユーザーがキーを押す必要がある方法でそれを実装していることです。ほとんどの OS には、そのようなアクティビティに対するシステム コールもありますが (面倒なエンター キーの欠点はありません)、通常はブロックが優先される動作であるため、非ブロック入力の設定はしばしば困難または難解です。

あなたのそのパッケージに何が入っているかはわかりませんが、そのGraphicsような呼び出しがあるかどうかを確認するためにそれを調べたいと思うかもしれません. これは学校のプログラミング課題であり、この課題で使用するために構築されたパッケージであると推測しています。もしそうなら、おそらくそのための何らかの機能がそこにあるでしょう。さもなければ、あなたのインストラクターはあなたのゲームがそのように動作することを想像していませんでした.

もう 1 つの方法は、ユーザー入力の読み取りに別の制御スレッドを使用することです。そうすれば、OS が好むブロッキング コールを 1 つのスレッドで使用し、ゲームの残りの部分を他のスレッドで楽しく処理することができます。Ada はこれをタスクで実装します (tbuillemin の回答に示されているように)。ここでの問題は、これら 2 つのタスク間の相互作用 (例: 入力をゲーム タスクに渡す) を適切に同期する必要があることです。また、両方のタスクで使用されるパッケージまたは機能は、タスクセーフでなければなりません。Ada パッケージの場合、ファイル オブジェクトなどを共有しようとしない限り、かなり安全です。しかし、サードパーティのパッケージ ( Graphics? など) の場合は、通常、そのパッケージを「所有」するタスクを 1 つ選択するのが最善です。

ほとんどのウィンドウ システムは、信じられないほど複雑な方法でこの問題を解決します。それらは、制御のスレッドを引き継ぐことになっている独自の「メインループ」を実装し、ウィンドウの内容の更新や入力のポーリングなどの日常的な作業を処理します。何かカスタムを行いたい場合 (例: ゲームの状態を定期的に更新する)、それをルーチンに入れて「コールバック」として登録する必要があります。

于 2012-11-28T15:01:50.080 に答える