Cuộc Application.Run
gọi điều khiển máy bơm thông báo Windows của bạn, cuối cùng là thứ cung cấp năng lượng cho tất cả các sự kiện bạn có thể kết nối trên Form
lớp (và các sự kiện khác). Để tạo một vòng lặp trò chơi trong hệ sinh thái này, bạn muốn lắng nghe khi bơm thông báo của ứng dụng trống và trong khi nó vẫn trống, hãy thực hiện "các trạng thái nhập quy trình, cập nhật logic trò chơi, kết xuất các cảnh" của vòng lặp trò chơi nguyên mẫu .
Sự Application.Idle
kiện này kích hoạt một lần mỗi khi hàng đợi tin nhắn của ứng dụng bị xóa và ứng dụng đang chuyển sang trạng thái không hoạt động. Bạn có thể nối sự kiện trong hàm tạo của biểu mẫu chính của bạn:
class MainForm : Form {
public MainForm () {
Application.Idle += HandleApplicationIdle;
}
void HandleApplicationIdle (object sender, EventArgs e) {
//TODO: Implement me.
}
}
Tiếp theo, bạn cần có khả năng xác định xem ứng dụng có còn không. Các Idle
sự kiện chỉ bắn một lần, khi ứng dụng trở nên nhàn rỗi. Nó không bị bắn lần nữa cho đến khi một tin nhắn được đưa vào hàng đợi và sau đó hàng đợi lại xuất hiện. Windows Forms không đưa ra một phương thức để truy vấn trạng thái của hàng đợi tin nhắn, nhưng bạn có thể sử dụng các dịch vụ gọi nền tảng để ủy quyền truy vấn cho hàm Win32 gốc có thể trả lời câu hỏi đó . Khai báo nhập khẩu PeekMessage
và các loại hỗ trợ của nó trông giống như:
[StructLayout(LayoutKind.Sequential)]
public struct NativeMessage
{
public IntPtr Handle;
public uint Message;
public IntPtr WParameter;
public IntPtr LParameter;
public uint Time;
public Point Location;
}
[DllImport("user32.dll")]
public static extern int PeekMessage(out NativeMessage message, IntPtr window, uint filterMin, uint filterMax, uint remove);
PeekMessage
về cơ bản cho phép bạn xem tin nhắn tiếp theo trong hàng đợi; nó trả về true nếu tồn tại, sai khác. Đối với mục đích của vấn đề này, không có tham số nào đặc biệt phù hợp: chỉ có giá trị trả về mới là vấn đề. Điều này cho phép bạn viết một hàm cho bạn biết nếu ứng dụng vẫn ở chế độ chờ (nghĩa là vẫn không có tin nhắn nào trong hàng đợi):
bool IsApplicationIdle () {
NativeMessage result;
return PeekMessage(out result, IntPtr.Zero, (uint)0, (uint)0, (uint)0) == 0;
}
Bây giờ bạn có mọi thứ bạn cần để viết vòng lặp trò chơi hoàn chỉnh của mình:
class MainForm : Form {
public MainForm () {
Application.Idle += HandleApplicationIdle;
}
void HandleApplicationIdle (object sender, EventArgs e) {
while(IsApplicationIdle()) {
Update();
Render();
}
}
void Update () {
// ...
}
void Render () {
// ...
}
[StructLayout(LayoutKind.Sequential)]
public struct NativeMessage
{
public IntPtr Handle;
public uint Message;
public IntPtr WParameter;
public IntPtr LParameter;
public uint Time;
public Point Location;
}
[DllImport("user32.dll")]
public static extern int PeekMessage(out NativeMessage message, IntPtr window, uint filterMin, uint filterMax, uint remove);
}
Hơn nữa, cách tiếp cận này khớp càng gần càng tốt (với sự phụ thuộc tối thiểu vào P / Gọi) với vòng lặp trò chơi Windows gốc chính tắc , trông giống như:
while (!done) {
if (PeekMessage(&message, window, 0, 0, PM_REMOVE)){
TranslateMessage(&message);
DispatchMessage(&message);
}
else {
Update();
Render();
}
}