2012-05-29 38 views
8

Đây là một vòng lặp trò chơi đơn giản trong OCaml. Trạng thái được hiển thị, đầu vào được nhận, và trạng thái được nâng cao. Số khung hình trên giây bị hạn chế là 40 bằng cách trì hoãn chuỗi trong vòng 0.025 giây mỗi vòng lặp.Sự kiện trì hoãn và bàn phím trong OCaml

main.ml:

let rec main (* state *) frame_time = 
    (* Display state here. *) 
    Input.get_input(); 
    (* Advance state by one frame here. *) 
    (* If less than 25ms have passed, delay until they have. *) 
    if((Sys.time()) < (frame_time +. 0.025)) then 
    Thread.delay ((frame_time +. 0.025) -. (Sys.time())); 
    main (* next_state *) (Sys.time()) 
;; 

let init = 
    Graphics.open_graph " 800x500"; 
    let start_time = (Sys.time()) in 
    main (* start_state *) start_time 
;; 

Đối với ví dụ này, get_input chức năng chỉ đơn giản in tổ hợp phím vào cửa sổ.

input.ml:

let get_input() = 
    let s = Graphics.wait_next_event 
    [Graphics.Key_pressed] in 
    if s.Graphics.keypressed then 
    Graphics.draw_char s.Graphics.key 
;; 

Makefile để thử nghiệm đơn giản:

main: input.cmo main.cmo 
    ocamlfind ocamlc -o [email protected] unix.cma -thread threads.cma graphics.cma $^ 
main.cmo: main.ml 
    ocamlfind ocamlc -c $< -thread 
input.cmo: input.ml 
    ocamlfind ocamlc -c $< 

này làm việc cho hầu hết các phần, nhưng khi bấm phím nào rất nhanh chóng, chương trình bị treo với lỗi này:

Fatal error: exception Unix.Unix_error(2, "select", "")

Tôi tin rằng nó có thứ gì đó để làm với Thread.delay. Điều gì gây ra vấn đề này, và cách tốt nhất để đạt được FPS liên tục là gì?

Trả lời

9

Tôi không chắc chắn chính xác những gì đang xảy ra (nó phụ thuộc vào việc thực hiện Thread.delay, mà tôi không biết). Tuy nhiên, lỗi 2 là Unix.EAGAIN, lỗi này thể hiện tình trạng thiếu tài nguyên hạt nhân tạm thời. Như tên nói, có lẽ bạn nên thử làm lại Thread.delay của mình. Nếu tôi sử dụng try ... with để bắt ngoại lệ Unix.Unix_error, tôi không thấy lỗi nào khác ngoại trừ EAGAIN đang được gửi. Nếu tôi chỉ in một tin nhắn và tiếp tục, chương trình có vẻ hoạt động. Ít nhất, nó tiếp tục lặp lại các ký tự vào cửa sổ và không bị sập. Tôi đang làm việc trong OS X 10.7 (Sư tử). Nó có thể làm việc khác nhau cho bạn.

Sửa

Một vấn đề khác có thể với mã này là Sys.time() lợi nhuận xử lý thời gian, mà chỉ tăng khi quá trình này được thực hiện tính toán thực sự. Nó không tăng trong khi quá trình đang chờ đầu vào. Điều này có nghĩa rằng sự chậm trễ luôn luôn được gọi, ngay cả khi bạn chờ đợi một thời gian dài giữa các lần nhấn phím (nó đã gây nhầm lẫn cho tôi một thời gian). Nó có thể tốt hơn để sử dụng Unix.gettimeofday(), trả về thời gian đồng hồ treo tường.

Chỉnh sửa 2

Sau khi một số nghiên cứu thêm và thử nghiệm, tôi tin rằng các lỗi Unix.EAGAIN đang nói với bạn rằng sự chậm trễ toàn bị gián đoạn bởi một số sự kiện. Trong trường hợp của bạn, sự kiện gián đoạn là sự xuất hiện của một nhân vật (tôi tin). Vì vậy, nếu bạn muốn đợi toàn bộ thời gian, bạn nên thay thế cuộc gọi đơn thành Thread.delay() bằng một vòng lặp.

này cung cấp cho bạn một cái gì đó như sau cho mã chính của bạn:

let rec main (* state *) frame_time = 
    (* Display state here. *) 
    Input.get_input(); 
    (* Advance state by one frame here. *) 
    (* If less than 25ms have passed, delay until they have. *) 
    let rec delay() = 
    let duration = frame_time +. 0.025 -. Unix.gettimeofday() in 
    if duration > 0.0 then 
     try 
     Thread.delay duration 
     with Unix.Unix_error (Unix.EAGAIN, _, _) -> delay() 
    in 
    delay(); 
    main (* next_state *) (Unix.gettimeofday ()) 
;; 

let init = 
    Graphics.open_graph " 800x500"; 
    let start_time = (Unix.gettimeofday ()) in 
    main (* start_state *) start_time 
;; 

(Nếu bạn sử dụng Unix.select làm trì hoãn, bạn có thể loại bỏ sự phụ thuộc vào chủ đề Nhưng bạn có thể cần đến chúng anyway cho. các lý do khác. Mã sẽ trông giống nhau ngoại trừ lỗi là EINTR thay vì EAGAIN.)

+2

Jeffrey là đúng trên tất cả các tài khoản. Bạn có thể nhận được nhiều thông tin hơn về Chủ đề.trì hoãn [ở đây] (http://ocamlunix.forge.ocamlcore.org/threads.html#htoc63). –

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