Mercurial > cortex
view org/games.org @ 539:fc116e960f56
more elaboration
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sun, 27 Apr 2014 21:52:39 -0400 |
parents | 7e7f8d6d9ec5 |
children |
line wrap: on
line source
1 #+title: jMonkeyEngine3 from Clojure2 #+author: Robert McIntyre3 #+email: rlm@mit.edu4 #+description: Using jMonkeyEngine3 from clojure5 #+keywords: clojure, jMonkeyEngine3, tutorial, examples6 #+SETUPFILE: ../../aurellem/org/setup.org7 #+INCLUDE: ../../aurellem/org/level-0.org8 #+babel: :mkdirp yes :noweb yes :exports both10 [TABLE-OF-CONTENTS]13 Here are the jMonkeyEngine "Hello" programs translated to clojure.15 * Hello Simple App16 Here is the hello world example for jme3 in clojure. It's a more or17 less direct translation from the java source [[http://jmonkeyengine.org/wiki/doku.php/jme3:beginner:hello_simpleapplication][here]].19 Of note is the fact that since we don't have access to the20 =AssetManager= via extending =SimpleApplication=, we have to build one21 ourselves.23 #+name: hello-simple-app24 #+begin_src clojure :results silent25 (ns hello.hello-simple-app26 (:use cortex.world)27 (:import com.jme3.math.Vector3f)28 (:import com.jme3.material.Material)29 (:import com.jme3.scene.Geometry)30 (:import com.jme3.math.ColorRGBA)31 (:import com.jme3.app.SimpleApplication)32 (:import com.jme3.scene.shape.Box))34 (def cube (Box. Vector3f/ZERO 1 1 1))36 (def geom (Geometry. "Box" cube))38 (def mat (Material. (asset-manager) "Common/MatDefs/Misc/Unshaded.j3md"))40 (.setColor mat "Color" ColorRGBA/Blue)42 (.setMaterial geom mat)44 (defn simple-app []45 (doto46 (proxy [SimpleApplication] []47 (simpleInitApp48 []49 ;; Don't take control of the mouse50 (org.lwjgl.input.Mouse/setGrabbed false)51 (.attachChild (.getRootNode this) geom)))52 ;; don't show a menu to change options.53 (.setShowSettings false)54 (.setPauseOnLostFocus false)55 (.setSettings *app-settings*)))56 #+end_src58 Running this program will begin a new jMonkeyEngine game which59 displays a single blue cube.61 #+begin_src clojure :exports code :results silent62 (.start (hello.hello-simple-app/simple-app))63 #+end_src65 #+caption: the simplest JME game.66 [[../images/simple-app.jpg]]68 * Simpler HelloSimpleApp70 #+name: hello-simpler-app71 #+begin_src clojure72 (ns hello.hello-simpler-app73 (:use cortex.world)74 (:use cortex.util)75 (:import com.jme3.math.ColorRGBA)76 (:import com.jme3.scene.Node))78 (defn simpler-world79 "The jMonkeyEngine3 Hello World program. Displays a blue 3D cube in80 a basic 3D world."81 []82 (world (doto (Node.)83 (.attachChild84 (box 1 1 185 :color ColorRGBA/Blue :physical? false)))86 {} no-op no-op))87 #+end_src89 More information about the jMonkeyEngine3 hello world program can be90 found [[http://jmonkeyengine.org/wiki/doku.php/starter:hello_world][here]].92 * COMMENT Hello Physics93 From http://jmonkeyengine.org/wiki/doku.php/jme3:beginner:hello_physics95 #+name: brick-wall-header96 #+begin_src clojure :results silent97 (ns hello.brick-wall)98 (require 'cortex.import)99 (use 'clojure.contrib.def)100 (rlm.rlm-commands/help)101 (cortex.import/mega-import-jme3)102 (use '[pokemon [lpsolve :only [constant-map]]])103 (use 'cortex.world)104 (use 'cortex.util)105 #+end_src107 #+name: brick-wall-body108 #+begin_src clojure :results silent109 (in-ns 'hello.brick-wall)111 (defn floor112 "make a sturdy, unmovable physical floor"113 []114 (box 20 1 20 :mass 0 :color false :position (Vector3f. 0 -2 0)))116 (def brick-length 0.48)117 (def brick-width 0.24)118 (def brick-height 0.12)119 (def gravity (Vector3f. 0 -9.81 0))121 (defn brick* [position]122 (doto (box brick-length brick-height brick-width123 :position position :name "brick"124 :material "Common/MatDefs/Misc/Unshaded.j3md"125 :texture "Textures/Terrain/BrickWall/BrickWall.jpg"126 :mass 36)127 (->128 (.getMesh)129 (.scaleTextureCoordinates (Vector2f. 1 0.5)))130 ;;(.setShadowMode RenderQueue$ShadowMode/CastAndReceive)131 )132 )134 (defn inception-brick-wall135 "construct a physical brick wall"136 []137 (let [node (Node. "brick-wall")]138 (dorun139 (map (comp #(.attachChild node %) brick*)140 (for141 [x (range 15)142 y (range 10)143 z (range 1)]144 (Vector3f.145 (* brick-length x 1.03)146 (* brick-width y y 10)147 (* brick-height z)))))148 node))150 (defn gravity-toggle151 [new-value]152 (fn [game value]153 (println-repl "set gravity to " new-value)154 (if value155 (set-gravity game new-value)156 (set-gravity game gravity))))158 (defn floor* []159 (doto (box 10 0.1 5 :name "floor" ;10 0.1 5 ; 240 0.1 240160 :material "Common/MatDefs/Misc/Unshaded.j3md"161 :texture "Textures/Terrain/Pond/Pond.png"162 :position (Vector3f. 0 -0.1 0 )163 :mass 0)164 (->165 (.getMesh)166 (.scaleTextureCoordinates (Vector2f. 3 6)));64 64167 (->168 (.getMaterial)169 (.getTextureParam "ColorMap")170 (.getTextureValue)171 (.setWrap Texture$WrapMode/Repeat))172 (.setShadowMode RenderQueue$ShadowMode/Receive)173 ))175 (defn brick-wall* []176 (let [node (Node. "brick-wall")]177 (dorun178 (map179 (comp #(.attachChild node %) brick*)180 (for [y (range 15)181 x (range 4)182 z (range 1)]183 (Vector3f.184 (+ (* 2 x brick-length)185 (if (even? (+ y z))186 (/ brick-length 4) (/ brick-length -4)))187 (+ (* brick-height (inc (* 2 y))))188 (* 2 z brick-width) ))))189 (.setShadowMode node RenderQueue$ShadowMode/CastAndReceive)190 node))192 (defn brick-wall-game-run []193 (doto194 (world195 (doto (Node.) (.attachChild (floor*))196 (.attachChild (brick-wall*))197 )198 {"key-i" (gravity-toggle (Vector3f. 0 0 -9.81))199 "key-m" (gravity-toggle (Vector3f. 0 0 9.81))200 "key-l" (gravity-toggle (Vector3f. 9.81 0 0))201 "key-j" (gravity-toggle (Vector3f. -9.81 0 0))202 "key-k" (gravity-toggle Vector3f/ZERO)203 "key-u" (gravity-toggle (Vector3f. 0 9.81 0))204 "key-o" (gravity-toggle (Vector3f. 0 -9.81 0))205 "key-f" (fn[game value]206 (if (not value) (add-element game (brick-wall*))))207 "key-return" (fire-cannon-ball)}208 position-camera209 (fn [& _]))210 (.start)))211 #+end_src213 #+begin_src clojure :results silent214 (hello.brick-wall/brick-wall-game-run)215 #+end_src217 #+caption: the brick wall standing218 [[../images/brick-wall-standing.jpg]]220 #+caption: the brick wall after it has been knocked over by a "pok\eacute{}ball"221 [[../images/brick-wall-knocked-down.jpg]]223 * COMMENT Other Brick Games224 #+name: other-games225 #+begin_src clojure :results silent226 (ns hello.other-games227 {:author "Dylan Holmes"})228 (use 'cortex.world)229 (use 'hello.brick-wall)230 (use 'cortex.import)231 (cortex.import/mega-import-jme3)233 (defn scad [position]234 (doto (box 0.1 0.1 0.1235 :position position :name "brick"236 :material "Common/MatDefs/Misc/Unshaded.j3md"237 :texture "Textures/Terrain/BrickWall/BrickWall.jpg"238 :mass 20)239 (->240 (.getMesh)241 (.scaleTextureCoordinates (Vector2f. 1 0.5))242 )243 (-> (.getControl RigidBodyControl)244 (.setLinearVelocity (Vector3f. 0 100 0))245 )247 ;;(.setShadowMode RenderQueue$ShadowMode/Cast)248 ))251 (defn shrapnel []252 (let [node (Node. "explosion-day")]253 (dorun254 (map255 (comp #(.attachChild node %) scad)256 (for [y (range 15)257 x (range 4)258 z (range 1)]259 (Vector3f.260 (+ (* 2 x brick-height)261 (if (even? (+ y z)) (/ brick-height 4) (/ brick-height -4)))262 (+ (* brick-height (inc (* 2 y))))263 (* 2 z brick-height) ))))264 node))267 (def domino-height 0.48)268 (def domino-thickness 0.12)269 (def domino-width 0.24)271 (def domino-thickness 0.05)272 (def domino-width 0.5)273 (def domino-height 1)275 (defn domino276 ([position]277 (domino position (Quaternion/IDENTITY)))278 ([position rotation]279 (doto (box domino-width domino-height domino-thickness280 :position position :name "domino"281 :material "Common/MatDefs/Misc/Unshaded.j3md"282 :texture "Textures/Terrain/BrickWall/BrickWall.jpg"283 :mass 1284 :rotation rotation)285 (.setShadowMode RenderQueue$ShadowMode/CastAndReceive)286 )))289 (defn domino-row []290 (let [node (Node. "domino-row")]291 (dorun292 (map293 (comp #(.attachChild node %) domino)294 (for [295 z (range 10)296 x (range 5)297 ]298 (Vector3f.299 (+ (* z domino-width) (* x 5 domino-width))300 (/ domino-height 1)301 (* -5.5 domino-thickness z) ))))303 node))305 (defn domino-cycle []306 (let [node (Node. "domino-cycle")]307 (dorun308 (map309 (comp #(.attachChild node %) (partial apply domino) )310 (for [n (range 720)]311 (let [space (* domino-height 5.5)312 r (fn[n] (* (+ n 3) domino-width 0.5))313 t (fn[n] (reduce314 +315 (map316 (fn dt[n] (/ space (* 2 (Math/PI) (r n))))317 (range n))))318 t (t n)319 r (r n)320 ct (Math/cos t)321 st (Math/sin t)322 ]323 (list324 (Vector3f.325 (* -1 r st)326 (/ domino-height 1)327 (* r ct))328 (.fromAngleAxis (Quaternion.)329 (- (/ 3.1415926 2) t) (Vector3f. 0 1 0))330 )))331 ))332 node))335 (defn domino-game-run []336 (doto337 (world338 (doto (Node.) (.attachChild (floor*))339 )340 {"key-i" (gravity-toggle (Vector3f. 0 0 -9.81))341 "key-m" (gravity-toggle (Vector3f. 0 0 9.81))342 "key-l" (gravity-toggle (Vector3f. 9.81 0 0))343 "key-j" (gravity-toggle (Vector3f. -9.81 0 0))344 "key-k" (gravity-toggle (Vector3f. 0 9.81 0) )345 "key-u" (fn[g v] ((gravity-toggle (Vector3f. 0 -0 0)) g true))346 "key-o" (gravity-toggle (Vector3f. 0 -9.81 0))348 "key-space"349 (fn[game value]351 (if (not value)352 (let [d (domino (Vector3f. 0 (/ domino-height 0.25) 0)353 (.fromAngleAxis (Quaternion.)354 (/ Math/PI 2) (Vector3f. 0 1 0)))]355 (add-element game d))))356 "key-f"357 (fn[game value](if (not value) (add-element game (domino-cycle))))358 "key-return" (fire-cannon-ball)}359 position-camera360 (fn [& _]))361 (.start)))362 #+end_src364 #+begin_src clojure :results silent365 (cortex.other-games/domino-game-run)366 #+end_src368 #+caption: floating dominos369 [[../images/dominos.jpg]]371 * Hello Loop372 #+name: hello-loop373 #+begin_src clojure :results silent374 (ns hello.loop375 (:use cortex.world)376 (:use cortex.util)377 (:import com.jme3.math.ColorRGBA)378 (:import com.jme3.scene.Node))380 (defn blue-cube []381 (box 1 1 1382 :color ColorRGBA/Blue383 :texture false384 :material "Common/MatDefs/Misc/Unshaded.j3md"385 :name "blue-cube"386 :physical? false))388 (defn blue-cube-game []389 (let [cube (blue-cube)390 root (doto (Node.) (.attachChild cube))]391 (world root392 {}393 no-op394 (fn [game tpf]395 (.rotate cube 0.0 (* 2 tpf) 0.0)))))396 #+end_src398 * COMMENT Hello Collision400 #+name: hello-collision401 #+begin_src clojure :results silent402 (ns hello.collision)403 (use 'cortex.world)404 (use 'cortex.import)405 (use 'clojure.contrib.def)408 (cortex.import/mega-import-jme3)409 (rlm.rlm-commands/help)410 (use '[hello [brick-wall :only [fire-cannon-ball brick-wall*]]])413 (defn environment []414 (let415 [scene-model416 (doto417 (.loadModel418 (doto (asset-manager)419 (.registerLocator420 "/home/r/cortex/assets/zips/town.zip" ZipLocator))421 "main.scene")422 (.setLocalScale (float 2.0)))423 collision-shape424 (CollisionShapeFactory/createMeshShape #^Node scene-model)425 landscape (RigidBodyControl. collision-shape 0)]426 (.setShadowMode scene-model RenderQueue$ShadowMode/CastAndReceive)427 (.addControl scene-model landscape)428 scene-model))430 (defn player-fn []431 (doto432 (CharacterControl.433 (CapsuleCollisionShape. (float 1.5) (float 6)(float 1))434 (float 0.05))435 (.setJumpSpeed 20)436 (.setFallSpeed 30)437 (.setGravity 30) ;30438 (.setPhysicsLocation (Vector3f. 0 10 0))))440 (defn lights []441 [(doto (AmbientLight.) (.setColor (.mult (ColorRGBA. 1 1 1 1) (float 1))))442 (doto (AmbientLight.) (.setColor (.mult (ColorRGBA. 1 0.7 0 1) (float 1))))443 (doto (DirectionalLight.)444 (.setColor (.mult ColorRGBA/White (float 0.9) ))445 (.setDirection (.normalizeLocal (Vector3f. 2.8 -28 2.8))))])447 (defn night-lights []448 [(doto (AmbientLight.) (.setColor (.mult (ColorRGBA. 0.275 0.467 0.784 1) (float 0.3))))449 (doto (DirectionalLight.)450 (.setColor (.mult ColorRGBA/White (float 0.2) ))451 (.setDirection (.normalizeLocal (Vector3f. 2.8 -28 2.8))))])453 (def player (atom (player-fn)))455 (defn setup-fn [game]456 (dorun (map #(.addLight (.getRootNode game) %) (lights)))457 ;; set the color of the sky458 (.setBackgroundColor (.getViewPort game) (ColorRGBA. 0.3 0.4 0.9 1))459 ;(.setBackgroundColor (.getViewPort game) (ColorRGBA. 0 0 0 1)460 (doto (.getFlyByCamera game)461 (.setMoveSpeed (float 100))462 (.setRotationSpeed 3))463 (.add464 (.getPhysicsSpace465 (.getState (.getStateManager game) BulletAppState))466 @player)468 (doto (Node.) (.attachChild (.getRootNode game))469 (.attachChild (brick-wall*))470 )472 )475 (def walking-up? (atom false))476 (def walking-down? (atom false))477 (def walking-left? (atom false))478 (def walking-right? (atom false))480 (defn set-walk [walk-atom game value]481 ;;(println-repl "setting stuff to " value)482 (reset! walk-atom value))484 (defn responses []485 {"key-w" (partial set-walk walking-up?)486 "key-d" (partial set-walk walking-right?)487 "key-s" (partial set-walk walking-down?)488 "key-a" (partial set-walk walking-left?)489 "key-return" (fire-cannon-ball)490 "key-space" (fn [game value] (.jump @player))491 })493 (defn update-fn494 [game tpf]495 (let [camera (.getCamera game)496 cam-dir (.multLocal497 (.clone498 (.getDirection camera)) (float 0.6))499 cam-left (.multLocal500 (.clone501 (.getLeft camera)) (float 0.4))502 walk-direction (Vector3f. 0 0 0)]504 (cond505 @walking-up? (.addLocal walk-direction cam-dir)506 @walking-right? (.addLocal walk-direction (.negate cam-left))507 @walking-down? (.addLocal walk-direction (.negate cam-dir))508 @walking-left? (.addLocal walk-direction cam-left))509 (.setWalkDirection @player walk-direction)510 (.setLocation camera (.getPhysicsLocation @player))))512 (defn run-game []513 (.start514 (world (environment)515 (responses)516 setup-fn517 update-fn)))518 #+end_src520 * COMMENT Hello Terrain521 #+name: hello-terrain522 #+begin_src clojure :results silent523 (ns hello.terrain)524 (use 'cortex.world)525 (use 'cortex.import)526 (use 'clojure.contrib.def)527 (import jme3tools.converters.ImageToAwt)530 (cortex.import/mega-import-jme3)531 (rlm.rlm-commands/help)532 (use '[hello [brick-wall :only [fire-cannon-ball brick-wall*]]])535 (defn setup-fn [type game]536 (.setMoveSpeed (.getFlyByCamera game) 50)537 (.setFrustumFar (.getCamera game) 10000)538 (let [env (environment type)539 cameras [(.getCamera game)]540 control (TerrainLodControl. env cameras)]541 ;;(.addControl env control)542 (.attachChild (.getRootNode game) env)))544 (defn environment [type]545 (let546 [mat_terrain547 (Material. (asset-manager) "Common/MatDefs/Terrain/Terrain.j3md")548 grass (.loadTexture (asset-manager) "Textures/Terrain/splat/grass.jpg")549 dirt (.loadTexture (asset-manager) "Textures/Terrain/splat/dirt.jpg")550 rock (.loadTexture (asset-manager) "Textures/Terrain/splat/road.jpg")551 heightmap-image (.loadTexture (asset-manager)552 ({:mountain "Textures/Terrain/splat/mountains512.png"553 :fortress "Textures/Terrain/splat/fortress512.png"554 }type))555 heightmap (ImageBasedHeightMap.556 (ImageToAwt/convert (.getImage heightmap-image) false true 0))557 terrain (do (.load heightmap)558 (TerrainQuad. "my terrain" 65 513 (.getHeightMap heightmap)))559 ]561 (dorun (map #(.setWrap % Texture$WrapMode/Repeat)562 [grass dirt rock]))564 (doto mat_terrain565 (.setTexture "Tex1" grass)566 (.setFloat "Tex1Scale" (float 64))568 (.setTexture "Tex2" dirt)569 (.setFloat "Tex2Scale" (float 32))571 (.setTexture "Tex3" rock)572 (.setFloat "Tex3Scale" (float 128))574 (.setTexture "Alpha"575 (.loadTexture576 (asset-manager)577 ({:mountain "Textures/Terrain/splat/alphamap.png"578 :fortress "Textures/Terrain/splat/alphamap2.png"} type))))580 (doto terrain581 (.setMaterial mat_terrain)582 (.setLocalTranslation 0 -100 0)583 (.setLocalScale 2 1 2))))587 (defn run-terrain-game [type]588 (.start589 (world590 (Node.)591 {}592 (partial setup-fn type)593 no-op)))594 #+end_src598 #+name: hello-animation599 #+begin_src clojure :results silent600 (ns hello.animation)601 (use 'cortex.world)602 (use 'cortex.import)603 (use 'clojure.contrib.def)604 (cortex.import/mega-import-jme3)605 (rlm.rlm-commands/help)606 (use '[hello [collision :only [lights]]])608 (defn stand609 [channel]610 (doto channel611 (.setAnim "stand" (float 0.5))612 (.setLoopMode LoopMode/DontLoop)613 (.setSpeed (float 1))))615 (defn anim-listener []616 (proxy [AnimEventListener] []617 (onAnimChange618 [control channel animation-name]619 (println-repl "RLM --- onAnimChange"))620 (onAnimCycleDone621 [control channel animation-name]622 (if (= animation-name "Walk")623 (stand channel)624 ))))626 (defn setup-fn [channel game]627 (dorun (map #(.addLight (.getRootNode game) %) (lights)))628 ;; set the color of the sky629 (.setBackgroundColor (.getViewPort game) (ColorRGBA. 0.3 0.4 0.9 1))630 ;(.setBackgroundColor (.getViewPort game) (ColorRGBA. 0 0 0 1)631 (.setAnim channel "stand")632 (doto (.getFlyByCamera game)633 (.setMoveSpeed (float 10))634 (.setRotationSpeed 1)))636 (defn walk [channel]637 (println-repl "zzz")638 (doto channel639 (.setAnim "Walk" (float 0.5))640 (.setLoopMode LoopMode/Loop)))643 (defn key-map [channel]644 {"key-space" (fn [game value]645 (if (not value)646 (walk channel)))})648 (defn player []649 (let [model (.loadModel (asset-manager) "Models/Oto/Oto.mesh.xml")650 control (.getControl model AnimControl)]651 (.setLocalScale model (float 0.5))652 (.clearListeners control)653 (.addListener control (anim-control))654 model))658 (defn run-anim-game []659 (let [ninja (player)660 control (.getControl ninja AnimControl)661 channel (.createChannel control)]662 (.start663 (world664 ninja665 (key-map channel)666 (partial setup-fn channel)667 no-op))))668 #+end_src670 * COMMENT Hello Materials671 #+name: material672 #+begin_src clojure :results silent673 (ns hello.material)674 (use 'cortex.world)675 (use 'cortex.import)676 (use 'cortex.util)677 (use 'clojure.contrib.def)678 (cortex.import/mega-import-jme3)679 (rlm.rlm-commands/help)681 (defn simple-cube []682 (box 1 1 1683 :position (Vector3f. -3 1.1 0)684 :material "Common/MatDefs/Misc/Unshaded.j3md"685 :texture "Interface/Logo/Monkey.jpg"686 :physical? false))688 (defn leaky-box []689 (box 1 1 1690 :position (Vector3f. 3 -1 0)691 :material "Common/MatDefs/Misc/ColoredTextured.j3md"692 :texture "Textures/ColoredTex/Monkey.png"693 :color (ColorRGBA. 1 0 1 1)694 :physical? false))696 (defn transparent-box []697 (doto698 (box 1 1 0.1699 :position Vector3f/ZERO700 :name "window frame"701 :material "Common/MatDefs/Misc/Unshaded.j3md"702 :texture "Textures/ColoredTex/Monkey.png"703 :physical? false)704 (-> (.getMaterial)705 (.getAdditionalRenderState)706 (.setBlendMode RenderState$BlendMode/Alpha))707 (.setQueueBucket RenderQueue$Bucket/Transparent)))709 (defn bumpy-sphere []710 (doto711 (sphere 2712 :position (Vector3f. 0 2 -2)713 :name "Shiny rock"714 :material "Common/MatDefs/Light/Lighting.j3md"715 :texture false716 :physical? false)717 (-> (.getMesh)718 (doto719 (.setTextureMode Sphere$TextureMode/Projected)720 (TangentBinormalGenerator/generate)))721 (-> (.getMaterial)722 (doto723 (.setTexture "DiffuseMap"724 (.loadTexture (asset-manager)725 "Textures/Terrain/Pond/Pond.jpg"))726 (.setTexture "NormalMap"727 (.loadTexture (asset-manager)728 "Textures/Terrain/Pond/Pond_normal.png"))729 (.setFloat "Shininess" (float 5))))730 (.rotate (float 1.6) 0 0)))733 (defn start-game []734 (.start735 (world736 (let [root (Node.)]737 (dorun (map #(.attachChild root %)738 [(simple-cube) (leaky-box) (transparent-box) (bumpy-sphere)]))739 root)740 {}741 (fn [world]742 (let [sun (doto (DirectionalLight.)743 (.setDirection (.normalizeLocal (Vector3f. 1 0 -2)))744 (.setColor ColorRGBA/White))]745 (.addLight (.getRootNode world) sun)))746 no-op747 )))748 #+end_src752 * COMMENT code generation754 #+begin_src clojure :tangle ../src/hello/brick_wall.clj755 <<brick-wall-header>>756 <<brick-wall-body>>757 #+end_src759 #+begin_src clojure :tangle ../src/hello/hello_simple_app.clj760 <<hello-simple-app>>761 #+end_src763 #+begin_src clojure :tangle ../src/hello/hello_simpler_app.clj764 <<hello-simpler-app>>765 #+end_src768 #+begin_src clojure :tangle ../src/hello/other_games.clj769 <<other-games>>770 #+end_src772 #+begin_src clojure :tangle ../src/hello/loop.clj773 <<hello-loop>>774 #+end_src776 #+begin_src clojure :tangle ../src/hello/collision.clj777 <<hello-collision>>778 #+end_src780 #+begin_src clojure :tangle ../src/hello/terrain.clj781 <<hello-terrain>>782 #+end_src784 #+begin_src clojure :tangle ../src/hello/animation.clj785 <<hello-animation>>786 #+end_src788 #+begin_src clojure :tangle ../src/hello/material.clj789 <<material>>790 #+end_src