summary history branches tags files
commit:3deca636149160c403314ac7233ae60461e87208
author:mrmekon
committer:mrmekon
date:Fri Mar 30 17:45:34 2012 -0400
parents:18d5f1db7368218cb40a590c0d790fd516817033
A jerk of a commit.  First of all, why do I do everything on master?  This is experimental additions to implement flipping of... flippers.  Game is currently broken, but flippers can flip to adjacent segments.  Some of these new functions are probably unused, and they aren't all documented.
diff --git a/tempest/tempest.cljs b/tempest/tempest.cljs
line changes: +31/-31
index 0f5a5e0..1853b0e
--- a/tempest/tempest.cljs
+++ b/tempest/tempest.cljs
@@ -89,37 +89,37 @@ Publicly exported functions to embed Tempest game in HTML.
                        :dims dims
                        :anim-fn (c/animationFrameMethod)
                        :enemy-list (list
-                                    (c/build-enemy level 0 :step 0)
-                                    (c/build-enemy level 8 :step 60)
-                                    (c/build-enemy level 1 :step 0)
-                                    (c/build-enemy level 1 :step 10)
-                                    (c/build-enemy level 1 :step 20)
-                                    (c/build-enemy level 1 :step 30)
-                                    (c/build-enemy level 1 :step 40)
-                                    (c/build-enemy level 1 :step 50)
-                                    (c/build-enemy level 1 :step 60)
-                                    (c/build-enemy level 1 :step 70)
-                                    (c/build-enemy level 3 :step 0)
-                                    (c/build-enemy level 3 :step 10)
-                                    (c/build-enemy level 3 :step 20)
-                                    (c/build-enemy level 3 :step 30)
-                                    (c/build-enemy level 3 :step 40)
-                                    (c/build-enemy level 3 :step 50)
-                                    (c/build-enemy level 3 :step 60)
-                                    (c/build-enemy level 3 :step 70)
-                                    (c/build-enemy level 7 :step 0)
-                                    (c/build-enemy level 7 :step 10)
-                                    (c/build-enemy level 7 :step 20)
-                                    (c/build-enemy level 7 :step 30)
-                                    (c/build-enemy level 7 :step 40)
-                                    (c/build-enemy level 7 :step 50)
-                                    (c/build-enemy level 8 :step 0)
-                                    (c/build-enemy level 8 :step 10)
-                                    (c/build-enemy level 8 :step 20)
-                                    (c/build-enemy level 8 :step 30)
-                                    (c/build-enemy level 8 :step 40)
-                                    (c/build-enemy level 8 :step 50)
-                                    (c/build-enemy level 11 :step 10)))]
+                                    (c/build-flipper level 0 :step 0)
+                                    (c/build-flipper level 8 :step 60)
+                                    (c/build-flipper level 1 :step 0)
+                                    (c/build-flipper level 1 :step 10)
+                                    (c/build-flipper level 1 :step 20)
+                                    (c/build-flipper level 1 :step 30)
+                                    (c/build-flipper level 1 :step 40)
+                                    (c/build-flipper level 1 :step 50)
+                                    (c/build-flipper level 1 :step 60)
+                                    (c/build-flipper level 1 :step 70)
+                                    (c/build-flipper level 3 :step 0)
+                                    (c/build-flipper level 3 :step 10)
+                                    (c/build-flipper level 3 :step 20)
+                                    (c/build-flipper level 3 :step 30)
+                                    (c/build-flipper level 3 :step 40)
+                                    (c/build-flipper level 3 :step 50)
+                                    (c/build-flipper level 3 :step 60)
+                                    (c/build-flipper level 3 :step 70)
+                                    (c/build-flipper level 7 :step 0)
+                                    (c/build-flipper level 7 :step 10)
+                                    (c/build-flipper level 7 :step 20)
+                                    (c/build-flipper level 7 :step 30)
+                                    (c/build-flipper level 7 :step 40)
+                                    (c/build-flipper level 7 :step 50)
+                                    (c/build-flipper level 8 :step 0)
+                                    (c/build-flipper level 8 :step 10)
+                                    (c/build-flipper level 8 :step 20)
+                                    (c/build-flipper level 8 :step 30)
+                                    (c/build-flipper level 8 :step 40)
+                                    (c/build-flipper level 8 :step 50)
+                                    (c/build-flipper level 11 :step 10)))]
       (c/next-game-state game-state))))
 
     

