2009-03-25 40 views
6

Mọi khuôn khổ hướng dẫn trò chơi và trò chơi (kể cả khung XNA khá mới) bắt đầu bằng một vòng lặp không bao giờ kết thúc có tương đương với DoEvents() để ngăn hệ điều hành khóa.Vòng lặp trò chơi tốt hơn so với vòng lặp vô tận + khối?

Bắt nguồn từ góc nhìn không dựa trên trò chơi, tôi cảm thấy loại mã này có mùi khá sôi nổi.
Không có lựa chọn thay thế tốt hơn?

--EDIT--
Rất nhiều câu trả lời cho biết mọi chương trình về cơ bản là vòng lặp. Đúng, nhưng tôi cảm thấy vòng lặp nên được thực hiện bởi hệ điều hành của bạn, không phải bởi bạn. Chỉ có hệ điều hành mới có tất cả thông tin cần thiết để phân phối tài nguyên của nó một cách tối ưu. Hay tôi đang thiếu một điểm quan trọng ở đây?

+0

Vâng, bạn đang bỏ lỡ sự khác biệt quan trọng rằng trò chơi không phải là dịch vụ hệ điều hành. – Hejazzman

Trả lời

5

Mỗi ứng dụng Windows có ít cốt lõi của nó một vòng lặp mà trông giống như sau:

BOOL bRet; 

