view org/test-creature.org @ 93:7b739503836a

saving work
author Robert McIntyre <rlm@mit.edu>
date Mon, 09 Jan 2012 19:14:47 -0700
parents e70ec4bba96b
children 69174ed0f9f6
line wrap: on
line source
1 #+title: First attempt at a creature!
2 #+author: Robert McIntyre
3 #+email: rlm@mit.edu
4 #+description:
5 #+keywords: simulation, jMonkeyEngine3, clojure
6 #+SETUPFILE: ../../aurellem/org/setup.org
7 #+INCLUDE: ../../aurellem/org/level-0.org
9 * Intro
10 So far, I've made the following senses --
11 - Vision
12 - Hearing
13 - Touch
14 - Proprioception
16 And one effector:
17 - Movement
19 However, the code so far has only enabled these senses, but has not
20 actually implemented them. For example, there is still a lot of work
21 to be done for vision. I need to be able to create an /eyeball/ in
22 simulation that can be moved around and see the world from different
23 angles. I also need to determine weather to use log-polar or cartesian
24 for the visual input, and I need to determine how/wether to
25 disceritise the visual input.
27 I also want to be able to visualize both the sensors and the
28 effectors in pretty pictures. This semi-retarted creature will by my
29 first attempt at bringing everything together.
31 * The creature's body
33 Still going to do an eve-like body in blender, but due to problems
34 importing the joints, etc into jMonkeyEngine3, I',m going to do all
35 the connecting here in clojure code, using the names of the individual
36 components and trial and error. Later, I'll maybe make some sort of
37 creature-building modifications to blender that support whatever
38 discreitized senses I'm going to make.
40 #+name: body-1
41 #+begin_src clojure
42 (ns cortex.silly
43 "let's play!"
44 {:author "Robert McIntyre"})
46 ;; TODO remove this!
47 (require 'cortex.import)
48 (cortex.import/mega-import-jme3)
49 (use '(cortex world util body hearing touch vision))
51 (rlm.rlm-commands/help)
53 (declare joint-create)
55 (defn load-bullet []
56 (let [sim (world (Node.) {} no-op no-op)]
57 (.enqueue
58 sim
59 (fn []
60 (.stop sim)))
61 (.start sim)))
63 (defn load-blender-model
64 "Load a .blend file using an asset folder relative path."
65 [^String model]
66 (.loadModel
67 (doto (asset-manager)
68 (.registerLoader BlenderModelLoader (into-array String ["blend"])))
69 model))
71 (defn meta-data [blender-node key]
72 (if-let [data (.getUserData blender-node "properties")]
73 (.findValue data key)
74 nil))
76 (defn blender-to-jme
77 "Convert from Blender coordinates to JME coordinates"
78 [#^Vector3f in]
79 (Vector3f. (.getX in)
80 (.getZ in)
81 (- (.getY in))))
83 (defn jme-to-blender
84 "Convert from JME coordinates to Blender coordinates"
85 [#^Vector3f in]
86 (Vector3f. (.getX in)
87 (- (.getZ in))
88 (.getY in)))
90 (defn joint-targets
91 "Return the two closest two objects to the joint object, ordered
92 from bottom to top according to the joint's rotation."
93 [#^Node parts #^Node joint]
94 ;;(println (meta-data joint "joint"))
95 (.getWorldRotation joint)
96 (loop [radius (float 0.01)]
97 (let [results (CollisionResults.)]
98 (.collideWith
99 parts
100 (BoundingBox. (.getWorldTranslation joint)
101 radius radius radius)
102 results)
103 (let [targets
104 (distinct
105 (map #(.getGeometry %) results))]
106 (if (>= (count targets) 2)
107 (sort-by
108 #(let [v
109 (jme-to-blender
110 (.mult
111 (.inverse (.getWorldRotation joint))
112 (.subtract (.getWorldTranslation %)
113 (.getWorldTranslation joint))))]
114 (println-repl (.getName %) ":" v)
115 (.dot (Vector3f. 1 1 1)
116 v))
117 (take 2 targets))
118 (recur (float (* radius 2))))))))
120 (defn world-to-local
121 "Convert the world coordinates into coordinates relative to the
122 object (i.e. local coordinates), taking into account the rotation
123 of object."
124 [#^Spatial object world-coordinate]
125 (let [out (Vector3f.)]
126 (.worldToLocal object world-coordinate out) out))
128 (defmulti joint-dispatch
129 "Translate blender pseudo-joints into real JME joints."
130 (fn [constraints & _]
131 (:type constraints)))
133 (defmethod joint-dispatch :point
134 [constraints control-a control-b pivot-a pivot-b rotation]
135 (println-repl "creating POINT2POINT joint")
136 (Point2PointJoint.
137 control-a
138 control-b
139 pivot-a
140 pivot-b))
142 (defmethod joint-dispatch :hinge
143 [constraints control-a control-b pivot-a pivot-b rotation]
144 (println-repl "creating HINGE joint")
145 (let [axis
146 (if-let
147 [axis (:axis constraints)]
148 axis
149 Vector3f/UNIT_X)
150 [limit-1 limit-2] (:limit constraints)
151 hinge-axis
152 (.mult
153 rotation
154 (blender-to-jme axis))]
155 (doto
156 (HingeJoint.
157 control-a
158 control-b
159 pivot-a
160 pivot-b
161 hinge-axis
162 hinge-axis)
163 (.setLimit limit-1 limit-2))))
165 (defmethod joint-dispatch :cone
166 [constraints control-a control-b pivot-a pivot-b rotation]
167 (let [limit-xz (:limit-xz constraints)
168 limit-xy (:limit-xy constraints)
169 twist (:twist constraints)]
171 (println-repl "creating CONE joint")
172 (println-repl rotation)
173 (println-repl
174 "UNIT_X --> " (.mult rotation (Vector3f. 1 0 0)))
175 (println-repl
176 "UNIT_Y --> " (.mult rotation (Vector3f. 0 1 0)))
177 (println-repl
178 "UNIT_Z --> " (.mult rotation (Vector3f. 0 0 1)))
179 (doto
180 (ConeJoint.
181 control-a
182 control-b
183 pivot-a
184 pivot-b
185 rotation
186 rotation)
187 (.setLimit (float limit-xz)
188 (float limit-xy)
189 (float twist)))))
191 (defn connect
192 "here are some examples:
193 {:type :point}
194 {:type :hinge :limit [0 (/ Math/PI 2)] :axis (Vector3f. 0 1 0)}
195 (:axis defaults to (Vector3f. 1 0 0) if not provided for hinge joints)
197 {:type :cone :limit-xz 0]
198 :limit-xy 0]
199 :twist 0]} (use XZY rotation mode in blender!)"
200 [#^Node obj-a #^Node obj-b #^Node joint]
201 (let [control-a (.getControl obj-a RigidBodyControl)
202 control-b (.getControl obj-b RigidBodyControl)
203 joint-center (.getWorldTranslation joint)
204 joint-rotation (.toRotationMatrix (.getWorldRotation joint))
205 pivot-a (world-to-local obj-a joint-center)
206 pivot-b (world-to-local obj-b joint-center)]
208 (if-let [constraints
209 (map-vals
210 eval
211 (read-string
212 (meta-data joint "joint")))]
213 ;; A side-effect of creating a joint registers
214 ;; it with both physics objects which in turn
215 ;; will register the joint with the physics system
216 ;; when the simulation is started.
217 (do
218 (println-repl "creating joint between"
219 (.getName obj-a) "and" (.getName obj-b))
220 (joint-dispatch constraints
221 control-a control-b
222 pivot-a pivot-b
223 joint-rotation))
224 (println-repl "could not find joint meta-data!"))))
226 (defn assemble-creature [#^Node pieces joints]
227 (dorun
228 (map
229 (fn [geom]
230 (let [physics-control
231 (RigidBodyControl.
232 (HullCollisionShape.
233 (.getMesh geom))
234 (if-let [mass (meta-data geom "mass")]
235 (do
236 (println-repl
237 "setting" (.getName geom) "mass to" (float mass))
238 (float mass))
239 (float 1)))]
241 (.addControl geom physics-control)))
242 (filter #(isa? (class %) Geometry )
243 (node-seq pieces))))
245 (dorun
246 (map
247 (fn [joint]
248 (let [[obj-a obj-b]
249 (joint-targets pieces joint)]
250 (connect obj-a obj-b joint)))
251 joints))
252 pieces)
254 (defn blender-creature [blender-path]
255 (let [model (load-blender-model blender-path)
256 joints
257 (if-let [joint-node (.getChild model "joints")]
258 (seq (.getChildren joint-node))
259 (do (println-repl "could not find joints node")
260 []))]
261 (assemble-creature model joints)))
263 (def hand "Models/creature1/one.blend")
265 (def worm "Models/creature1/try-again.blend")
267 (def touch "Models/creature1/touch.blend")
269 (defn worm-model [] (load-blender-model worm))
271 (defn x-ray [#^ColorRGBA color]
272 (doto (Material. (asset-manager)
273 "Common/MatDefs/Misc/Unshaded.j3md")
274 (.setColor "Color" color)
275 (-> (.getAdditionalRenderState)
276 (.setDepthTest false))))
278 (defn test-creature [thing]
279 (let [x-axis
280 (box 1 0.01 0.01 :physical? false :color ColorRGBA/Red)
281 y-axis
282 (box 0.01 1 0.01 :physical? false :color ColorRGBA/Green)
283 z-axis
284 (box 0.01 0.01 1 :physical? false :color ColorRGBA/Blue)]
285 (world
286 (nodify [(blender-creature thing)
287 (box 10 2 10 :position (Vector3f. 0 -9 0)
288 :color ColorRGBA/Gray :mass 0)
289 x-axis y-axis z-axis
290 ])
291 standard-debug-controls
292 (fn [world]
293 (light-up-everything world)
294 (enable-debug world)
295 ;;(com.aurellem.capture.Capture/captureVideo
296 ;; world (file-str "/home/r/proj/ai-videos/hand"))
297 (.setTimer world (NanoTimer.))
298 (set-gravity world (Vector3f. 0 0 0))
299 (speed-up world)
300 )
301 no-op
302 ;;(let [timer (atom 0)]
303 ;; (fn [_ _]
304 ;; (swap! timer inc)
305 ;; (if (= (rem @timer 60) 0)
306 ;; (println-repl (float (/ @timer 60))))))
307 )))
310 (defn colorful []
311 (.getChild (worm-model) "worm-21"))
313 (import jme3tools.converters.ImageToAwt)
315 (import ij.ImagePlus)
317 (defn triangle-indices
318 "Get the triangle vertex indices of a given triangle from a given
319 mesh."
320 [#^Mesh mesh triangle-index]
321 (let [indices (int-array 3)]
322 (.getTriangle mesh triangle-index indices)
323 (vec indices)))
325 (defn uv-coord
326 "Get the uv-coordinates of the vertex named by vertex-index"
327 [#^Mesh mesh vertex-index]
328 (let [UV-buffer
329 (.getData
330 (.getBuffer
331 mesh
332 VertexBuffer$Type/TexCoord))]
333 (Vector2f.
334 (.get UV-buffer (* vertex-index 2))
335 (.get UV-buffer (+ 1 (* vertex-index 2))))))
337 (defn tri-uv-coord
338 "Get the uv-cooridnates of the triangle's verticies."
339 [#^Mesh mesh #^Triangle triangle]
340 (map (partial uv-coord mesh)
341 (triangle-indices mesh (.getIndex triangle))))
343 (defn touch-receptor-image
344 "Return the touch-sensor distribution image in ImagePlus format."
345 [#^Geometry obj]
346 (let
347 [mat (.getMaterial obj)
348 texture
349 (.getTextureValue
350 (.getTextureParam
351 mat
352 MaterialHelper/TEXTURE_TYPE_DIFFUSE))
353 im (.getImage texture)]
354 (ImagePlus.
355 "UV-map"
356 (ImageToAwt/convert im false false 0))))
359 (import ij.process.ImageProcessor)
360 (import java.awt.image.BufferedImage)
362 (defprotocol Frame
363 (frame [this]))
365 (extend-type BufferedImage
366 Frame
367 (frame [image]
368 (merge
369 (apply
370 hash-map
371 (interleave
372 (doall (for [x (range (.getWidth image)) y (range (.getHeight image))]
373 (vector x y)))
374 (doall (for [x (range (.getWidth image)) y (range (.getHeight image))]
375 (let [data (.getRGB image x y)]
376 (hash-map :r (bit-shift-right (bit-and 0xff0000 data) 16)
377 :g (bit-shift-right (bit-and 0x00ff00 data) 8)
378 :b (bit-and 0x0000ff data)))))))
379 {:width (.getWidth image) :height (.getHeight image)})))
382 (extend-type ImagePlus
383 Frame
384 (frame [image+]
385 (frame (.getBufferedImage image+))))
387 (def white -1)
389 (defn filter-pixels
390 "List the coordinates of all pixels matching pred."
391 {:author "Dylan Holmes"}
392 [pred #^ImageProcessor ip]
393 (let
394 [width (.getWidth ip)
395 height (.getHeight ip)]
396 ((fn accumulate [x y matches]
397 (cond
398 (>= y height) matches
399 (>= x width) (recur 0 (inc y) matches)
400 (pred (.getPixel ip x y))
401 (recur (inc x) y (conj matches (Vector2f. x y)))
402 :else (recur (inc x) y matches)))
403 0 0 [])))
405 (defn white-coordinates
406 "List the coordinates of all the white pixels in an image."
407 [#^ImageProcessor ip]
408 (filter-pixels #(= % white) ip))
410 (defn same-side? [p1 p2 ref p]
411 (<=
412 0
413 (.dot
414 (.cross (.subtract p2 p1) (.subtract p p1))
415 (.cross (.subtract p2 p1) (.subtract ref p1)))))
417 (defn inside-triangle?
418 [vert-1 vert-2 vert-3 p]
419 (and
420 (same-side? vert-1 vert-2 vert-3 p)
421 (same-side? vert-2 vert-3 vert-1 p)
422 (same-side? vert-3 vert-1 vert-2 p)))
425 (defn analyze-triangle [#^Geometry obj #^Triangle tri]
426 ;; first, calculate the transformation matrix that will take us
427 ;; from uv-coordinates to the real world coordinates
428 (let [mesh (.getMesh obj)
429 world [(.get1 tri) (.get2 tri) (.get3 tri)]
430 uv (tri-uv-coord mesh tri)
435 (println-repl world uv)))
441 (defn tactile-coords*
442 [#^Geometry obj]
443 (let
444 [tris (triangles obj)
445 mesh (.getMesh obj)
448 )
452 ;; for each triangle in the mesh,
453 ;; get the normal to the triangle,
454 ;; look at the UV touch map, restricted to that triangle,
455 ;; get the positions of those touch sensors in geometry-relative
456 ;; coordinates.
457 (defn tactile-coords [#^Geometry obj]
458 (let [mesh (.getMesh obj)
459 num-triangles (.getTriangleCount mesh)
460 num-verticies (.getVertexCount mesh)
461 uv-coord (partial uv-coord mesh)
462 triangle-indices (partial triangle-indices mesh)
463 receptors (touch-receptor-image obj)
464 tris (triangles obj)
465 ]
466 (map
467 (fn [[tri-1 tri-2 tri-3]]
468 (let [width (.getWidth receptors)
469 height (.getHeight receptors)
470 uv-1 (uv-coord tri-1)
471 uv-2 (uv-coord tri-2)
472 uv-3 (uv-coord tri-3)
473 x-coords (map #(.getX %) [uv-1 uv-2 uv-3])
474 y-coords (map #(.getY %) [uv-1 uv-2 uv-3])
475 max-x (Math/ceil (* width (apply max x-coords)))
476 min-x (Math/floor (* width (apply min x-coords)))
477 max-y (Math/ceil (* height (apply max y-coords)))
478 min-y (Math/floor (* height (apply min y-coords)))
480 image-1 (Vector2f. (* width (.getX uv-1))
481 (* height (.getY uv-1)))
482 image-2 (Vector2f. (* width (.getX uv-2))
483 (* height (.getY uv-2)))
484 image-3 (Vector2f. (* width (.getX uv-3))
485 (* height (.getY uv-3)))
486 left-corner
487 (Vector2f. min-x min-y)
489 ]
491 (.setRoi receptors min-x min-y (- max-x min-x) (- max-y min-y))
492 (let [processor (.crop (.getProcessor receptors))]
493 (map
494 #(.add left-corner %)
496 (filter
497 (partial
498 inside-triangle?
499 (.subtract image-1 left-corner)
500 (.subtract image-2 left-corner)
501 (.subtract image-3 left-corner))
502 (white-coordinates processor))))
503 )) (map triangle-indices (range num-triangles)))))
511 (defn all-names []
512 (concat
513 (re-split #"\n" (slurp (file-str
514 "/home/r/proj/names/dist.female.first")))
515 (re-split #"\n" (slurp (file-str
516 "/home/r/proj/names/dist.male.first")))
517 (re-split #"\n" (slurp (file-str
518 "/home/r/proj/names/dist.all.last")))))
528 (defrecord LulzLoader [])
529 (defprotocol Lulzable (load-lulz [this]))
530 (extend-type LulzLoader
531 Lulzable
532 (load-lulz [this] (println "the lulz have arrived!")))
535 (defn world-setup [joint]
536 (let [joint-position (Vector3f. 0 0 0)
537 joint-rotation
538 (.toRotationMatrix
539 (.mult
540 (doto (Quaternion.)
541 (.fromAngleAxis
542 (* 1 (/ Math/PI 4))
543 (Vector3f. -1 0 0)))
544 (doto (Quaternion.)
545 (.fromAngleAxis
546 (* 1 (/ Math/PI 2))
547 (Vector3f. 0 0 1)))))
548 top-position (.mult joint-rotation (Vector3f. 8 0 0))
550 origin (doto
551 (sphere 0.1 :physical? false :color ColorRGBA/Cyan
552 :position top-position))
553 top (doto
554 (sphere 0.1 :physical? false :color ColorRGBA/Yellow
555 :position top-position)
557 (.addControl
558 (RigidBodyControl.
559 (CapsuleCollisionShape. 0.5 1.5 1) (float 20))))
560 bottom (doto
561 (sphere 0.1 :physical? false :color ColorRGBA/DarkGray
562 :position (Vector3f. 0 0 0))
563 (.addControl
564 (RigidBodyControl.
565 (CapsuleCollisionShape. 0.5 1.5 1) (float 0))))
566 table (box 10 2 10 :position (Vector3f. 0 -20 0)
567 :color ColorRGBA/Gray :mass 0)
568 a (.getControl top RigidBodyControl)
569 b (.getControl bottom RigidBodyControl)]
571 (cond
572 (= joint :cone)
574 (doto (ConeJoint.
575 a b
576 (world-to-local top joint-position)
577 (world-to-local bottom joint-position)
578 joint-rotation
579 joint-rotation
580 )
583 (.setLimit (* (/ 10) Math/PI)
584 (* (/ 4) Math/PI)
585 0)))
586 [origin top bottom table]))
588 (defn test-joint [joint]
589 (let [[origin top bottom floor] (world-setup joint)
590 control (.getControl top RigidBodyControl)
591 move-up? (atom false)
592 move-down? (atom false)
593 move-left? (atom false)
594 move-right? (atom false)
595 roll-left? (atom false)
596 roll-right? (atom false)
597 timer (atom 0)]
599 (world
600 (nodify [top bottom floor origin])
601 (merge standard-debug-controls
602 {"key-r" (fn [_ pressed?] (reset! move-up? pressed?))
603 "key-t" (fn [_ pressed?] (reset! move-down? pressed?))
604 "key-f" (fn [_ pressed?] (reset! move-left? pressed?))
605 "key-g" (fn [_ pressed?] (reset! move-right? pressed?))
606 "key-v" (fn [_ pressed?] (reset! roll-left? pressed?))
607 "key-b" (fn [_ pressed?] (reset! roll-right? pressed?))})
609 (fn [world]
610 (light-up-everything world)
611 (enable-debug world)
612 (set-gravity world (Vector3f. 0 0 0))
613 )
615 (fn [world _]
616 (if (zero? (rem (swap! timer inc) 100))
617 (do
618 ;; (println-repl @timer)
619 (.attachChild (.getRootNode world)
620 (sphere 0.05 :color ColorRGBA/Yellow
621 :position (.getWorldTranslation top)
622 :physical? false))
623 (.attachChild (.getRootNode world)
624 (sphere 0.05 :color ColorRGBA/LightGray
625 :position (.getWorldTranslation bottom)
626 :physical? false))))
628 (if @move-up?
629 (.applyTorque control
630 (.mult (.getPhysicsRotation control)
631 (Vector3f. 0 0 10))))
632 (if @move-down?
633 (.applyTorque control
634 (.mult (.getPhysicsRotation control)
635 (Vector3f. 0 0 -10))))
636 (if @move-left?
637 (.applyTorque control
638 (.mult (.getPhysicsRotation control)
639 (Vector3f. 0 10 0))))
640 (if @move-right?
641 (.applyTorque control
642 (.mult (.getPhysicsRotation control)
643 (Vector3f. 0 -10 0))))
644 (if @roll-left?
645 (.applyTorque control
646 (.mult (.getPhysicsRotation control)
647 (Vector3f. -1 0 0))))
648 (if @roll-right?
649 (.applyTorque control
650 (.mult (.getPhysicsRotation control)
651 (Vector3f. 1 0 0))))))))
655 #+end_src
657 #+results: body-1
658 : #'cortex.silly/test-joint
661 * COMMENT purgatory
662 #+begin_src clojure
663 (defn bullet-trans []
664 (let [obj-a (sphere 0.5 :color ColorRGBA/Red
665 :position (Vector3f. -10 5 0))
666 obj-b (sphere 0.5 :color ColorRGBA/Blue
667 :position (Vector3f. -10 -5 0)
668 :mass 0)
669 control-a (.getControl obj-a RigidBodyControl)
670 control-b (.getControl obj-b RigidBodyControl)
671 swivel
672 (.toRotationMatrix
673 (doto (Quaternion.)
674 (.fromAngleAxis (/ Math/PI 2)
675 Vector3f/UNIT_X)))]
676 (doto
677 (ConeJoint.
678 control-a control-b
679 (Vector3f. 0 5 0)
680 (Vector3f. 0 -5 0)
681 swivel swivel)
682 (.setLimit (* 0.6 (/ Math/PI 4))
683 (/ Math/PI 4)
684 (* Math/PI 0.8)))
685 (world (nodify
686 [obj-a obj-b])
687 standard-debug-controls
688 enable-debug
689 no-op)))
692 (defn bullet-trans* []
693 (let [obj-a (box 1.5 0.5 0.5 :color ColorRGBA/Red
694 :position (Vector3f. 5 0 0)
695 :mass 90)
696 obj-b (sphere 0.5 :color ColorRGBA/Blue
697 :position (Vector3f. -5 0 0)
698 :mass 0)
699 control-a (.getControl obj-a RigidBodyControl)
700 control-b (.getControl obj-b RigidBodyControl)
701 move-up? (atom nil)
702 move-down? (atom nil)
703 move-left? (atom nil)
704 move-right? (atom nil)
705 roll-left? (atom nil)
706 roll-right? (atom nil)
707 force 100
708 swivel
709 (.toRotationMatrix
710 (doto (Quaternion.)
711 (.fromAngleAxis (/ Math/PI 2)
712 Vector3f/UNIT_X)))
713 x-move
714 (doto (Matrix3f.)
715 (.fromStartEndVectors Vector3f/UNIT_X
716 (.normalize (Vector3f. 1 1 0))))
718 timer (atom 0)]
719 (doto
720 (ConeJoint.
721 control-a control-b
722 (Vector3f. -8 0 0)
723 (Vector3f. 2 0 0)
724 ;;swivel swivel
725 ;;Matrix3f/IDENTITY Matrix3f/IDENTITY
726 x-move Matrix3f/IDENTITY
727 )
728 (.setCollisionBetweenLinkedBodys false)
729 (.setLimit (* 1 (/ Math/PI 4)) ;; twist
730 (* 1 (/ Math/PI 4)) ;; swing span in X-Y plane
731 (* 0 (/ Math/PI 4)))) ;; swing span in Y-Z plane
732 (world (nodify
733 [obj-a obj-b])
734 (merge standard-debug-controls
735 {"key-r" (fn [_ pressed?] (reset! move-up? pressed?))
736 "key-t" (fn [_ pressed?] (reset! move-down? pressed?))
737 "key-f" (fn [_ pressed?] (reset! move-left? pressed?))
738 "key-g" (fn [_ pressed?] (reset! move-right? pressed?))
739 "key-v" (fn [_ pressed?] (reset! roll-left? pressed?))
740 "key-b" (fn [_ pressed?] (reset! roll-right? pressed?))})
742 (fn [world]
743 (enable-debug world)
744 (set-gravity world Vector3f/ZERO)
745 )
747 (fn [world _]
749 (if @move-up?
750 (.applyForce control-a
751 (Vector3f. force 0 0)
752 (Vector3f. 0 0 0)))
753 (if @move-down?
754 (.applyForce control-a
755 (Vector3f. (- force) 0 0)
756 (Vector3f. 0 0 0)))
757 (if @move-left?
758 (.applyForce control-a
759 (Vector3f. 0 force 0)
760 (Vector3f. 0 0 0)))
761 (if @move-right?
762 (.applyForce control-a
763 (Vector3f. 0 (- force) 0)
764 (Vector3f. 0 0 0)))
766 (if @roll-left?
767 (.applyForce control-a
768 (Vector3f. 0 0 force)
769 (Vector3f. 0 0 0)))
770 (if @roll-right?
771 (.applyForce control-a
772 (Vector3f. 0 0 (- force))
773 (Vector3f. 0 0 0)))
775 (if (zero? (rem (swap! timer inc) 100))
776 (.attachChild
777 (.getRootNode world)
778 (sphere 0.05 :color ColorRGBA/Yellow
779 :physical? false :position
780 (.getWorldTranslation obj-a)))))
781 )
782 ))
786 #+end_src
789 * COMMENT generate source
790 #+begin_src clojure :tangle ../src/cortex/silly.clj
791 <<body-1>>
792 #+end_src