diff --git a/tempest/tempest/core.cljs b/tempest/tempest/core.cljs
line changes: +89/-6
index 424a260..efe7331
--- a/tempest/tempest/core.cljs
+++ b/tempest/tempest/core.cljs
@@ -46,6 +46,7 @@ after passing through all the other functions.  This implements the game loop.
        remove-collided-entities
        update-projectile-locations
        update-enemy-locations
+       update-enemy-flippyness
        update-frame-count
        maybe-render-fps-display
        schedule-next-frame
@@ -65,6 +66,12 @@ after passing through all the other functions.  This implements the game loop.
    :path-fn path/projectile-path-on-level
    })
 
+(def DirectionEnum {"NONE" 0 "CW" 1 "CCW" 2})
+
+(defn direction-string-from-value
+  [val]
+  (first (first (filter #(= 1 (peek %)) (into [] maptest)))))
+
 (defn build-enemy
   "Returns a dictionary describing an enemy on the given level and segment,
    and starting on the given step.  Step defaults to 0 (innermost step of
@@ -73,12 +80,88 @@ after passing through all the other functions.  This implements the game loop.
   {:step step
    :stride 1
    :segment seg-idx
-   :path-fn path/flipper-path-on-level
    :level level
    :hits-remaining 1
-   :bounding-fn path/flipper-path-bounding-box
+   :path-fn #([])
+   :bounding-fn #(identity 0)
+
+    :flip-dir (DirectionEnum "NONE")
+    :flip-point [0 0]
+    :flip-stride 1
+    :flip-max-angle 0
+    :flip-cur-angle 0
    })
 
+(defn build-flipper
+  [level seg-idx & {:keys [step] :or {step 0}}]
+  (assoc (build-enemy level seg-idx :step step)
+    :bounding-fn path/flipper-path-bounding-box
+    :path-fn path/flipper-path-on-level
+    :flip-dir (DirectionEnum "NONE")
+    :flip-point [0 0]
+    :flip-stride 1
+    :flip-max-angle 0
+    :flip-cur-angle 0
+    ))
+
+(defn mark-flipper-for-flipping
+  [flipper direction stride seg-idx cw?]
+  (assoc flipper
+    :stride 0
+    :flip-dir (DirectionEnum direction)
+    :flip-stride stride
+    :flip-cur-angle 0
+    :flip-point (path/flip-point-between-segments
+                 (:level flipper)
+                 (:segment flipper)
+                 seg-idx
+                 (:step flipper)
+                 cw?)
+    :flip-max-angle (path/flip-angle-between-segments
+                     (:level flipper)
+                     (:segment flipper)
+                     seg-idx
+                     cw?)))
+
+(defn random-direction-string
+  []
+  (condp = (rand-int 2)
+        0 "CW"
+        "CCW"))
+
+(defn segment-for-flip-direction
+  [flipper flip-dir]
+  (condp = flip-dir
+        "CW" (segment-entity-cw flipper)
+        (segment-entity-ccw flipper)))
+
+(defn maybe-engage-flipping
+  [flipper]
+  (let [should-flip (and (= (:step flipper) 100) (= (:flip-dir flipper) (DirectionEnum "NONE")))
+        flip-dir (random-direction-string)
+        flip-seg-idx (segment-for-flip-direction flipper flip-dir)
+        cw? (= flip-dir "CW")]
+    (if (and should-flip
+             (not= flip-seg-idx (:segment flipper)))             
+      (mark-flipper-for-flipping flipper flip-dir 1 flip-seg-idx cw?)
+      flipper)))
+
+(defn consider-flipping
+  [entity-list]
+  ((fn [oldlist newlist]
+     (let [entity (first oldlist)]
+       (if (empty? entity)
+         newlist
+         (recur (rest oldlist)
+                (cons (maybe-engage-flipping entity) newlist))))
+         ) entity-list []))
+
+(defn update-enemy-flippyness
+  [game-state]
+  (let [{enemy-list :enemy-list} game-state]
+    (assoc game-state :enemy-list (consider-flipping enemy-list))))
+
+
 (defn build-player
   "Returns a dictionary describing a player on the given level and segment."
   [level seg-idx]
@@ -291,7 +374,7 @@ after passing through all the other functions.  This implements the game loop.
     (conj projectile-list
           (build-projectile level seg-idx stride :step step))))
 
-(defn segment-player-left
+(defn segment-entity-cw
   "Returns the segment to the left of the player.  Loops around the level
    on connected levels, and stops at 0 on unconnected levels."
   [player]
@@ -305,7 +388,7 @@ after passing through all the other functions.  This implements the game loop.
       new-seg)))
 
 
-(defn segment-player-right
+(defn segment-entity-ccw
   "Returns the segment to the right of the player.  Loops around the level
    on connected levels, and stops at max on unconnected levels."
   [player]
@@ -344,10 +427,10 @@ after passing through all the other functions.  This implements the game loop.
     (condp = key
       key-codes/RIGHT (assoc game-state
                         :player
-                        (assoc player :segment (segment-player-right player)))
+                        (assoc player :segment (segment-entity-ccw player)))
       key-codes/LEFT  (assoc game-state
                         :player
-                        (assoc player :segment (segment-player-left player)))
+                        (assoc player :segment (segment-entity-cw player)))
       key-codes/SPACE (assoc game-state
                         :projectile-list
                         (add-player-projectile projectile-list player))

diff --git a/tempest/tempest/draw.cljs b/tempest/tempest/draw.cljs
line changes: +40/-3
index 86ac2d7..912a1c6
--- a/tempest/tempest/draw.cljs
+++ b/tempest/tempest/draw.cljs
@@ -29,7 +29,39 @@ level functions to draw complete game entities using the primitives.
   (.moveTo context (first point0) (peek point0))
   (.lineTo context (first point1) (peek point1))
   (.stroke context))
-  
+
+(defn max-flipper-angle
+  []
+  ;; get (x0,y0) and (x1,y1) of corners of current segment
+  ;; gamma = atan2(y1-y0,x1-x0)
+  ;; theta = PI-gamma
+  )
+
+(defn draw-path-rotated
+  [context origin vecs skipfirst? point angle]
+  ;; determine x/y translate and origin offsets by difference between
+  ;; cartesian midpoint of segment and cartesian corner of segment.
+  ;;
+  ;; angle starts at 0, and ends at some angle difference between 
+  (do
+    (.save context)
+    (.translate context
+                (- (first origin) (first point))
+                (- (peek origin) (peek point)))
+    (.rotate context angle)
+    ((fn [origin vecs skip?]
+       (if (empty? vecs)
+         nil
+         (let [line (first vecs)
+               point (path/rebase-origin (path/polar-to-cartesian-coords line)
+                                         origin)]
+           (.lineTo context (first point) (peek point))
+           (recur point (next vecs) false))))
+     [(first point) (peek point)] vecs skipfirst?)
+     ;;[0 0] vecs skipfirst?)
+    (.stroke context)
+    (.restore context)
+    ))
 
 (defn draw-path
   "Draws a 'path', a vector of multiple polar coordinates, on an HTML5 2D
@@ -83,12 +115,17 @@ level functions to draw complete game entities using the primitives.
   [context dims level entity-list]
   (doseq [entity entity-list]
     (.beginPath context)
-    (draw-path context
+    (draw-path-rotated context
                (path/polar-to-cartesian-centered
                 (path/polar-entity-coord entity)
                 dims)
                (path/round-path ((:path-fn entity) entity))
-               true)
+               true
+               (:flip-point entity)
+               ;;[20 -20]
+               (:flip-max-angle entity)
+               ;;0
+               )
     (.closePath context)))
 
 (defn draw-board

diff --git a/tempest/tempest/levels.cljs b/tempest/tempest/levels.cljs
line changes: +4/-1
index 04841ab..492e20c
--- a/tempest/tempest/levels.cljs
+++ b/tempest/tempest/levels.cljs
@@ -243,6 +243,8 @@ Functions related to generating paths representing levels.
 (def *level6_lines* (vec (oblong-level [135 45 90 135 45 90 135 45 90 135 45 90
                                         135 45 90 135 45 90 135 45 90 135 45] 15 80)))
 
+(def *level7_lines* (vec (oblong-level [135 45 135 45] 15 3)))
+
 
 
 (defn make-level-entry 
@@ -263,6 +265,7 @@ Functions related to generating paths representing levels.
     (make-level-entry *level3_lines* false)
     (make-level-entry *level4_lines* false)
     (make-level-entry *level5_lines* false)
-    (make-level-entry *level6_lines* true)])
+    (make-level-entry *level6_lines* true)
+    (make-level-entry *level7_lines* false)])
 
 

