Подтвердить что ты не робот

Одновременное использование методов

У меня есть класс Dog с методом Run, который должен перемещать изображения по экрану:

public bool Run()
{
    Point p = PictureBoxDog.Location;

    while(p.X < 530)
    {
        int movement = Randomizer.Next(0, 3);
        p.X += movement;
        PictureBoxDog.Location = p;
    }

    if (Location == 4) //Incomplete section.
        return true;
    else
        return false;
}

Этот метод вызывается из события нажатия кнопки, в котором создаются 4 объекта собаки, и каждый объект вызывает метод Run:

private void button1_Click(object sender, EventArgs e)
{
    Dog dog1 = new Dog(pictureDog1);
    Dog dog2 = new Dog(pictureDog2);
    Dog dog3 = new Dog(pictureDog3);
    Dog dog4 = new Dog(pictureDog4);

    dog1.Run();
    dog2.Run();
    dog3.Run();
    dog4.Run();
}

Проблема заключается в том, что каждый метод выполняется один за другим, а не одновременно. Я хочу, чтобы каждый метод запускался одновременно. Если я удалю оператор while, тогда все методы выполняются в одно и то же время, но с циклом while они выполняются один за другим. Любые предложения по устранению этой проблемы очень ценятся. Выполнить метод без цикла while:

public bool Run() //Dog1.Run()
{
    Point p = PictureBoxDog.Location;

    int movement = Randomizer.Next(0, 30);
    //Location += movement;

    p.X += movement;
    PictureBoxDog.Location = p;

    if (Location == 4) //Incomplete code.
    return true;
    else
    return false;
}
4b9b3361

Ответ 1

Анимация и WinForms, как правило, не являются простыми. Обычно программисты настраивают игровой цикл. Игровой цикл выполняет три функции: выбор пользовательского ввода, обновление новой позиции спрайтов, а затем рисование спрайтов на экране.

using System.Threading;

public partial class Form1
{ 
   private Timer _timer;
   private Dog _dog1, _dog2, _dog3, _dog4;

   public void InitializeComponent()
   {
      SetupDogs();

      // Every quarter of a second, run the function GameLoop
      _timer = new Timer(GameLoop, null, 
        TimeSpan.FromSeconds(0.25),
        TimeSpan.FromSeconds(0.25));
   }

   private void SetupDogs()
   {
      _dog1 = new Dog(PictureBoxDog1);
      _dog2 = new Dog(PictureBoxDog2);
      _dog3 = new Dog(PictureBoxDog3);
      _dog4 = new Dog(PictureBoxDog4);

   }

   public void GameLoop(object state)
   {
       GetUserInput();
       Update();
       Draw();
   }

   public void GetUserInput()
   {
     // You don't need this now. But if you need to
     // process user input later, you can do it here.
     //
     // e.g. if Last key 
     //   pressed  was arrow-left or 
     //   arrow-right etc.
   }

   public void Update()
   {
     _dog1.Update();
     _dog2.Update();
     _dog3.Update();
     _dog4.Update();
   }

   public void Draw()
   {
      // Draw on the main UI thread
      Dispatcher.BeginInvoke(() => 
      {
         _dog1.Draw();
         _dog2.Draw();
         _dog3.Draw();
         _dog4.Draw();
      });
   }

}

Затем ваш класс Dog выглядит так. Он должен Update его местоположение каждый раз, когда таймер тикает, а затем нарисовать его положение:

public class Dog
{

  bool _isRunning = true;

  Point Location { get; set; }

  Point NextLocation { get; set; }

  PictureBox PictureBoxDog { get; set; }

  public Dog(PictureBox pictureBox) 
  {
     PictureBoxDog = pictureBox;

     Location = GetRandomLocation();

     NextLocation = GetRandomLocation();
  }

  private Point GetRandomLocation()
  {
     var random = new Random();
     return new Point(random.Next(800), random.Next(800));
  }

  public void Update()
  {
    // Calculates the new coordinates for a dog

    // The dog starts from a random position, and is 
    // given a new random position to run towards.

    // If the dog has arrived at the new random position, then
    // give the dog a new random position to run to again
    if (NextLocation.X == Location.X && NextLocation.Y == Location.Y)
    {
      NextLocation = GetRandomLocation();
    }

    if (_isRunning)
    {
       // Move the dog closer to its destination
       // dx and dy can be -1, 0, or 1
       var dx = Math.Sign(NextLocation.X - Location.X);
       var dy = Math.Sign(NextLocation.Y - Location.Y);

       Location = new Point(Location.X + dx, Location.Y + dy);
    }
  }

  public void Draw()
  {
     PictureBoxDog.Location = Location;
  }
}

Ответ 2

Попробуйте это

Dispatcher.BeginInvoke((Action) (() =>
{
     dog1.Run();
}));
Dispatcher.BeginInvoke((Action) (() =>
{
     dog2.Run();
}));
Dispatcher.BeginInvoke((Action) (() =>
{
     dog3.Run();
}));
Dispatcher.BeginInvoke((Action) (() =>
{
     dog4.Run();
}));

и для цикла While также используйте этот

Dispatcher.BeginInvoke((Action) (() =>
{
    while(p.X < 530)
    {
        int movement = Randomizer.Next(0, 3);
        p.X += movement;
        PictureBoxDog.Location = p;
    }
}));

BeginInvoke является асинхронным; поэтому управление немедленно возвращается к вызывающему объекту после его вызова. BeginInvoke возвращает объект DispatcherOperation, который может использоваться для взаимодействия с делегатом, когда делегат находится в очереди событий. Объект DispatcherOperation, возвращаемый BeginInvoke, может использоваться несколькими способами для взаимодействия с указанным делегатом

Ответ 3

Почему бы не попробовать это?

Task.Factory.StartNew( () => Parallel.ForEach<Dog>(Dogs, dog=> dog.run()));

Чтобы правильно использовать эту инструкцию, вы должны создать список Dog.

 List<Dog> Dogs = new List<Dog>();
        Dogs.Add(dog1);
        Dogs.Add(dog2);
        Dogs.Add(dog3);
        Dogs.Add(dog4);
        Task.Factory.StartNew(() => Parallel.ForEach<Dog>(Dogs, dog => dog.Run()));

Если вам не нравится список:

Task.Factory.StartNew(() => dog1.Run());
Task.Factory.StartNew(() => dog2.Run());
Task.Factory.StartNew(() => dog3.Run());
Task.Factory.StartNew(() => dog4.Run());

Чтобы взаимодействовать с пользовательским интерфейсом из другого потока, вам нужно использовать делегат и вызвать Control.Invoke/BeginInvoke. Вы можете проверить, нужно ли вам вызывать Invoke, используя свойство InvokeRequired. Итак, в вашем случае:

if (PictureBoxDog.InvokeRequired){
PictureBoxDog.Invoke((MethodInvoker)(() => PictureBoxDog.location = p));}