Skip to content

Commit 32645ad

Browse files
committed
initial code
1 parent 1c232bf commit 32645ad

File tree

6 files changed

+307
-0
lines changed

6 files changed

+307
-0
lines changed

.gitignore

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/target
2+
/classes
3+
/checkouts
4+
pom.xml
5+
pom.xml.asc
6+
*.jar
7+
*.class
8+
/.lein-*
9+
/.nrepl-port
10+
.hgignore
11+
.hg/
12+
13+
*.iml
14+
/.idea/**
15+
16+
.rebel_readline_history
17+
/.cpcache/**

deps.edn

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{:deps {org.clojure/clojure {:mvn/version "1.9.0"}
2+
play-cljs {:git/url "https://github.com/oakes/play-cljs"
3+
:sha "3f3c665bc5f47a6195ad64cd354bbba1d984a013"}
4+
com.bhauman/figwheel-main {:mvn/version "0.1.9"}
5+
com.bhauman/rebel-readline-cljs {:mvn/version "0.1.4"}}
6+
:paths ["src" "target" "resources"]
7+
:aliases {:build-dev {:main-opts ["-m" "figwheel.main" "-b" "dev" "-r"]}}}

dev.cljs.edn

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{:main schlang.core}

project.clj

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
(defproject schlang "0.1.0-SNAPSHOT"
2+
:description "FIXME: write description"
3+
:url "http://example.com/FIXME"
4+
:license {:name "Eclipse Public License"
5+
:url "http://www.eclipse.org/legal/epl-v10.html"}
6+
:main ^:skip-aot schlang.core
7+
:target-path "target/%s"
8+
:profiles {:uberjar {:aot :all}}
9+
10+
:plugins [[lein-tools-deps "0.4.1"]]
11+
:middleware [lein-tools-deps.plugin/resolve-dependencies-with-deps-edn]
12+
:lein-tools-deps/config {:config-files [:install :user :project]})

resources/public/index.html

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="UTF-8">
5+
</head>
6+
<body>
7+
<div id="app">
8+
</div>
9+
<script src="cljs-out/dev-main.js" type="text/javascript"></script>
10+
</body>
11+
</html>

src/schlang/core.cljs

+259
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
(ns schlang.core
2+
(:require [play-cljs.core :as p]))
3+
4+
(enable-console-print!)
5+
6+
(declare menu-screen main-screen)
7+
8+
(def initial-state (let [x 12
9+
y 12
10+
x2 (int (/ x 2))]
11+
{:width 500
12+
:height 500
13+
:speed 400
14+
:game {:width x
15+
:height y
16+
:score 0
17+
:food [[x2 1]]}
18+
:snake {:body [[x2 (-> y dec dec dec)]
19+
[x2 (-> y dec dec)]
20+
[x2 (-> y dec)]]
21+
:eaten false}
22+
:player {:key-pressed :none
23+
:direction :up}}))
24+
25+
(defonce *state (atom initial-state))
26+
27+
(defonce game (let [width (:width @*state)
28+
height (:height @*state)]
29+
(p/create-game width height)))
30+
31+
(defn next-direction [direction key-pressed]
32+
(let [ctrl {:right {:up :right
33+
:right :down
34+
:down :left
35+
:left :up}
36+
:left {:up :left
37+
:left :down
38+
:down :right
39+
:right :up}}]
40+
(if (#{:up :right :down :left} key-pressed)
41+
(-> ctrl key-pressed direction)
42+
direction)))
43+
44+
(defn next-position [[x y] direction]
45+
(let [state @*state
46+
width (-> state :game :width)
47+
height (-> state :game :height)
48+
assumed-position (case direction
49+
:up [x (dec y)]
50+
:down [x (inc y)]
51+
:left [(dec x) y]
52+
:right [(inc x) y])
53+
position-checked-x (let [[new-x new-y] assumed-position]
54+
(cond (>= new-x width) [0 new-y]
55+
(< new-x 0) [(dec width) new-y]
56+
:default assumed-position))
57+
position-checked-y (let [[new-x new-y] position-checked-x]
58+
(cond (>= new-y height) [new-x 0]
59+
(< new-y 0) [new-x (dec height)]
60+
:default position-checked-x))]
61+
position-checked-y))
62+
63+
#_(events/listen js/window "mousedown" (fn []))
64+
65+
(defn new-food [s]
66+
(let [width (-> s :game :width)
67+
height (-> s :game :height)
68+
points (repeatedly (fn [] [(rand-int width) (rand-int height)]))
69+
occupied (reduce into #{} [(-> s :game :food) (-> s :snake :body)])]
70+
(some #(if (not (occupied %))
71+
%)
72+
points)))
73+
74+
(defn check-food [s]
75+
(let [food (into #{} (-> s :game :food))
76+
body (-> s :snake :body)
77+
head (first body)
78+
eat (food head)]
79+
(if eat
80+
(-> s
81+
(update-in [:game :food] (fn [food] (remove #(= % head) food)))
82+
(update-in [:game :food] #(conj % (new-food s)))
83+
(assoc-in [:snake :eaten] true))
84+
s)))
85+
86+
(defn step []
87+
(let [state @*state
88+
old-direction (-> state :player :direction)
89+
key-pressed (-> state :player :key-pressed)
90+
new-direction (next-direction old-direction key-pressed)
91+
old-body (-> state :snake :body)
92+
old-head (first old-body)
93+
new-head (next-position old-head new-direction)
94+
eaten (-> state :snake :eaten)
95+
new-body (into [new-head] (if eaten
96+
old-body
97+
(drop-last old-body)))
98+
lost (not (apply distinct? new-body))]
99+
(if lost
100+
(p/set-screen game menu-screen)
101+
(swap! *state
102+
(fn [state]
103+
(if lost
104+
initial-state
105+
(-> state
106+
(assoc-in [:snake :body] new-body)
107+
(assoc-in [:player :direction] new-direction)
108+
(assoc-in [:snake :eaten] false)
109+
(assoc-in [:player :key-pressed] :move-executed)
110+
check-food)))))))
111+
112+
; define a screen, where all the action takes place
113+
(def main-screen
114+
(reify p/Screen
115+
116+
; runs when the screen is first shown
117+
(on-show [this]
118+
(reset! *state initial-state)
119+
(swap! *state (fn [s]
120+
(-> s
121+
(update-in [:timeoutid]
122+
(fn [_]
123+
(js/setInterval
124+
step
125+
(:speed s))))))))
126+
127+
; runs when the screen is hidden
128+
(on-hide [this]
129+
(js/clearInterval (:timeoutid @*state)))
130+
131+
; runs every time a frame must be drawn (about 60 times per sec)
132+
(on-render [this]
133+
(p/render game
134+
(let [state @*state
135+
width (:width state)
136+
height (:height state)
137+
game-width (-> state :game :width)
138+
game-height (-> state :game :height)
139+
tile-width (/ width game-width)
140+
tile-height (/ height game-height)
141+
body (-> state :snake :body)
142+
part-of-body (into #{} body)
143+
food (into #{} (-> state :game :food))]
144+
[[:stroke {:color "gray"}
145+
(for [x (range game-width) y (range game-height)]
146+
[:fill {:color (cond (= [x y] (first body)) "darkgray"
147+
(part-of-body [x y]) "gray"
148+
(food [x y]) "lightgreen"
149+
:default "lightblue")}
150+
[:rect {:x (* x tile-width)
151+
:y (* y tile-height)
152+
:width tile-width
153+
:height tile-height}
154+
(cond (= [x y] (first body))
155+
(let [old-direction (-> state :player :direction)
156+
key-pressed (-> state :player :key-pressed)
157+
new-direction (next-direction old-direction key-pressed)
158+
eye-width (/ tile-width 4)
159+
eye-height (/ tile-width 4)]
160+
[:fill {:color "red"}
161+
[:rect {:x (case new-direction
162+
:left 0
163+
:right (- tile-width eye-width)
164+
(- (/ tile-width 4) (/ eye-width 2)))
165+
:y (case new-direction
166+
:up 0
167+
:down (- tile-height eye-height)
168+
(- (/ tile-height 4) (/ eye-height 2)))
169+
:height eye-height
170+
:width eye-width}]
171+
[:rect {:x (case new-direction
172+
:left 0
173+
:right (- tile-width eye-width)
174+
(- (* 3 (/ tile-width 4)) (/ eye-width 2)))
175+
:y (case new-direction
176+
:up 0
177+
:down (- tile-height eye-height)
178+
(- (* 3 (/ tile-height 4)) (/ eye-height 2)))
179+
:height eye-height
180+
:width eye-width}]])
181+
(food [x y])
182+
(let [eye-width (/ tile-width 4)
183+
eye-height (/ tile-width 4)]
184+
[:fill {:color "green"}
185+
[:rect {:x (+ (- (/ tile-width 4) (/ eye-width 2))
186+
(* (rand) (/ eye-width 4)))
187+
:y (+ (- (/ tile-height 4) (/ eye-height 2))
188+
(* (rand) (/ eye-width 4)))
189+
:height eye-height
190+
:width eye-width}]
191+
[:rect {:x (+ (- (* 3 (/ tile-width 4)) (/ eye-width 2))
192+
(* (rand) (/ eye-width 4)))
193+
:y (+ (- (/ tile-height 4) (/ eye-height 2))
194+
(* (rand) (/ eye-height 4)))
195+
:height eye-height
196+
:width eye-width}]]))]])]]))
197+
(let [old-key (-> @*state :player :key-pressed)
198+
pressed-keys (p/get-pressed-keys game)]
199+
(swap! *state (fn [s]
200+
(cond (= old-key :move-executed) (if (empty? pressed-keys)
201+
(assoc-in s [:player :key-pressed] :none)
202+
s)
203+
(empty? pressed-keys) s
204+
;(pressed-keys 87) (update :text-y dec) ;up
205+
(= pressed-keys #{68}) (assoc-in s [:player :key-pressed] :right)
206+
;(pressed-keys 83) (update :text-y inc) ;down
207+
(= pressed-keys #{65}) (assoc-in s [:player :key-pressed] :left)
208+
:default (assoc-in s [:player :key-pressed] :none))))))))
209+
210+
#_(if (= (first body) [x y])
211+
(let [direction (-> state :player :direction)]
212+
[:fill {:color "red"}
213+
[:rect {:x (+ (* x tile-width)
214+
(/ tile-width 3))
215+
:y (+ (* y tile-height)
216+
(/ tile-height 3))
217+
:width tile-width
218+
:height tile-height}]]))
219+
220+
#_[:fill {:color "black"}
221+
[:text {:value (str "Hello, world!" (p/get-pressed-keys game))
222+
:x (:text-x state)
223+
:y (:text-y state)
224+
:size 16
225+
:font "Georgia"
226+
:style :italic}]]
227+
228+
(def menu-screen
229+
(reify p/Screen
230+
231+
; runs when the screen is first shown
232+
(on-show [this])
233+
234+
; runs when the screen is hidden
235+
(on-hide [this])
236+
237+
; runs every time a frame must be drawn (about 60 times per sec)
238+
(on-render [this]
239+
(p/render game
240+
[[:fill {:color "lightblue"}
241+
[:rect {:x 0 :y 0 :width 500 :height 500}]]
242+
[:fill {:color "black"}
243+
[:text {:value (str "press any button to start!")
244+
:x (/ (:width @*state) 4)
245+
:y (/ (:height @*state) 2)
246+
:size 16
247+
:font "Georgia"
248+
:style :italic}]]])
249+
(let [pressed-keys (p/get-pressed-keys game)]
250+
(if (empty? pressed-keys)
251+
nil
252+
(p/set-screen game main-screen))))))
253+
254+
255+
; start the game
256+
(comment
257+
(doto game
258+
(p/start)
259+
(p/set-screen menu-screen)))

0 commit comments

Comments
 (0)