Как приостановить код, чтобы он мог завершить другой код, а затем возобновить - PullRequest
1 голос
/ 05 ноября 2019

Я хочу сделать ИИ и сделать его как игрок. Когда он не знает, что делать, он будет делать случайный ход, и я назвал это rndPlay();. Он будет случайным образом выбирать место для щелчка. Можно выбирать из 9 локаций. press1();, press2(); и т. Д. Я повторяю, пока не нажмете две кнопки подряд. Теперь вот проблема

Когда цикл for выполняется, я говорю, чтобы он нажал на 850, 400 там есть кнопка, так что давайте назовем это btn1, и это выполняет, например, btnPressed1();, я вижумышь перемещается туда, и она щелкает, но не выполняет btnPressed1();. Вместо этого он нажимает на следующее случайное место и продолжает повторять 10000 раз, потому что он не сделал успешное движение (он должен нажать две вещи в определенном порядке). Затем, когда он выходит из цикла for, он выполняет btnPressed1();. Я не хочу, чтобы он делал это после того, как он остановился, потому что на каждой кнопке находится другая кнопка, и назовем ее btnMove1 с номером, соответствующим кнопке под ней. например, он нажал кнопки 1, 1 и 8, он должен после нажатия btn1 показать btnMove1, но поскольку он не выполняется мгновенно, он снова нажимает btn1 (не btnMove1), а затем btn8, затем, когдаон завершает, выполняет btnPressed1();, затем btnPressed1(); снова и, наконец, btnPressed8(); Как мне заставить его выполнить код, который он нажал, прежде чем нажать следующую вещь?

Я пытался использовать Thread.Sleep(100), чтобы сделать этоостановить, но он просто ждет и не выполняет кнопку, которую он только что нажал. Я также создал свой цикл for с оператором if, потому что подумал, что это может быть цикл for, который останавливает выполнение ввода.

Код XAML:

<button x:Name="btn1" Click="btnPressed1"/>
<button x:Name="btnMove1" Click="btnMove1" Visibility="Hidden"/>
<button x:Name="btn2" Click="btnPressed2"/>
<button x:Name="btnMove2" Click="btnPressedMove2" Visibility="Hidden"/>
<button x:Name="btn3" Click="btnPressed3"/>
<button x:Name="btnMove3" Click="btnMove3" Visibility="Hidden"/>
//etc

Код C #:

        private void btnPressed1(object sender, RoutedEventArgs e)
        {
            btnMove1.Visibility = Visibility.Visible
        }

        private void btnPressed2(object sender, RoutedEventArgs e)
        {
            btnMove2.Visibility = Visibility.Visible
        }

        //etc

        private void btnPressedMove1(object sender, RoutedEventArgs e)
        {
          //some code
        }

        private void btnPressedMove2(object sender, RoutedEventArgs e)
        {
          //some code
        }

        //etc

        private void MoveTo(int x, int y)
        {
            mouse_event(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE, x, y, 0, 0);
        }

[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint cButtons, uint dwExtraInfo);
        //Mouse actions
        private const int MOUSEEVENTF_LEFTDOWN = 0x02;
        private const int MOUSEEVENTF_LEFTUP = 0x04;
        private const int MOUSEEVENTF_RIGHTDOWN = 0x08;
        private const int MOUSEEVENTF_RIGHTUP = 0x10;

        [DllImport("user32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private extern bool SetCursorPos(uint X, uint Y);
        private void LeftMouseClick(uint X, uint Y)
        {
            SetCursorPos(X, Y);
            //Call the imported function with the cursor's current 
            mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, X, Y, 0, 0);
            Thread.Sleep(1000);
            return;
        }

        private void press1()
        {
            LeftMouseClick(28000, 25000);
            last2Moves("1");
        }
        private void press2()
        {
            LeftMouseClick(33000, 25000);
            last2Moves("2");
        }
        //etc

        private void rndPlay()
        {
            for (int r = 0; moveSucces != true && r < 10000; r++)
            {

                Random rndP = new Random();
                int rndPress = rndP.Next(1, 10);
                if (rndPress == 1)
                {
                    press1();
                }
                if (rndPress == 2)
                {
                    press2();
                }
                    //etc
             }
         }

Я хочу, чтобы он сначала выполнил btnPressed1(); перед нажатием следующей кнопки, но он сохраняет то, что нажимает, до завершения кода. Как мне заставить его закончить код, прежде чем он нажал следующую вещь?

1 Ответ

1 голос
/ 05 ноября 2019

Приложения, имеющие графический интерфейс, управляются событиями. Все действия пользователя (и некоторые другие события) публикуются в очереди сообщений и обрабатываются по одному в цикле сообщений. Вы можете прочитать это для некоторой справочной информации: https://docs.microsoft.com/en-us/windows/win32/winmsg/about-messages-and-message-queues

Если вы пишете код, подобный циклу for, выполнение которого занимает много времени, то вы блокируете этот цикл сообщений от обработки любых событий.

Один из способов избежать блокировки цикла сообщений - переписать rndPlay как асинхронный метод:

    private async Task rndPlay()
    {
        for (int r = 0; moveSucces != true && r < 10000; r++)
        {

            Random rndP = new Random();
            int rndPress = rndP.Next(1, 10);
            if (rndPress == 1)
            {
                press1();
            }
            if (rndPress == 2)
            {
                press2();
            }
            //etc

            await Task.Delay(1000);
         }
     }

Это приводит к приостановке выполнения rndPlay в каждом await и публикациипродолжение выполнения метода в очереди сообщений после задержки 1000 мс. Таким образом, другие события в очереди сообщений получают возможность обработки в цикле сообщений.

Обратите внимание, что в вашем примере кода не отображается вызывающая сторона rndPlay. Возможно, вам также придется внести некоторые изменения.

...