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))))