2011-05-14 62 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