on master help sign in
Changed type signature of JSON.fromString; added multiplayer mario example
40c1cfaJohn P Mayer Jr
.gitignore+2−1
@@ -11,4 +11,5 @@ cabal-dev
11/Examples/elm-js/Redirect/Redirect.html
11/Examples/elm-js/Redirect/Redirect.html
12/Examples/elm-js/Form/Form.html
12/Examples/elm-js/Form/Form.html
13/Examples/elm-js/FrameRate/FrameRate.html
13/Examples/elm-js/FrameRate/FrameRate.html
14−/Examples/elm-js/Maps/Map.html
14+/Examples/elm-js/Maps/Map.html
15+elm/elm-runtime.js
Examples/mario_mp/Clicks.elmnew file+6
@@ -0,0 +1,6 @@
1+
2+module Clicks where
3+import WebSocket
4+msgs = show <~ count Mouse.clicks
5+main = asText <~ open "ws://localhost:8080/ws" msgs
6+
Examples/mario_mp/Mario.elmnew file+91
@@ -0,0 +1,91 @@
1+
2+module Mario where
3+
4+import Dict
5+import JavaScript
6+import JSON
7+import Random
8+import WebSocket
9+
10+{- INPUT -}
11+
12+jumpStep isJump obj = if isJump && obj.y == 0 then { obj | vy <- 5 } else obj
13+gravityStep t obj = { obj | vy <- if obj.y > 0 then obj.vy - t/4 else obj.vy }
14+timeStep t obj = let {x,y,vx,vy} = obj in
15+ { obj | x <- x + t * vx , y <- max 0 $ y + t * vy }
16+walkStep dir obj = { obj | vx <- dir, dir <- if | dir < 0 -> "left"
17+ | dir > 0 -> "right"
18+ | otherwise -> obj.dir }
19+
20+step t d j = timeStep t . gravityStep t . jumpStep j . walkStep d
21+
22+delta = lift (flip (/) 20) (fps 25)
23+leftRight = toFloat . .x <~ Keyboard.arrows
24+jump = (\{y} -> y > 0) <~ Keyboard.arrows
25+steps = sampleOn delta (lift3 step delta leftRight jump)
26+
27+{- LOCAL STATE -}
28+
29+initialMario = { x = 0, y = 0, vx = 0, vy = 0, dir = "right" }
30+stateSignal = foldp ($) initialMario steps
31+
32+encode obj id =
33+ castJSStringToString . (toPrettyJSString "") . JSON.fromList $
34+ [ ("id", JsonNumber id)
35+ , ("x", JsonNumber obj.x)
36+ , ("y", JsonNumber obj.y)
37+ , ("vx", JsonNumber obj.vx)
38+ , ("dir", JsonString obj.dir) ]
39+--encode obj id = show id ++ " " ++ show obj.x ++ " " ++ show obj.y
40+
41+clientID = inRange 0 99999
42+myStream = encode <~ stateSignal ~ clientID
43+
44+{- NETWORK LAYER -}
45+
46+worldMessageStream = open "ws://localhost:8080/ws" myStream
47+
48+-- :: String -> Maybe (Float, Record)
49+parsePlayer msg =
50+ case fromString msg of
51+ Nothing -> Nothing
52+ Just json ->
53+ let id = findNumber "id" json
54+ x = findNumber "x" json
55+ y = findNumber "y" json
56+ vx = findNumber "vx" json
57+ dir = findString "dir" json
58+ in Just (id, { x = x, y = y, vx = vx, vy = 0, dir = dir })
59+
60+-- :: Maybe (Float, Record) -> Dict String Record -> Dict String Record
61+updateWorldPositions maybeMario marioDict = case maybeMario of
62+ Just (id, mario) -> (Dict.insert) (show id) mario marioDict
63+ Nothing -> marioDict
64+
65+-- :: Signal (Dict String Record)
66+worldPositions = foldp updateWorldPositions Dict.empty (parsePlayer <~ worldMessageStream)
67+--worldPositions = constant empty
68+
69+marios = Dict.values <~ worldPositions
70+
71+{- RENDER CODE -}
72+
73+-- :: Record -> Form
74+mario2Form (w,h) mario =
75+ let verb = if mario.vx /= 0 then "walk" else "stand"
76+ src = "/imgs/mario/" ++ verb ++ "/" ++ mario.dir ++ ".gif"
77+ in toForm (mario.x, (h-63)-mario.y) (image 35 35 src)
78+
79+-- :: (Int,Int) -> [Record] -> Element
80+render (w,h) marios =
81+ collage w h ( (filled cyan $ rect w h (w `div` 2, h `div` 2))
82+ : (filled green $ rect w 50 (w `div` 2,h-25))
83+ : List.map (mario2Form (w,h)) marios )
84+
85+{- PUTTING IT TOGETHER -}
86+
87+-- :: Signal Element
88+main = render <~ Window.dimensions ~ marios
89+--main = above <~ ((plainText . show) <~ (marios)) ~ (render <~ Window.dimensions ~ marios)
90+--main = (plainText . show) <~ (marios)
91+
Examples/mario_mp/Object.elmnew file+8
@@ -0,0 +1,8 @@
1+
2+module Object where
3+
4+import JavaScript
5+import JSON
6+
7+main = plainText . castJSStringToString . (toPrettyJSString "") . fromList $ [ ("answer", JsonNumber 42) ]
8+
Examples/mario_mp/Values.elmnew file+7
@@ -0,0 +1,7 @@
1+
2+module Values where
3+
4+import Dict
5+
6+main = constant . plainText . show . values $ empty
7+
Examples/mario_mp/conn.gonew file+43
@@ -0,0 +1,43 @@
1+package main
2+
3+import (
4+ "code.google.com/p/go.net/websocket"
5+)
6+
7+type connection struct {
8+ // The websocket connection.
9+ ws *websocket.Conn
10+
11+ // Buffered channel of outbound messages.
12+ send chan string
13+}
14+
15+func (c *connection) reader() {
16+ for {
17+ var message string
18+ err := websocket.Message.Receive(c.ws, &message)
19+ if err != nil {
20+ break
21+ }
22+ h.broadcast <- message
23+ }
24+ c.ws.Close()
25+}
26+
27+func (c *connection) writer() {
28+ for message := range c.send {
29+ err := websocket.Message.Send(c.ws, message)
30+ if err != nil {
31+ break
32+ }
33+ }
34+ c.ws.Close()
35+}
36+
37+func wsHandler(ws *websocket.Conn) {
38+ c := &connection{send: make(chan string, 256), ws: ws}
39+ h.register <- c
40+ defer func() { h.unregister <- c }()
41+ go c.writer()
42+ c.reader()
43+}
Examples/mario_mp/elm-runtime.jsnew file+1
@@ -0,0 +1 @@
1+../../elm/elm-runtime.js
Examples/mario_mp/hub.gonew file+44
@@ -0,0 +1,44 @@
1+package main
2+
3+type hub struct {
4+ // Registered connections.
5+ connections map[*connection]bool
6+
7+ // Inbound messages from the connections.
8+ broadcast chan string
9+
10+ // Register requests from the connections.
11+ register chan *connection
12+
13+ // Unregister requests from connections.
14+ unregister chan *connection
15+}
16+
17+var h = hub{
18+ broadcast: make(chan string),
19+ register: make(chan *connection),
20+ unregister: make(chan *connection),
21+ connections: make(map[*connection]bool),
22+}
23+
24+func (h *hub) run() {
25+ for {
26+ select {
27+ case c := <-h.register:
28+ h.connections[c] = true
29+ case c := <-h.unregister:
30+ delete(h.connections, c)
31+ close(c.send)
32+ case m := <-h.broadcast:
33+ for c := range h.connections {
34+ select {
35+ case c.send <- m:
36+ default:
37+ delete(h.connections, c)
38+ close(c.send)
39+ go c.ws.Close()
40+ }
41+ }
42+ }
43+ }
44+}
Examples/mario_mp/imgs/mario/stand/left.gifnew file