diff --git a/tempest/tempest/path.cljs b/tempest/tempest/path.cljs
line changes: +107/-18
index 18a2e0e..228428e
--- a/tempest/tempest/path.cljs
+++ b/tempest/tempest/path.cljs
@@ -19,6 +19,76 @@ and 'paths' consisting of a sequence of coordinates.
   [(+ (first point1) (first point0))
    (- (peek point1) (peek point0))])
 
+(defn cartesian-edge-coordinates
+  "Returns a pair of cartesian coordinates [[x0 y0] [x1 y1]], representing
+   the points on the edges of the given segment of the given level at the
+   given step.
+
+   That is, this returns the two points at the edge of a segment between which
+   an entity would be drawn."
+  [level seg-idx step]
+  (let [edges (polar-lines-for-segment level seg-idx false)
+        edge-steps (step-lengths-for-segment-lines level seg-idx)
+        offset0 (* (first edge-steps) step)
+        offset1 (* (peek edge-steps) step)
+        point0 (polar-extend offset0 (first edges))
+        point1 (polar-extend offset1 (peek edges))]
+    [(polar-to-cartesian-coords point0)
+     (polar-to-cartesian-coords point1)]))
+
+(defn cartesian-point-between-segments
+  [level seg-idx0 seg-idx1 step]
+  (let [line (edge-line-between-segments level seg-idx0 seg-idx1)
+        line-steps (step-length-for-level-line level line)        
+        offset (* line-steps step)
+        point0 (polar-extend offset line)]
+    (polar-to-cartesian-coords point0)))
+
+
+(defn edge-line-between-segments
+  [level seg-idx0 seg-idx1]
+  (let [segs0 (get (:segments level) seg-idx0)
+        segs1 (get (:segments level) seg-idx1)
+        allsegs (flatten [segs0 segs1])]
+    (first (for [[id freq] (frequencies allsegs) :when (> freq 1)]
+             (get (:lines level) id)))))
+
+(defn flip-angle-between-segments
+  "Returns the angle, in radians, between the two given segments on the
+given level."
+  [level seg-idx-cur seg-idx-new cw?]
+  (let [angle-cur (segment-angle level seg-idx-cur)
+        angle-new (segment-angle level seg-idx-new)]
+      (- 0 (- (+ angle-new 3.14159265) angle-cur))
+  ))
+
+(defn flip-point-between-segments
+  [level seg-idx-cur seg-idx-new step cw?]
+  (let [[x0 y0] (cartesian-point-between-segments level
+                                                  seg-idx-cur
+                                                  seg-idx-new
+                                                  step)
+        [x1 y1] (polar-to-cartesian-coords
+                 (polar-segment-midpoint level seg-idx-cur step))
+        edge-points (cartesian-edge-coordinates level seg-idx-new step)]
+    (.log js/console (pr-str "Edge points: " edge-points
+                             "\nPivot point: " [x0 y0]))
+    (.log js/console (pr-str "Result: " [(- x0 x1) (- y0 y1)]))
+    [(- x1 x0) (- y0 y1)]))
+
+(comment
+(defn flip-point-between-segments
+  [level seg-idx-cur seg-idx-new step cw?]
+  (let [[x0 y0] (polar-to-cartesian-coords
+                 (polar-segment-midpoint level seg-idx-cur step))
+        [[x1 y1] [x2 y2]] (cartesian-edge-coordinates level seg-idx-new step)]
+    (.log js/console (str "CW? " (pr-str cw?) " "
+                          (pr-str [(- x0 x2) (- y2 y0)]
+                                  [(- x1 x0) (- y0 y1)])))
+    (if cw?
+      [(- x0 x2) (- y2 y0)]
+      [(- x1 x0) (- y0 y1)])))
+)
 
 (defn rebase-origin
   "Return cartesian coordinate 'point' in relation to 'origin'."
@@ -94,15 +164,32 @@ and 'paths' consisting of a sequence of coordinates.
      (polar-to-cartesian-coords line1)]
     ))
 
