summary history branches tags files
tempest/tempest.cljs
;;
;; This file is part of tempest-cljs
;; Copyright (c) 2012, Trevor Bentley
;; All rights reserved.
;; See LICENSE file for details.
;;

(ns ^{:doc "
Publicly exported functions to embed Tempest game in HTML.
"}
  tempest
  (:require [tempest.levels :as levels]
            [tempest.draw :as draw]
            [tempest.core :as c]
            [goog.dom :as dom]
            [goog.events :as events]
            [goog.events.KeyHandler :as key-handler]))

;; ## Design notes:
;;
;;  * Nearly everything is defined with polar coordinates (length and angle)
;;  * "Entities" are players, enemies, projectiles
;;  * "Entities" are defined by a path, a series of polar coordinates, that
;;    are in relation to the previous point in the path.
;;  * Polar coordinates are converted to cartesian coordinates shortly before
;;    drawing.
;;  * Levels have a number of "steps" defined, which is how many occupiable
;;    points the level has (instead of allowing continuous motion).
;;  * An entity's location in the level is dictated by its current segment,
;;    and which step of the level it's on.
;;  * An entity has a "stride", which is how many steps it moves per update.
;;    The sign of the stride is direction, with positive strides moving out
;;    towards the player.
;;
;; ## Obscure design oddities:
;;
;;  * draw-path can optionally follow, but not draw, the first line of an
;;    entity's path.  There is a crazy reason for this.  The 'center' of
;;    an entity when drawn ends up being the first point drawn.  The first
;;    vertex is the one that gets centered on its location on the board. If
;;    the needs to be centered around a point that is not drawn (or just
;;    not its first point), the first, undrawn line given to draw-path
;;    can be a line from where the entity's center should be to its first
;;    drawn vertex.  An example is the player's ship, whose first vertex
;;    is it's "rear thruster", but who's origin when drawing must be up
;;    in the front center of the ship.
;;
;;
;; ## TODO:
;;
;;   * MOAR ENEMIES
;;   * Jump?  Is that possible with this design?  I think so, easily, by
;;     scaling just the first, undrawn line of player.  It ends up being
;;     normal to the segment's top line.
;;   * Power ups.  Bonus points if they're crazy swirly particle things.
;;   * Browser + keyboard input stuff
;;     - Any way to change repeat rate?  Probably not
;;     - Any way to use the mouse?
;;     - I'm not above making a custom rotary controller.
;;     - Two keys at the same time?  Gotta swirl-n-shoot.
;;   * Rate-limit bullets
;;   * Frame timing, and disassociate movement speed from framerate.
;;

(defn enemy-on-each-segment
  "List of enemies, one per segment."
  [level]
  (map #(c/build-flipper level % :step 0)
       (range (count (:segments level)))))

(defn ^:export canvasDraw
  "Begins a game of tempest.  'level' specified as a string representation
   of an integer."
  [level-str]
  (let [document (dom/getDocument)
        level-idx (- (js/parseInt level-str) 1)
        canvas (dom/getElement "canv-fg")
        context (.getContext canvas "2d")
        bgcanvas (dom/getElement "canv-bg")
        bgcontext (.getContext bgcanvas "2d")
        handler (goog.events.KeyHandler. document true)
        dims {:width (.-width canvas) :height (.-height canvas)}]

    (events/listen handler "key" (fn [e] (c/queue-keypress e)))

    (let [empty-game-state (c/build-game-state)
          game-state (c/change-level
                      (assoc empty-game-state
                        :context context
                        :bgcontext bgcontext
                        :dims dims
                        :anim-fn (c/animationFrameMethod)
                        :enemy-list )
                      level-idx)]
      (c/next-game-state game-state))))