1

特定の条件が満たされるまで、DrawableGameComponentクラスのメソッドが返されないようにしたい

このクラスがあるとします (クラスのスニペットDrawableGameComponent):

public override void Update(GameTime gameTime)
        {
            if (moving && pixFromLastMove <= distanceToMove)
            {
                position += velocity;
                pixFromLastMove += velocity.Length();
            }
            else
            {
                moving = false;
            }
            if (rotating)
            {
                rotation += 0.1f;
                var cRotation = MathHelper.Clamp(rotation, -MathHelper.PiOver2, angleBeforeRotation + degToRotate);
                if (cRotation != rotation)
                {
                    rotation = cRotation;
                    angleBeforeRotation = rotation;
                    rotating = false;
                }
            }
            base.Update(gameTime);
        }

public void Ahead(int pix)
        {
            moving = true;
            distanceToMove = pix;
            pixFromLastMove = 0;
            velocity = new Vector2((float) Math.Cos(rotation), (float) Math.Sin(rotation))*5.0f;

            //DO NOT RETURN UNTIL THIS ROBOT HAS MOVED TO ITS DESTINATION
            }

public void TurnLeft(int deg)
        {
            rotating = true;
            degToRotate = MathHelper.ToRadians(deg);
            angleBeforeRotation = rotation;

            //DO NOT RETURN UNTIL THIS ROBOT HAS BEEN FULLY ROTATED
        }

このクラスはDraw()メイン スレッドで描画 ( ) されています (この drawablegamecomponent は別のスレッドで実行されているため)。また、メイン スレッドには、順番に実行したいコマンドのリストがあります。Aheadメソッドが に値を割り当てた直後に戻るとvelocity、メソッドはほぼ同時に実行され、すべてのアニメーションが同時に実行されます。

では、特定の条件が満たされる前にコマンド ( など)Aheadであるメソッドが返されないようにするにはどうすればよいと思いますか?TurnLeft

4

4 に答える 4

3

Update() メソッド用にある種のステート マシンを作成する必要があります。例えば

public override void Update() { 
    if (movingRobot) {
        OnlyUpdateRobotPosition();
    }
    else {
        DoStuffPerhapsIncludingStartingRobotMove();
    }
}

または、質問がありませんか?

于 2009-03-16T22:41:03.717 に答える
2

ああ、2つの言葉:協調マルチタスク。ファイバー(または選択した協調マルチタスクビルディングブロック)の喜びで、 ( C#でファイバーを有効にするためにこのようないくつかの基礎を築いた後)次のようなことができます:

public void Ahead(int pix)
{
  moving = true;
  distanceToMove = pix;
  pixFromLastMove = 0;
  velocity = new Vector2((float) Math.Cos(rotation), (float) Math.Sin(rotation))*5.0f;

  //DO NOT RETURN UNTIL THIS ROBOT HAS MOVED TO ITS DESTINATION
  while(!HasReachedDestination())
  {
    Yield(); // let another fiber run
  }
}

ただし、これを機能させるには、単純なラウンドロビンスケジューラを実装する必要があります。C#は実際には私のボートではありませんが、私が行うことは、C#をシンプルに保ち、Cooperative(または何か)と呼ぶある種の基本クラスを作成することです。このクラスには、作成されたすべてのファイバーの静的リストと、静的メソッドCreate()およびYield()が含まれます。Create()は新しいファイバー(またはその他)を作成し、Yield()はSwitchToFiber()の呼び出しを含むファイバーの世界で、実行する次のファイバー(ラウンドロビンスタイル)をスケジュールするだけです。また、ファイバーの実行を開始する場所であるStart()(またはその他)と呼ばれる仮想メソッドもあります。

それをより派手なものにするために、後で実行可能または実行不可能のいずれかである(つまり、何かが起こるのを待つ)ファイバーの別々のリストを保持することができます。その場合、Aheadのループを次のように簡略化できる可能性があります。

WaitFor(HasReachedDestination);

しかし、最初に協調マルチタスクの概念で足を濡らすことをお勧めします。

最後に、ファイバーを作成する必要があることについていくつか考えます。通常、メインの更新ループは1つのファイバーであり、すべてのオブジェクトを更新および描画してから、Yield()を呼び出します。すべてのゲームオブジェクトもファイバーになります(ゲームオブジェクトがたくさんある場合、これは実行できない可能性があります)。ゲームオブジェクトに対して、次のようなことを行います。

public override Start()
{
  do
  {
    if(EnemyToTheLeft())
    {
      TurnLeft(90); // this will call Yield and return when we have finished turning
      Shoot();
    }
    Yield(); // always yield
  }while(!dead);
}
于 2009-03-17T23:15:06.023 に答える
1

あなたのデザインはやや奇妙だと思いますが、目的を達成するための最良の方法は、EventWaitHandleを使用して別のスレッドから通知することです。

クラスに待機ハンドルのインスタンスがあるとします

メソッドで waithadle.WaitOne() を呼び出し、条件が満たされたときに waithandle.Set() を使用して別のスレッドからイベントを通知できます。その時点で、メソッドは待機から再開します。

于 2009-03-16T22:25:53.910 に答える