+(defn polar-segment-midpoint
+  "Returns current polar coordinates to the entity."
+  [level seg-idx step]
+  (let [steplen (step-length-segment-midpoint level seg-idx)
+        offset (* steplen step)
+        midpoint (segment-midpoint level seg-idx)]
+    (polar-extend offset midpoint)))
 
 (defn polar-entity-coord
   "Returns current polar coordinates to the entity."
   [entity]
+  (polar-segment-midpoint (:level entity)
+                          (:segment entity)
+                          (:step entity)))
+
+
+(comment
+  (defn polar-entity-coord
+  "Returns current polar coordinates to the entity."
+  [entity]
   (let [steplen (step-length-segment-midpoint (:level entity)
                                               (:segment entity))
         offset (* steplen (:step entity))
         midpoint (segment-midpoint (:level entity) (:segment entity))]
     (polar-extend offset midpoint)))
+  )
 
 (defn step-length-segment-midpoint
   "Finds the 'step length' of a line through the middle of a level's segment.
@@ -134,6 +221,11 @@ and 'paths' consisting of a sequence of coordinates.
      (first point1))
     (:steps level))))
 
+(defn step-length-for-level-line
+  [level line]
+  (let [longline (scale-polar-coord (:length-fn level) line)]
+    (step-length-line level line longline)))
+
 (defn step-lengths-for-segment-lines
   "Returns a vector [len0 len1] with the 'step length' for the two edge
    lines that mark the boundaries of the given segment."
@@ -334,27 +426,24 @@ and 'paths' consisting of a sequence of coordinates.
   [length path]
   (map #(polar-extend length %) path))
 
+(defn segment-angle
+  "Returns the angle (in radians) of the given segment.
+   The angle of a segment is the angle of any line projected onto it."
+  [level seg-idx]
+  (let [[point0 point1] (polar-lines-for-segment level seg-idx false)]
+    (apply js/Math.atan2
+           (vec (reverse (map - (polar-to-cartesian-coords point0)
+                              (polar-to-cartesian-coords point1)))))))
+
 (defn enemy-angle
-  "Returns the angle from origin that the enemy needs to be rotated to
-   appear in the correct orientation at its current spot on the level.
-   In reality, it returns the angle of the line that traverses the segment
-   across the midpoint of the enemy.  TODO: This should be renamed to
+  "Returns the angle (in degrees) from origin that the enemy needs to be
+   rotated to appear in the correct orientation at its current spot on the
+   level. In reality, it returns the angle of the line that traverses the
+   segment across the midpoint of the enemy.  TODO: This should be renamed to
    'entity-angle', it works with anything on the board."
   [enemy]
-  (let [edges (polar-lines-for-segment (:level enemy)
-                                       (:segment enemy)
-                                       false)
-        edge-steps (step-lengths-for-segment-lines (:level enemy)
-                                                   (:segment enemy))
-        offset0 (* (first edge-steps) (:step enemy))
-        offset1 (* (peek edge-steps) (:step enemy))
-        point0 (polar-extend offset0 (first edges))
-        point1 (polar-extend offset1 (peek edges))]
-    (util/rad-to-deg
-     (apply js/Math.atan2
-            (vec (reverse (map - (polar-to-cartesian-coords point0)
-                      (polar-to-cartesian-coords point1))))))))
-  
+  (util/rad-to-deg (segment-angle (:level enemy) (:segment enemy))))
+
 (defn entity-desired-width
   "Returns how wide the given enemy should be drawn to span the full width
    of its current location.  In reality, that means returning the length of