2011-05-14 60 views
6

我在clojure中編寫了一個多線程彈跳球程序。在啓動動畫線程後,我會 -在Clojure中使用代理的多線程彈跳球程序

(send-balls) 

啓動彈跳球線程。球不會移動,這是顯示在控制檯上 -

(#<[email protected] FAILED: #<[email protected]: {:x 759, :y 629, :x-speed 3, :y-speed 1}>> #<[email protected] FAILED: #<[email protected]: {:x 794, :y 258, :x-speed 2, :y-speed 3}>> #<[email protected] FAILED: #<[email protected]: {:x 831, :y 251, :x-speed 4, :y-speed 2}>>) 

有人可以指出這裏發生了什麼?

(import 
'(java.awt Color Graphics Dimension) 
'(java.awt.image BufferedImage) 
'(javax.swing JPanel JFrame)) 

(def width 1000) 
(def height 1000) 

(def number-of-balls 3) 

(def rad 20) 

(def origin-x 100) 
(def origin-y 100) 
(def box-height 500) 
(def box-width 700) 
(def max-x (+ origin-x box-width (* 4 rad))) 
(def max-y (+ origin-y box-height (* 4 rad))) 
(def min-x origin-x) 
(def min-y origin-y) 

(defn init-x 
[] 
(+ (rand-int (- max-x min-x)) min-x)) 

(defn init-y 
[] 
    (+ (rand-int (- max-y min-y)) min-y)) 

(defstruct ball :x :y :x-speed :y-speed) 

(def balls 
(apply vector (map (fn [_] (ref (struct ball (init-x) (init-y) 
(rand-int 10) (rand-int 10)))) 
       (range number-of-balls)))) 

(def ball-agents (apply vector (map agent balls))) 

(defn get-ball 
[n] 
(balls n)) 


(defn set-new-x 
[ball] 
(let [x (@ball :x) 
     x-speed (@ball :x-speed) 
     new-x (+ x x-speed)] 
    (dosync 
    (if (and (>= new-x min-x) (<= new-x max-x)) 
     (ref-set ball (assoc @ball :x new-x)) 
      (ref-set ball (assoc @ball :x-speed (* -1 x-speed))))) 
    (println "the new x is " @(ball :x))) 
@ball) 

(defn set-new-y 
[ball] 
(let [y (@ball :y) 
     y-speed (@ball :y-speed) 
     new-y (+ y y-speed)] 
    (dosync 
    (if (and (>= new-y min-y) (<= new-y max-y)) 
      (ref-set ball (assoc @ball :y new-y)) 
      (ref-set ball (assoc @ball :y-speed (* -1 y-speed)))))) 
@ball) 

(defn paint-balls 
[bg x y] 
(doto bg 
    (.setColor (. Color red)) 
    (.fillOval x y rad rad))) 


(defn render 
[g] 
(let [img (new BufferedImage width height 
       (. BufferedImage TYPE_INT_ARGB)) 
     bg (. img (getGraphics))] 
    (doto bg 
    (.setColor (. Color white)) 
    (.fillRect 0 0 (. img (getWidth)) (. img (getHeight))) 
    (.setColor (. Color red)) 
    (.drawRect origin-x origin-y (+ origin-x box-width) (+ origin-y box-height))) 
    (dorun 
    (for [i (range number-of-balls)] 
     (do 
     (paint-balls bg (@(get-ball i) :x) (@(get-ball i) :y))))) 
    (. g (drawImage img 0 0 nil)) 
    (. bg (dispose)))) 

(def panel (doto (proxy [JPanel] [] 
         (paint [g] (render g))) 
      (.setPreferredSize (new Dimension 
            width 
            height)))) 

(def frame (doto (new JFrame) (.add panel) .pack .show)) 

(def animator (agent nil)) 

(defn bounce 
[x] 
(while true 
    (set-new-x @*agent*) 
    (set-new-y @*agent*) 
    (. Thread (sleep 100)) 
    (println "here in bounce " *agent*))) 




(defn animation 
[x] 
(send-off *agent* animation) 
(. panel (repaint)) 
(. Thread (sleep 100))) 

(defn send-balls 
[] 
(doall 
    (for [i (range number-of-balls)] 
    (do 
     (send-off (ball-agents i) bounce))))) 


(send-off animator animation) 
+0

看起來您的代理更新失敗 - 可能是由於反彈功能中的異常。我懷疑有一個問題是你的解除引用過多,即「@ * agent *」實際上應該是「\ * agent \ *」。 – mikera 2011-05-14 15:13:54

+0

@mikera - 我試過了,但那不是... – Pranav 2011-05-14 18:30:47

回答

3

正如我看到的主要問題 - 您向代理人發送的功能不是與代理程序一起運行,而是與它的值(ref)一起運行。通過省去@set-new-xset-new-y函數可以使它工作。

(ns balls) 

(import 
    '(java.awt Color Graphics Dimension) 
    '(java.awt.image BufferedImage) 
    '(javax.swing JPanel JFrame)) 

(def width 1000) 
(def height 1000) 

(def number-of-balls 3) 

(def rad 20) 

(def origin-x 100) 
(def origin-y 100) 
(def box-height 500) 
(def box-width 700) 
(def max-x (+ origin-x box-width (* 4 rad))) 
(def max-y (+ origin-y box-height (* 4 rad))) 
(def min-x origin-x) 
(def min-y origin-y) 

(defn init-x 
[] 
(+ (rand-int (- max-x min-x)) min-x)) 

(defn init-y 
[] 
    (+ (rand-int (- max-y min-y)) min-y)) 

(defstruct ball :x :y :x-speed :y-speed) 

(def balls 
(apply vector (map (fn [_] (ref (struct ball (init-x) (init-y) 
(rand-int 10) (rand-int 10)))) 
       (range number-of-balls)))) 

(def ball-agents (apply vector (map agent balls))) 

(defn get-ball 
[n] 
(balls n)) 


(defn set-new-x 
    [ball] 
    (let [x (ball :x) 
     x-speed (ball :x-speed) 
     new-x (+ x x-speed)] 
    (dosync 
     (if (and (>= new-x min-x) (<= new-x max-x)) 
     (alter ball assoc :x new-x) 
     (alter ball assoc :x-speed (* -1 x-speed))))) 
    ball) 

(defn set-new-y 
    [ball] 
    (let [y (ball :y) 
     y-speed (ball :y-speed) 
     new-y (+ y y-speed)] 
    (dosync 
     (if (and (>= new-y min-y) (<= new-y max-y)) 
     (alter ball assoc :y new-y) 
     (alter ball assoc :y-speed (* -1 y-speed)))) 
    ball)) 

(defn paint-balls 
[bg x y] 
(doto bg 
    (.setColor (. Color red)) 
    (.fillOval x y rad rad))) 


(defn render 
[g] 
(let [img (new BufferedImage width height 
       (. BufferedImage TYPE_INT_ARGB)) 
     bg (. img (getGraphics))] 
    (doto bg 
    (.setColor (. Color white)) 
    (.fillRect 0 0 (. img (getWidth)) (. img (getHeight))) 
    (.setColor (. Color red)) 
    (.drawRect origin-x origin-y (+ origin-x box-width) (+ origin-y box-height))) 
    (dorun 
    (for [i (range number-of-balls)] 
     (do 
     (paint-balls bg (@(get-ball i) :x) (@(get-ball i) :y))))) 
    (. g (drawImage img 0 0 nil)) 
    (. bg (dispose)))) 

(def panel (doto (proxy [JPanel] [] 
         (paint [g] (render g))) 
      (.setPreferredSize (new Dimension 
            width 
            height)))) 

(def frame (doto (new JFrame) (.add panel) .pack .show)) 

(def animator (agent nil)) 

(defn bounce 
[ball_cur] 
(do 
    (Thread/sleep 100) 
    (send-off *agent* bounce) 
    (set-new-x (set-new-y ball_cur)))) 

(defn animation 
[x] 
(send-off *agent* animation) 
(. panel (repaint)) 
(. Thread (sleep 100))) 

(defn send-balls 
[] 
(doall 
    (for [i (range number-of-balls)] 
    (do 
     (send-off (ball-agents i) bounce))))) 


(send-off animator animation) 
(send-balls) 
1

您的發送(或發送)功能(在這種情況下:反彈)應返回代理的(新)狀態。這完全描述爲here

1

有幾個與代碼的問題 -

  1. 作爲Maurits的人士指出,反彈不會返回代理的新狀態。
  2. 在退回功能中,再次向代理的操作隊列添加退回時沒有任何地方。這是需要的,因爲新的協調需要一次又一次地計算。
3

我覺得你不需要代理內部的refs。請參閱下面的代理工作版本。你可以加載代碼例如。通過load-file然後簡單地發出start。一幀會彈出所需的動畫。它可以通過reset!將返回的原子停止到false。您可以通過多次調用啓動來獲得許多獨立的動畫幀。

希望有所幫助。

(import 
'(java.awt Color Graphics Dimension) 
'(java.awt.image BufferedImage) 
'(javax.swing JPanel JFrame)) 

(def width 1000) 
(def height 1000) 

(def number-of-balls 3) 

(def rad 20) 

(def origin-x 100) 
(def origin-y 100) 
(def box-height 500) 
(def box-width 700) 
(def min-borders {:x origin-x 
        :y origin-y}) 
(def max-borders {:x (+ origin-x box-width (* 4 rad)) 
        :y (+ origin-y box-height (* 4 rad))}) 

(defn init 
[coord] 
(+ (rand-int (- (get max-borders coord) (get min-borders coord))) 
    (get min-borders coord))) 

(defn init-balls 
    [] 
    (->> (repeatedly number-of-balls 
        #(array-map :x (init :x) :y (init :y) 
           :x-speed (rand-int 10) 
           :y-speed (rand-int 10))) 
    (map agent) 
    vec)) 

(defn update-coordinate 
    [ball coord-key speed-key] 
    (let [coord (get ball coord-key) 
     speed (get ball speed-key) 
     new-c (+ coord speed)] 
    (if (<= (get min-borders coord-key) new-c (get max-borders coord-key)) 
     (assoc ball coord-key new-c) 
     (assoc ball speed-key (- speed))))) 

(defn paint-ball 
    [bg x y] 
    (doto bg 
    (.setColor Color/red) 
    (.fillOval x y rad rad))) 

(defn render 
    [g balls] 
    (let [img (BufferedImage. width height BufferedImage/TYPE_INT_ARGB) 
     bg (.getGraphics img)] 
    (doto bg 
     (.setColor Color/white) 
     (.fillRect 0 0 (.getWidth img) (.getHeight img)) 
     (.setColor Color/red) 
     (.drawRect origin-x origin-y 
       (+ origin-x box-width) (+ origin-y box-height))) 
    (doseq [b balls] 
     (let [ball @b] 
     (paint-ball bg (:x ball) (:y ball)))) 
    (.drawImage g img 0 0 nil))) 

(defn bounce 
    [ball running?] 
    (when @running? 
    (send-off *agent* bounce running?)) 
    (Thread/sleep 100) 
    (-> ball 
    (update-coordinate :x :x-speed) 
    (update-coordinate :y :y-speed))) 

(defn animation 
    [panel running?] 
    (while @running? 
    (javax.swing.SwingUtilities/invokeAndWait #(.repaint panel)) 
    (Thread/sleep 100))) 

(defn start 
    [] 
    (let [running? (atom true) 
     balls (init-balls) 
     panel (doto (proxy [JPanel] [] 
         (paint [g] (render g balls))) 
        (.setPreferredSize (Dimension. width height))) 
     frame (doto (JFrame.) (.add panel) .pack .show)] 
    (doseq [b balls] 
     (send-off b bounce running?)) 
    (future (animation panel running?)) 
    running?)) 
+0

更新座標功能有問題。 – Pranav 2011-05-18 13:24:25

+0

@pranav Woops。切割'不良'故障。固定。 – kotarak 2011-05-18 14:12:21