2013-05-05 42 views
5

Tôi tự hỏi liệu có giải pháp hẹn giờ phổ biến nào không.Bộ hẹn giờ trong clojure?

Tôi muốn viết một công cụ trò chơi đơn giản để xử lý người dùng nhập vào đánh dấu mỗi 20ms (hoặc thực hiện một số hành động sau khi sau 20ms (hoặc bất kỳ khoảng thời gian nào khác)) và về cơ bản cập nhật trạng thái "toàn cầu" thông qua giao dịch. Tôi dự định sử dụng futures để giải pháp này có thể giải quyết được vấn đề đồng thời.

Bạn có thể cho tôi lời khuyên không?

Trả lời

11

Bạn thực sự có hai vấn đề khác biệt ở đây.

Đầu tiên là vấn đề của bộ hẹn giờ. Bạn có rất nhiều lựa chọn ở đây:

  • Bắt đầu một chủ đề mà ngủ giữa hành động, một cái gì đó giống như (future (loop [] (do-something) (Thread/sleep 20) (when (game-still-running) (recur))))
  • Sử dụng Java TimerTask - dễ dàng để gọi từ Clojure
  • Sử dụng thư viện như tiện ích nhỏ của tôi Task bao gồm DSL cho các tác vụ lặp lại
  • Sử dụng chức năng hẹn giờ từ bất kỳ công cụ trò chơi nào bạn đang sử dụng - hầu hết các công cụ này cung cấp một số công cụ để thiết lập vòng lặp trò chơi

Tôi có lẽ chỉ cần sử dụng tùy chọn chuỗi đơn giản - nó khá dễ dàng để thiết lập và dễ dàng để hack nhiều tính năng hơn sau này nếu bạn cần.

Vấn đề thứ hai là xử lý trạng thái trò chơi. Đây thực sự là vấn đề phức tạp hơn và bạn sẽ cần phải thiết kế nó xung quanh loại hình cụ thể của trò chơi bạn đang làm, vì vậy tôi sẽ chỉ đưa ra một vài điểm của lời khuyên:

  • Nếu trò chơi nhà nước của bạn là bất biến, sau đó bạn nhận được rất nhiều lợi thế: mã kết xuất của bạn có thể vẽ trạng thái trò chơi hiện tại một cách độc lập trong khi cập nhật trò chơi đang tính toán trạng thái trò chơi tiếp theo. Tính bất biến có một số chi phí hiệu suất, nhưng lợi thế đồng thời là rất lớn nếu bạn có thể làm cho nó hoạt động. Cả hai trò chơi Clojure nhỏ của tôi (Ironclad và Alchemy) đều sử dụng phương pháp này
  • Bạn có thể thử và lưu trữ trạng thái trò chơi của mình trong một số một cấp cao nhất var. Tôi thấy điều này hoạt động tốt hơn việc tách các phần khác nhau của trạng thái trò chơi trên các loại vars khác nhau. Nó cũng có nghĩa là bạn không thực sự cần các giao dịch dựa trên ref: một nguyên tử hoặc tác nhân thường sẽ thực hiện thủ thuật.
  • Bạn có thể muốn triển khai hàng đợi sự kiện cần được xử lý tuần tự bằng chức năng cập nhật trạng thái trò chơi. Điều này đặc biệt quan trọng nếu bạn có nhiều nguồn sự kiện đồng thời (ví dụ: tác vụ trình phát, dấu hẹn giờ, sự kiện mạng, v.v.)
+0

Cảm ơn, tôi đồng ý rằng trò chơi rất khó, đường dẫn của tôi với kiến ​​trúc quy hoạch sử dụng tính năng clojure chỉ bắt đầu :) – asdf

4

Giải pháp này giả định bạn đang viết Clojure trên JVM. Một cái gì đó như thế này có thể hoạt động:

(import '(java.util TimerTask Timer)) 

(let [task (proxy [TimerTask] [] 
      (run [] (println "Here we go!")))] 
    (. (new Timer) (schedule task (long 20)))) 
+0

Cũng có liên quan và thú vị http://pragprog.com/magazines/2011-07/create-unix-services-with-clojure –

+0

Cảm ơn, cuối cùng tôi nhận được thông báo 'tick' của mình xuất hiện :) – asdf

+4

@dig, trên JVM hãy xem xét sử dụng 'ScheduledExecutorService': http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledExecutorService.html. Timer có một số nhược điểm mà dịch vụ thực thi không có. –

4

Ngày nay tôi sẽ xem xét lõi/async là một lựa chọn tốt, vì

  • nó quy mô rất tốt khi nói đến nhiệm vụ phức tạp có thể được chia thành các hoạt động liên lạc qua các kênh truyền hình
  • tránh ràng buộc hoạt động to a thread

đây là phác thảo

(require '[clojure.core.async :refer [go-loop]]) 
(go-loop [] 
    (do 
    (do-something ...) 
    (Thread/sleep 1000) 
    (recur)))) 
+2

Sử dụng '(

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