我在clojure中编写了一个多线程弹跳球程序。启动动画线程后,我做 -
(send-balls)
启动弹跳球线程。球不会移动,这会显示在控制台上 -
(#<Agent@5675b3ee FAILED: #<Ref@313d21d6: {:x 759, :y 629, :x-speed 3, :y-speed 1}>> #<Agent@22cf3539 FAILED: #<Ref@247881db: {:x 794, :y 258, :x-speed 2, :y-speed 3}>> #<Agent@51af4309 FAILED: #<Ref@445ead9d: {: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 :(得分:3)
正如我所看到的主要问题 - 您向代理发送的功能不是与代理一起运行,而是与其值(引用)一起运行。通过消除 set-new-x 和 set-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 :(得分:3)
我认为你不需要代理内部的refs。请参阅下面的仅与代理商合作的工作版本。你可以加载代码,例如。通过load-file
,然后发出start
。将弹出一个带有所需动画的框架。它可以通过reset!
将返回的原子停止到false
来停止。你可以通过多次调用start来拥有许多独立的动画帧。
希望有所帮助。
(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?))
答案 2 :(得分:1)
您的发送(或发送)功能(在这种情况下:退回)应该返回代理的(新)状态。这已完整描述here。
答案 3 :(得分:1)
代码存在一些问题 -