如何暂停代码以便它可以完成其他代码然后继续
How to pause code so it can finish other code and then resume
我想制作一个 AI,让它像一个播放器一样。当它不知道该做什么时,它会随机移动,我称之为 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)
让它停止,但它只是等待并且不执行它刚刚按下的按钮。我还用 if 语句创建了自己的 for 循环,因为我认为它可能是停止执行输入的 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();
但它会保存它按下的内容,直到它完成代码。如何让它在按下下一步之前完成代码?
具有 GUI 的应用程序是事件驱动的。所有用户操作(和一些其他事件)都被发布到消息队列并由消息循环一个接一个地处理。您可以阅读本文以获取一些背景信息:
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);
}
}
这具有在每个 await
暂停执行 rndPlay
的效果,并在 1000 毫秒延迟后将方法执行的继续发布到消息队列。这样,消息队列中的其他事件就有机会被消息循环处理。
请注意,您的示例代码未显示 rndPlay
的调用者。您可能还必须在那里进行一些更改。
我想制作一个 AI,让它像一个播放器一样。当它不知道该做什么时,它会随机移动,我称之为 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)
让它停止,但它只是等待并且不执行它刚刚按下的按钮。我还用 if 语句创建了自己的 for 循环,因为我认为它可能是停止执行输入的 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();
但它会保存它按下的内容,直到它完成代码。如何让它在按下下一步之前完成代码?
具有 GUI 的应用程序是事件驱动的。所有用户操作(和一些其他事件)都被发布到消息队列并由消息循环一个接一个地处理。您可以阅读本文以获取一些背景信息: 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);
}
}
这具有在每个 await
暂停执行 rndPlay
的效果,并在 1000 毫秒延迟后将方法执行的继续发布到消息队列。这样,消息队列中的其他事件就有机会被消息循环处理。
请注意,您的示例代码未显示 rndPlay
的调用者。您可能还必须在那里进行一些更改。