大多数游戏不会等待事件。它们会在必要时轮询输入设备并相应地行动。事实上,如果你看一下XNA,你会发现有一个Keyboard.GetState()方法(或Gamepad.GetState()),你可以在更新过程中调用它,并根据结果更新你的游戏逻辑。当使用Windows.Forms时,没有现成的方法来做到这一点,但是你可以使用P/Invoke GetKeyBoardState()函数来利用它。好处是,你可以同时轮询多个按键,并因此对多个按键按下作出反应。这里有一个我在网上找到的简单类来帮助实现这个:
http://sanity-free.org/17/obtaining_key_state_info_in_dotnet_csharp_getkeystate_implementation.html
为了演示,我编写了一个简单的Windows应用程序,基本上根据键盘输入移动球。它使用我提供的类来轮询键盘状态。如果你同时按住两个键,你会注意到它会对角线移动。
首先是Ball.cs:
public class Ball
{
private Brush brush;
public float X { get; set; }
public float Y { get; set; }
public float DX { get; set; }
public float DY { get; set; }
public Color Color { get; set; }
public float Size { get; set; }
public void Draw(Graphics g)
{
if (this.brush == null)
{
this.brush = new SolidBrush(this.Color);
}
g.FillEllipse(this.brush, X, Y, Size, Size);
}
public void MoveRight()
{
this.X += DX;
}
public void MoveLeft()
{
this.X -= this.DX;
}
public void MoveUp()
{
this.Y -= this.DY;
}
public void MoveDown()
{
this.Y += this.DY;
}
}
这里需要翻译的内容是:
真的没有什么花哨的东西......
然后这里是Form1代码:
public partial class Form1 : Form
{
private Ball ball;
private Timer timer;
public Form1()
{
InitializeComponent();
this.ball = new Ball
{
X = 10f,
Y = 10f,
DX = 2f,
DY = 2f,
Color = Color.Red,
Size = 10f
};
this.timer = new Timer();
timer.Interval = 20;
timer.Tick += new EventHandler(timer_Tick);
timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
var left = KeyboardInfo.GetKeyState(Keys.Left);
var right = KeyboardInfo.GetKeyState(Keys.Right);
var up = KeyboardInfo.GetKeyState(Keys.Up);
var down = KeyboardInfo.GetKeyState(Keys.Down);
if (left.IsPressed)
{
ball.MoveLeft();
this.Invalidate();
}
if (right.IsPressed)
{
ball.MoveRight();
this.Invalidate();
}
if (up.IsPressed)
{
ball.MoveUp();
this.Invalidate();
}
if (down.IsPressed)
{
ball.MoveDown();
this.Invalidate();
}
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (this.ball != null)
{
this.ball.Draw(e.Graphics);
}
}
}
一个简单的小应用程序。只创建一个球和一个计时器。每20毫秒,它检查键盘状态,如果按下了某个键,它就移动它并无效化,以便可以重新绘制。