C# 在我的游戏中使用什么来代替Application.DoEvents?
我正在用C#WinForms创建一个太空入侵者游戏,在对玩家大炮的移动进行编码时,我创建了以下事件处理程序:C# 在我的游戏中使用什么来代替Application.DoEvents?,c#,winforms,C#,Winforms,我正在用C#WinForms创建一个太空入侵者游戏,在对玩家大炮的移动进行编码时,我创建了以下事件处理程序: private void Game_Screen_KeyDown(object sender, KeyEventArgs e) { for (int i = 0; i < 500; i++) { if (e.KeyCode == Keys.Left) { cannonBox.Location = new Po
private void Game_Screen_KeyDown(object sender, KeyEventArgs e)
{
for (int i = 0; i < 500; i++)
{
if (e.KeyCode == Keys.Left)
{
cannonBox.Location = new Point(cannonBox.Left - 2, cannonBox.Top); //Changes location of cannonBox to a new location to the left
Application.DoEvents();
System.Threading.Thread.Sleep(10); //Delays the movement by couple milliseconds to stop instant movement
}
if (e.KeyCode == Keys.Right)
{
cannonBox.Location = new Point(cannonBox.Left + 2, cannonBox.Top); //Changes location of cannonBox to a new location to the right
Application.DoEvents();
System.Threading.Thread.Sleep(10); //Delays the movement by couple milliseconds to stop instant movement
}
if (e.KeyCode == Keys.Up)
{
createLaser(); //Calls the method whenever Up arrow key is pressed
}
}
}
private void Game\u Screen\u KeyDown(对象发送者,KeyEventArgs e)
{
对于(int i=0;i<500;i++)
{
if(e.KeyCode==Keys.Left)
{
cannonBox.Location=新点(cannonBox.Left-2,cannonBox.Top);//将cannonBox的位置更改为左侧的新位置
Application.DoEvents();
System.Threading.Thread.Sleep(10);//将移动延迟几毫秒以停止即时移动
}
if(e.KeyCode==Keys.Right)
{
cannonBox.Location=新点(cannonBox.Left+2,cannonBox.Top);//将cannonBox的位置更改为右侧的新位置
Application.DoEvents();
System.Threading.Thread.Sleep(10);//将移动延迟几毫秒以停止即时移动
}
if(e.KeyCode==Keys.Up)
{
createLaser();//每当按下向上箭头键时调用该方法
}
}
}
但是在不同的网站上,关于这在C#中是如何不可靠的,我将确保不会从上面使用它。在这个实例中,还有哪些替代方法可以代替Application.DoEvents使用?我建议将事件处理程序
设置为异步,并使用wait Task.Delay()
而不是Thread.Sleep()
:
private async void Game\u Screen\u KeyDown(对象发送方,KeyEventArgs e)
{
对于(int i=0;i<500;i++)
{
if(e.KeyCode==Keys.Left)
{
cannonBox.Location=新点(cannonBox.Left-2,cannonBox.Top);//将cannonBox的位置更改为左侧的新位置
wait Task.Delay(10);//将移动延迟几毫秒以停止即时移动
}
if(e.KeyCode==Keys.Right)
{
cannonBox.Location=新点(cannonBox.Left+2,cannonBox.Top);//将cannonBox的位置更改为右侧的新位置
wait Task.Delay(10);//将移动延迟几毫秒以停止即时移动
}
if(e.KeyCode==Keys.Up)
{
createLaser();//每当按下向上箭头键时调用该方法
}
}
}
这样,控制流将返回给调用者,您的UI线程有时间处理其他事件(因此不需要Application.DoEvents()
)。然后在(大约)10毫秒之后,返回控件并继续执行该处理程序
可能需要进行更多的微调,因为现在当然可以在方法尚未完成时点击更多的键。如何处理取决于周围环境。您可以声明一个标志,表示当前执行并拒绝进一步的方法条目(此处不需要线程安全性,因为这一切都是在UI线程上顺序发生的)。
或者,不要拒绝重新进入,而是将击键排队,并在另一个事件中处理它们,例如“空闲”事件(如注释中建议的Lasse)
请注意,事件处理程序是很少使用async
而不返回任务的情况之一。Application.DoEvents()中断方法的执行,UI线程将处理其事件(包括重新绘制UI)。根据我的经验,在正确的地方使用它没有什么错
使用“异步”模式(如RenéVogt所建议的)是制作Responsive UI的最佳实践
不过。你必须问问自己,你是否需要一个检查500次的循环,如果向下键是左键、右键还是向上键。特别是当这个循环似乎是由一个键关闭事件触发的
如果您在main中创建一个“while(true)”循环并从那里调用Application.DoEvents,可能会更容易
或者,您对按键按下事件做出反应,并一次执行操作。=>按左->向左移动一个->再次按左->再向左移动一个。。。等等
使用一个计时器,该计时器每20毫秒调用一次游戏处理
在KeyDown
/keydup
事件中,只需更改游戏处理所使用的当前状态
示例代码:
[Flags]
public enum ActionState
{
MoveLeft,
MeveRight,
FireLaser,
}
// stores the current state
private ActionState _actionState;
// set action state
private void Game_Screen_KeyDown(object sender, KeyEventArgs e)
{
switch ( e.KeyCode )
{
case Keys.Left:
_actionState |= ActionState.MoveLeft;
break;
case Keys.Right:
_actionState |= ActionState.MoveRight;
break;
case Keys.Up:
_actionState |= ActionState.FireLaser;
break;
default:
break;
}
}
// remove action state
private void Game_Screen_KeyUp(object sender, KeyEventArgs e)
{
switch ( e.KeyCode )
{
case Keys.Left:
_actionState &= ~ActionState.MoveLeft;
break;
case Keys.Right:
_actionState &= ~ActionState.MoveRight;
break;
case Keys.Up:
_actionState &= ~ActionState.FireLaser;
break;
default:
break;
}
}
// called from a timer every 20 milliseconds
private void Game_Screen_LoopTimer_Tick(object sender, EventArgs e)
{
if ( _actionState.HasFlag( ActionState.MoveLeft ) && !_actionState.HasFlag( ActionState.MoveRight ) )
{
cannonBox.Location = new Point(cannonBox.Left - 2, cannonBox.Top); //Changes location of cannonBox to a new location to the left
}
if ( _actionState.HasFlag( ActionState.MoveRight ) && !_actionState.HasFlag( ActionState.MoveLeft ) )
{
cannonBox.Location = new Point(cannonBox.Left + 2, cannonBox.Top); //Changes location of cannonBox to a new location to the right
}
if ( _actionState.HasFlag( ActionState.FireLaser ) )
{
createLaser(); //Calls the method whenever Up arrow key is pressed
}
}
谢谢你的改进!它的运行比以前平稳得多,没有应用程序时也一样。DoEvents:)请注意,如果在循环完成之前按了左键(或者它被注册为按下,autorepeat?),则实际上会同时运行两个这样的循环。500乘以10毫秒等于5秒,这已经足够让这样的事情发生了。你可以简单地记录下玩家想要向左移动,并将实际移动代码移动到其他事件,比如“空闲”之类的事件,然后记录玩家不再想在向上键时向左移动。游戏循环是少数几个使用Application.DoEvents()从根本上说没有错误的例子之一。但它属于循环,而不属于事件处理程序。谷歌“windows窗体游戏循环”查找示例代码..“主循环”-主循环是什么?你是说?或多或少是的。主要方法是C#应用程序的入口点。
[Flags]
public enum ActionState
{
MoveLeft,
MeveRight,
FireLaser,
}
// stores the current state
private ActionState _actionState;
// set action state
private void Game_Screen_KeyDown(object sender, KeyEventArgs e)
{
switch ( e.KeyCode )
{
case Keys.Left:
_actionState |= ActionState.MoveLeft;
break;
case Keys.Right:
_actionState |= ActionState.MoveRight;
break;
case Keys.Up:
_actionState |= ActionState.FireLaser;
break;
default:
break;
}
}
// remove action state
private void Game_Screen_KeyUp(object sender, KeyEventArgs e)
{
switch ( e.KeyCode )
{
case Keys.Left:
_actionState &= ~ActionState.MoveLeft;
break;
case Keys.Right:
_actionState &= ~ActionState.MoveRight;
break;
case Keys.Up:
_actionState &= ~ActionState.FireLaser;
break;
default:
break;
}
}
// called from a timer every 20 milliseconds
private void Game_Screen_LoopTimer_Tick(object sender, EventArgs e)
{
if ( _actionState.HasFlag( ActionState.MoveLeft ) && !_actionState.HasFlag( ActionState.MoveRight ) )
{
cannonBox.Location = new Point(cannonBox.Left - 2, cannonBox.Top); //Changes location of cannonBox to a new location to the left
}
if ( _actionState.HasFlag( ActionState.MoveRight ) && !_actionState.HasFlag( ActionState.MoveLeft ) )
{
cannonBox.Location = new Point(cannonBox.Left + 2, cannonBox.Top); //Changes location of cannonBox to a new location to the right
}
if ( _actionState.HasFlag( ActionState.FireLaser ) )
{
createLaser(); //Calls the method whenever Up arrow key is pressed
}
}