Binary file not shown.

Examples/mario_mp/imgs/mario/stand/right.gifnew file

Binary file not shown.

Examples/mario_mp/imgs/mario/walk/left.gifnew file

Binary file not shown.

Examples/mario_mp/imgs/mario/walk/right.gifnew file

Binary file not shown.

Examples/mario_mp/main.gonew file+24
@@ -0,0 +1,24 @@
1+package main
2+
3+import (
4+ "code.google.com/p/go.net/websocket"
5+ "flag"
6+ "log"
7+ "net/http"
8+)
9+
10+var addr = flag.String("addr", ":8080", "http service address")
11+
12+func fileHandler(w http.ResponseWriter, r *http.Request) {
13+ http.ServeFile(w, r, r.URL.Path[1:])
14+}
15+
16+func main() {
17+ flag.Parse()
18+ go h.run()
19+ http.HandleFunc("/", fileHandler)
20+ http.Handle("/ws", websocket.Handler(wsHandler))
21+ if err := http.ListenAndServe(*addr, nil); err != nil {
22+ log.Fatal("ListenAndServe:", err)
23+ }
24+}
Examples/mario_mp/makefilenew file+19
@@ -0,0 +1,19 @@
1+all: mario_mp Mario.html Clicks.html Object.html Values.html
2+
3+mario_mp: *.go
4+ go build
5+
6+Mario.html: Mario.elm
7+ elm -r elm-runtime.js Mario.elm
8+
9+Clicks.html: Clicks.elm
10+ elm -r elm-runtime.js Clicks.elm
11+
12+Object.html: Object.elm
13+ elm -r elm-runtime.js Object.elm
14+
15+Values.html: Values.elm
16+ elm -r elm-runtime.js Values.elm
17+
18+clean:
19+ rm -rf *.html mario_mp
core-js/cat.sh+3−2
@@ -5,10 +5,10 @@
5cat \
5cat \
6 Guid.js\
6 Guid.js\
7 foreign/JavaScript.js\
7 foreign/JavaScript.js\
8− foreign/JSON.js\
9− Value.js\
10 List.js\
8 List.js\
11 Maybe.js\
9 Maybe.js\
10+ foreign/JSON.js\
11+ Value.js\
12 Char.js\
12 Char.js\
13 Graphics/Color.js\
13 Graphics/Color.js\
14 Graphics/Collage.js\
14 Graphics/Collage.js\
@@ -29,4 +29,5 @@ cat \
29 Dict.js\
29 Dict.js\
30 Set.js\
30 Set.js\
31 Automaton.js\
31 Automaton.js\
32+ Signal/WebSocket.js\
32 > ../elm/elm-runtime.js
33 > ../elm/elm-runtime.js
core-js/foreign/JSON.js+8−2
@@ -104,7 +104,12 @@ Elm.JSON = function() {
104 };
104 };
105 }
105 }
106 function fromJSString(str) {
106 function fromJSString(str) {
107+ var obj;
108+ try {
107− var obj = JSjson.parse(str);
109+ obj = JSjson.parse(str);
110+ } catch (e) {
111+ return Elm.Maybe.Nothing;
112+ }
108 function toValue(v) {
113 function toValue(v) {
109 switch (typeof v) {
114 switch (typeof v) {
110 case 'string' : return [ "JsonString", JS.castJSStringToString(v) ];
115 case 'string' : return [ "JsonString", JS.castJSStringToString(v) ];
@@ -122,12 +127,13 @@ Elm.JSON = function() {
122 for (var i in obj) {
127 for (var i in obj) {
123 obj[i] = toValue(obj[i]);
128 obj[i] = toValue(obj[i]);
124 }
129 }
125− return ['JSON',obj];
130+ return Elm.Maybe.Just( ['JSON',obj] );
126 }
131 }
127 return {empty : empty,
132 return {empty : empty,
128 singleton : singleton,
133 singleton : singleton,
129 insert : insert,
134 insert : insert,
130 lookup : lookup,
135 lookup : lookup,
136+ findNumber : find("JsonNumber",0),
131 findString : find("JsonString",["Nil"]),
137 findString : find("JsonString",["Nil"]),
132 findObject : find("JsonObject", empty ),
138 findObject : find("JsonObject", empty ),
133 findArray : find("JsonArray" ,["Nil"]),
139 findArray : find("JsonArray" ,["Nil"]),
elm/src/Types/Hints.hs+1−1
@@ -125,7 +125,7 @@ json = prefix "JSON"
125 , "JsonObject" -: jsonObject ==> jsonValue
125 , "JsonObject" -: jsonObject ==> jsonValue
126 , numScheme (\n -> n ==> jsonValue) "JsonNumber"
126 , numScheme (\n -> n ==> jsonValue) "JsonNumber"
127 , "toString" -: jsonObject ==> string
127 , "toString" -: jsonObject ==> string
128− , "fromString" -: string ==> jsonObject
128+ , "fromString" -: string ==> maybeOf jsonObject
129 , "lookup" -: string ==> jsonObject ==> maybeOf jsonValue
129 , "lookup" -: string ==> jsonObject ==> maybeOf jsonValue
130 , "findObject" -: string ==> jsonObject ==> jsonObject
130 , "findObject" -: string ==> jsonObject ==> jsonObject
131 , "findArray" -: string ==> jsonObject ==> listOf jsonValue
131 , "findArray" -: string ==> jsonObject ==> listOf jsonValue