while((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) 
{ 
    if (bRet == -1) 
    { 
     // handle the error and possibly exit 
    } 
    else 
    { 
     TranslateMessage(&msg); 
     DispatchMessage(&msg); 
    } 
} 

Đó là công việc của ứng dụng - không phải là system's điều hành - để đảm bảo rằng các thông điệp được gửi đi.Có thể bạn đã biết, các game Windows đầu tiên sử dụng một phương pháp thay thế, thay vì gọi chức năng chặn GetMessage, họ sẽ gọi PeekMessage và sau đó gọi vòng xử lý chính của trò chơi nếu không có thông báo để xử lý. Các dạng trễ khác nhau được sử dụng để cố gắng đạt được tỷ lệ khung hình đầy đủ mà không cần lấy CPU 100%. Chỉ có không phải là một bộ đếm thời gian đủ tốt để cung cấp cho một tỷ lệ khung hình trơn tru.

Hôm nay, có thể không cần phải viết một vòng lặp rõ ràng gọi DoEvents. Hiện tại, có thể là để có tốc độ khung hình mượt mà bằng cách sử dụng bộ hẹn giờ trong bộ hẹn giờ tích hợp (được hiển thị trong .NET by System.Threading.Timer và được bao bọc bởi System.Timers.Timer).

Khi tôi nhớ lại, cũng có vấn đề với việc nhận các sự kiện chuột và bàn phím một cách kịp thời. Chúng tôi sử dụng truy cập bàn phím và chuột trực tiếp thay vì tùy thuộc vào vòng lặp tin nhắn, vì vòng lặp tin nhắn thường quá chậm và đôi khi sẽ khiến chúng tôi mất thông tin.

Tôi đã không viết trò chơi trong một số năm và tôi không biết .NET giống như nền tảng trò chơi. Có thể đầu vào vẫn là một vấn đề - rằng hàng đợi tin nhắn đơn giản là không đủ nhanh để cung cấp phản hồi nhanh như chớp mà các nhà phát triển trò chơi muốn. Vì vậy, họ bỏ qua hàng đợi tin nhắn cho các nhiệm vụ quan trọng.

+0

Tôi đã thực sự suy nghĩ nếu nó sẽ làm cho sence để làm cho một bộ đếm thời gian mà biết tần số của màn hình để tạo khung. Bằng cách đó, các hoạt động không cần thiết đã từng được thực hiện. Ngoài ra ý tưởng được đặt ra bởi @Bryan Parker để có bản vẽ trong một chủ đề riêng biệt để kéo nó rời khỏi phần còn lại (logic trò chơi/IO) ... –

+0

..sounds như một ý tưởng hay. Tôi không biết nếu nó là pratical mặc dù. –

+1

Hầu hết các trò chơi đều hiển thị trong một chuỗi riêng biệt ngay bây giờ. Và bạn muốn có thể tách rời các bản cập nhật của bạn từ vsync để kiểm tra hiệu suất (trong số các lý do khác) – BigSandwich

1

Tất cả các chương trình đang chạy không bao giờ kết thúc vòng lặp. Mặc dù trong một số trường hợp, bạn không tương tác với vòng lặp (như trong lập trình web hoặc các chương trình nhỏ khác)

Hệ điều hành của bạn là vòng lặp chờ lệnh nhập. Tương tự với một trò chơi. Máy chủ web là vòng lặp đang chờ yêu cầu.

Một lời giải thích tuyệt vời là từ người dùng slim on one of my own questions.

+0

Về cơ bản bạn có quyền, mặc dù điều này chỉ đúng đối với các chương trình dựa trên GUI. cho các ứng dụng tầm thường và dòng lệnh, bạn có thể dễ dàng thoát khỏi mà không có vòng lặp chính. –

+0

Đã thêm làm rõ. –

+0

Đọc bài đăng của bạn và thực sự tôi đã tìm ra điều đó. Nhưng kể từ khi hệ điều hành đã làm vòng lặp này, nó không phải là một ý tưởng tốt để móc vào vòng lặp đó (sử dụng các sự kiện của hệ điều hành) chứ không phải sau đó tạo vòng lặp của riêng của chúng tôi trong vòng lặp hệ điều hành? –

0

nhắn Queues là vòng Infinite cũng khiến tất cả các chương trình như Infinite Loops.

-3

nếu bạn không cảm thấy thoải mái về điều đó, gói nó với lớp và giao diện,

đó là những gì chúng ta nói "nguyên tắc mở và đóng": mở giao diện không bao giờ thay đổi, đóng phần bẩn.

lý do chúng tôi sử dụng vòng lặp? bởi vì nó là cấu trúc cơ bản của máy tính của chúng tôi!

+0

Tôi lo sợ có thông tin sai lạc. Tôi biết làm thế nào tôi có thể ẩn tất cả các bit xấu xí, nhưng câu hỏi là tại sao chúng ta nên thực hiện một vòng lặp trong vòng lặp hệ điều hành. –

1

Vòng lặp tốt hơn là vòng lặp vô tận với chặn cuộc gọi để gửi các sự kiện/tin nhắn. Nếu không có gì để được thực hiện, bạn thực sự không nên ngủ, nhưng chặn trong khi chờ đợi cho hệ điều hành. Nhưng nếu hệ điều hành thực sự không chặn khi bạn thăm dò ý kiến ​​cho các sự kiện, ngủ giữa các cuộc thăm dò là giải pháp duy nhất để ngăn chặn việc sử dụng CPU 100%.

+0

Ok, đó thực sự là những gì tôi muốn nói với giấc ngủ. (các DoEvents cũ). Sẽ thay đổi bài đăng để phản ánh điều đó. –

1

Tôi không thấy nó có thể được thực hiện nhiều cách khác nhau như thế nào?

Việc thực thi chương trình của bạn xảy ra bên trong một chuỗi (hoặc nhiều chuỗi nếu bạn ưa thích). Có một gameloop (hoặc một win32 GetMessage/DispatchMessage bơm) là tất cả về chờ đợi cho sự kiện xảy ra và sau đó xử lý chúng. Cách khác là đăng ký callbacks, sau đó gọi một HandleAllMyMessages(), mà sẽ làm nội bộ làm khá nhiều điều tương tự ... và điều đó sẽ không thực sự mua cho bạn bất cứ điều gì.

Hệ điều hành sẽ không thể phân tách chương trình của bạn thành nhiều chủ đề vì nó không có kiến ​​thức về những gì bạn muốn làm trong các chủ đề đó. Việc tạo ra một luồng mới cho mỗi thư đến sẽ là cả địa chỉ hoạt động và đồng bộ hóa.

1

On Win32 tôi sử dụng một bộ đếm thời gian MultiMedia gọi đánh dấu gamelogic tôi ...

// request 1ms period for timer 
g_mmTimer = timeBeginPeriod(1); 
if (g_mmTimer != TIMERR_NOERROR) 
    return false; 

//start game loop event timer/thread 
g_mmTimer = timeSetEvent(10, 10, DoUpdate, 0, TIME_PERIODIC); 

Tùy chọn, bạn có thể làm tất cả những bản vẽ trong chủ đề khác để các trò chơi logic là tự động không phụ thuộc vào tốc độ khung hình.

2

Trò chơi (trong hầu hết các trường hợp) là mô phỏng. Theo truyền thống, điều này có nghĩa là bạn cập nhật mô phỏng, trình bày trạng thái hiện tại của nó (ví dụ: render đồ họa) và lặp lại. Biểu diễn tự nhiên cho điều này là một vòng lặp.

Máy bơm tin nhắn Win32 mặt khác là một quirk cụ thể nền tảng, hướng tới các ứng dụng theo hướng sự kiện tạo nên phần lớn các ứng dụng trên Windows. Nó không phải là tiêu chuẩn cho các ứng dụng trên tất cả các nền tảng, do đó không có gì đáng ngạc nhiên khi không phải tất cả phần mềm đều phù hợp với mô hình. Vì vậy, để sửa đổi một chương trình điển hình để phù hợp với mô hình Win32, bạn thường tiêu hao hàng đợi đó trong một lần, mỗi lần lặp lại vòng lặp, sử dụng PeekMessage cho đến khi nó trống. Hoặc, bạn đặt logic đó vào một chuỗi riêng biệt và sử dụng GetMessage khi thích hợp.

Đối với hầu hết các trò chơi có hiệu suất, không có cách nào khác để thực hiện điều này. Thứ nhất, nếu bạn cố gắng làm cho trò chơi hướng sự kiện thay vì bỏ phiếu, bạn cần thời gian có độ phân giải cao hơn Windows có thể cung cấp cho bạn một cách đáng tin cậy nếu bạn muốn duy trì hiệu suất cao mà nhiều trò chơi đi. Thứ hai, Windows chỉ là một trong những nền tảng mà trò chơi được viết cho, và làm lại trò chơi để phù hợp với mô hình Win32 sẽ là một sự bất tiện cho nền tảng trò chơi chuyên dụng mà mong đợi vòng lặp trò chơi kinh điển thay thế.

Cuối cùng, những lo ngại về việc 'lấy 100% CPU' bị đặt không đúng chỗ. Hầu hết các trò chơi hiện đại được thiết kế để sử dụng ở chế độ toàn màn hình với quyền truy cập phần cứng độc quyền, không chỉ là một trong nhiều ứng dụng khác cùng tồn tại. Khách hàng của các trò chơi như vậy thực sự yêu cầu trò chơi tận dụng tối đa phần cứng của họ và điều này không thể thực hiện nếu có các cuộc gọi hoặc cập nhật Sleep() cố định phụ thuộc vào bộ hẹn giờ bên ngoài đánh thức ứng dụng N lần một giây. Rõ ràng có những ngoại lệ cho nhiều trò chơi, ví dụ như. những thứ được thiết kế để chạy chủ yếu trong một cửa sổ, nhưng điều quan trọng cần lưu ý là sự khác biệt.

+0

Câu trả lời và tổng quan tuyệt vời. –

+0

Lấy 100% CPU chắc chắn là một mối quan tâm hợp lệ và một cái gì đó cần tránh. Ngay cả khi bạn đang ở chế độ toàn màn hình, bạn cũng không muốn lãng phí các chu kỳ CPU. Nó cản trở việc quản lý năng lượng nhiều hơn và nhiều hơn nữa với mỗi năm trôi qua. Khi bạn viết câu trả lời của bạn, nó sẽ chỉ có được một mối quan tâm cho máy tính xách tay (đó vẫn là lý do đủ để không ghi CPU). Hôm nay, nó sẽ tung một lõi CPU vào Turbo Boost, giảm sức mạnh cho GPU tích hợp. Vì vậy, ý tưởng của bạn về việc hogging tất cả các tài nguyên cho trò chơi của bạn thực sự làm giảm hiệu suất của nó. -1 –

+0

@BenVoigt - Đó là một điểm hợp lệ nhưng nó phụ thuộc vào nền tảng bạn đang nhắm mục tiêu. Trò chơi AAA không được nhắm mục tiêu dành riêng cho nền tảng di động hoặc máy tính xách tay sẽ không cố tình giới thiệu chu kỳ ngủ vì bất kỳ lý do nào và sẽ tăng quy mô xử lý để lấp đầy tài nguyên CPU sẵn có. Cụ thể hơn, họ sẽ không được mong đợi sẽ tạo ra hiệu suất tốt trên các GPU tích hợp - họ là những công dân hạng hai khi có liên quan đến phần mềm trò chơi. Nhưng nếu bạn đang nhắm vào thiết bị di động ... đó là một câu chuyện khác. – Kylotan

0

MsgWaitForMultipleEvents kết hợp chức năng GetMessage/PeekMessage với thời gian chờ và khả năng chờ đối tượng hạt nhân, chẳng hạn như WaitableTimer.

Tôi đã sử dụng CreateWaitableTimer để thiết lập tốc độ khung hình mong muốn cùng với MsgWaitForMultipleEvents để gửi tin nhắn với thành công lớn cho hoạt ảnh rất mượt mà trước đây mà không bận. Tôi muốn các hệ điều hành khác có bất cứ điều gì tốt đẹp như vậy.

Các vấn đề liên quan