shank 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. data/.gitignore +22 -0
  2. data/Gemfile +3 -0
  3. data/LICENSE +22 -0
  4. data/README.md +0 -0
  5. data/Rakefile +2 -0
  6. data/lib/assets/javascripts/engine.gamepads.coffee +46 -0
  7. data/lib/assets/javascripts/engine_stats.coffee +10 -0
  8. data/lib/assets/javascripts/error_handler.coffee +11 -0
  9. data/lib/assets/javascripts/game_keys.coffee +6 -0
  10. data/lib/assets/javascripts/gamepads.coffee +21 -0
  11. data/lib/assets/javascripts/gamepads.controller.coffee +138 -0
  12. data/lib/assets/javascripts/init.coffee +6 -0
  13. data/lib/assets/javascripts/joysticks.coffee +238 -0
  14. data/lib/assets/javascripts/jquery.hotkeys.coffee +161 -0
  15. data/lib/assets/javascripts/jquery.reverse_merge.coffee +21 -0
  16. data/lib/assets/javascripts/keydown.coffee +73 -0
  17. data/lib/assets/javascripts/mouse.coffee +66 -0
  18. data/lib/assets/javascripts/music.coffee +78 -0
  19. data/lib/assets/javascripts/pixie_canvas.coffee +739 -0
  20. data/lib/assets/javascripts/request_animation_frame.coffee +22 -0
  21. data/lib/assets/javascripts/shank.coffee +18 -0
  22. data/lib/assets/javascripts/sound.coffee +131 -0
  23. data/lib/assets/javascripts/storage.coffee +88 -0
  24. data/lib/shank/version.rb +3 -0
  25. data/lib/shank.rb +10 -0
  26. data/shank.gemspec +17 -0
  27. data/test/jquery.reverse_merge.coffee +43 -0
  28. data/test/keydown.coffee +19 -0
  29. data/test/pixie_canvas.coffee +18 -0
  30. data/test/request_animation_frame.coffee +7 -0
  31. data/test/sound.coffee +7 -0
  32. data/test/storage.coffee +47 -0
  33. data/test/xstats.coffee +7 -0
  34. data/vendor/assets/javascripts/xstats.js +767 -0
  35. metadata +113 -0
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .DS_STORE
4
+ .bundle
5
+ .config
6
+ .sass-cache/
7
+ .yardoc
8
+ Gemfile.lock
9
+ InstalledFiles
10
+ _yardoc
11
+ coverage
12
+ doc/
13
+ docs/
14
+ lib/bundler/man
15
+ lib/assets/test.html
16
+ lib/assets/javascripts/cornerstone_tests.js
17
+ pkg
18
+ rdoc
19
+ spec/reports
20
+ test/tmp
21
+ test/version_tmp
22
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Daniel X. Moore
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
File without changes
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,46 @@
1
+ ###*
2
+ The <code>Gamepads</code> module gives the engine access to gamepads.
3
+
4
+ # First you need to add the `Gamepads` module to the engine
5
+ Engine.defaultModules.push "Gamepads"
6
+
7
+ window.engine = Engine
8
+ ...
9
+
10
+ # Then you need to get a controller reference
11
+ # id = 0 for player 1, etc.
12
+ controller = engine.controller(id)
13
+
14
+ # Point indicating direction primary axis is held
15
+ direction = controller.position()
16
+
17
+ # Check if buttons are held
18
+ controller.actionDown("A")
19
+ controller.actionDown("B")
20
+ controller.actionDown("X")
21
+ controller.actionDown("Y")
22
+
23
+ @name Gamepads
24
+ @fieldOf Engine
25
+ @module
26
+
27
+ @param {Object} I Instance variables
28
+ @param {Object} self Reference to the engine
29
+ ###
30
+ Engine.Gamepads = (I, self) ->
31
+ gamepads = Gamepads()
32
+
33
+ self.bind "beforeUpdate", ->
34
+ # Update the gamepads
35
+ gamepads.update()
36
+
37
+ ###*
38
+ Get a controller for a given id.
39
+
40
+ @name controller
41
+ @methodOf Engine.Gamepads#
42
+
43
+ @param {Number} index The index to get a controller for.
44
+ ###
45
+ controller: (index) ->
46
+ gamepads.controller(index)
@@ -0,0 +1,10 @@
1
+ Engine.Stats = (I={}, self) ->
2
+ stats = xStats()
3
+
4
+ $(stats.element).css
5
+ position: "absolute"
6
+ right: 0
7
+ top: 0
8
+ .appendTo("body")
9
+
10
+ return {}
@@ -0,0 +1,11 @@
1
+ ###*
2
+ This error handler captures any runtime errors and reports them to the IDE
3
+ if present.
4
+ ###
5
+ window.onerror = (message, url, lineNumber) ->
6
+ errorContext = $('script').last().text().split('\n')[(lineNumber-5)..(lineNumber+4)]
7
+
8
+ errorContext[4] = "<b style='font-weight: bold; text-decoration: underline;'>" + errorContext[4] + "</b>"
9
+
10
+ displayRuntimeError?("<code>#{message}</code> <br /><br />(Sometimes this context may be wrong.)<br /><code><pre>#{errorContext.join('\n')}</pre></code>")
11
+
@@ -0,0 +1,6 @@
1
+ (->
2
+ root = (exports ? this)
3
+
4
+ root.gameKeys = (keyMap) ->
5
+ parent.postMessage {type: 'controls', data: keyMap}, 'http://pixieengine.com'
6
+ )()
@@ -0,0 +1,21 @@
1
+ Gamepads = (I={}) ->
2
+ state = {} # holds current and previous states
3
+ controllers = [] # controller cache
4
+
5
+ # Capture the current gamepad state
6
+ snapshot = ->
7
+ Array::map.call navigator.webkitGamepads || navigator.webkitGetGamepads(), (x) ->
8
+ axes: x.axes
9
+ buttons: x.buttons
10
+
11
+ controller: (index=0) ->
12
+ controllers[index] ||= Gamepads.Controller
13
+ index: index
14
+ state: state
15
+
16
+ update: ->
17
+ state.previous = state.current
18
+ state.current = snapshot()
19
+
20
+ controllers.each (controller) ->
21
+ controller?.update()
@@ -0,0 +1,138 @@
1
+ Gamepads.Controller = (I={}) ->
2
+ Object.reverseMerge I,
3
+ debugColor: "#000"
4
+
5
+ MAX_BUFFER = 0.03
6
+ AXIS_MAX = 1 - MAX_BUFFER
7
+ DEAD_ZONE = AXIS_MAX * 0.2
8
+ TRIP_HIGH = AXIS_MAX * 0.75
9
+ TRIP_LOW = AXIS_MAX * 0.5
10
+
11
+ BUTTON_THRESHOLD = 0.5
12
+
13
+ buttonMapping =
14
+ "A": 0
15
+ "B": 1
16
+
17
+ # X/C, Y/D are interchangeable
18
+ "C": 2
19
+ "D": 3
20
+ "X": 2
21
+ "Y": 3
22
+
23
+ "L": 4
24
+ "LB": 4
25
+ "L1": 4
26
+
27
+ "R": 5
28
+ "RB": 5
29
+ "R1": 5
30
+
31
+ "SELECT": 6
32
+ "BACK": 6
33
+
34
+ "START": 7
35
+
36
+ "HOME": 8
37
+ "GUIDE": 8
38
+
39
+ "TL": 9
40
+ "TR": 10
41
+
42
+ currentState = ->
43
+ I.state.current?[I.index]
44
+
45
+ previousState = ->
46
+ I.state.previous?[I.index]
47
+
48
+ axisTrips = []
49
+ tap = Point(0, 0)
50
+
51
+ processTaps = ->
52
+ [x, y] = [0, 1].map (n) ->
53
+ if !axisTrips[n] && self.axis(n).abs() > TRIP_HIGH
54
+ axisTrips[n] = true
55
+
56
+ return self.axis(n).sign()
57
+
58
+ if axisTrips[n] && self.axis(n).abs() < TRIP_LOW
59
+ axisTrips[n] = false
60
+
61
+ return 0
62
+
63
+ tap = Point(x, y)
64
+
65
+ self = Core().include(Bindable).extend
66
+ actionDown: (buttons...) ->
67
+ if state = currentState()
68
+ buttons.inject false, (down, button) ->
69
+ down || if button is "ANY"
70
+ state.buttons.inject false, (down, button) ->
71
+ down || (button > BUTTON_THRESHOLD)
72
+ else
73
+ state.buttons[buttonMapping[button]] > BUTTON_THRESHOLD
74
+ else
75
+ false
76
+
77
+ # true if button was just pressed
78
+ buttonPressed: (button) ->
79
+ buttonId = buttonMapping[button]
80
+
81
+ return (self.buttons()[buttonId] > BUTTON_THRESHOLD) && !(previousState()?.buttons[buttonId] > BUTTON_THRESHOLD)
82
+
83
+ position: (stick=0) ->
84
+ if state = currentState()
85
+ p = Point(self.axis(2*stick), self.axis(2*stick+1))
86
+
87
+ magnitude = p.magnitude()
88
+
89
+ if magnitude > AXIS_MAX
90
+ p.norm()
91
+ else if magnitude < DEAD_ZONE
92
+ Point(0, 0)
93
+ else
94
+ ratio = magnitude / AXIS_MAX
95
+
96
+ p.scale(ratio / AXIS_MAX)
97
+
98
+ else
99
+ Point(0, 0)
100
+
101
+ axis: (n) ->
102
+ self.axes()[n] || 0
103
+
104
+ axes: ->
105
+ if state = currentState()
106
+ state.axes
107
+ else
108
+ []
109
+
110
+ buttons: ->
111
+ if state = currentState()
112
+ state.buttons
113
+ else
114
+ []
115
+
116
+ tap: ->
117
+ tap
118
+
119
+ update: ->
120
+ processTaps()
121
+
122
+ drawDebug: (canvas) ->
123
+ lineHeight = 18
124
+
125
+ self.axes().each (axis, i) ->
126
+ canvas.drawText
127
+ color: I.debugColor
128
+ text: axis
129
+ x: 0
130
+ y: i * lineHeight
131
+
132
+ self.buttons().each (button, i) ->
133
+ canvas.drawText
134
+ color: I.debugColor
135
+ text: button
136
+ x: 250
137
+ y: i * lineHeight
138
+
@@ -0,0 +1,6 @@
1
+ # Prevent browser contextmenu from popping up in games.
2
+ document.oncontextmenu = -> false
3
+
4
+ # Prevent default keypresses except for input fields
5
+ $(document).bind "keydown", (event) ->
6
+ event.preventDefault() unless $(event.target).is "input"
@@ -0,0 +1,238 @@
1
+ Joysticks = ( ->
2
+ type = "application/x-boomstickjavascriptjoysticksupport"
3
+ plugin = null
4
+ MAX_BUFFER = 2000
5
+ AXIS_MAX = 32767 - MAX_BUFFER
6
+ DEAD_ZONE = AXIS_MAX * 0.2
7
+ TRIP_HIGH = AXIS_MAX * 0.75
8
+ TRIP_LOW = AXIS_MAX * 0.5
9
+
10
+ # Raw Joysticks data
11
+ previousJoysticks = []
12
+ joysticks = []
13
+
14
+ controllers = []
15
+
16
+ buttonMappingDefault =
17
+ "A": 1
18
+ "B": 2
19
+
20
+ # X/C, Y/D are interchangeable
21
+ "C": 4
22
+ "D": 8
23
+ "X": 4
24
+ "Y": 8
25
+
26
+ "R": 32
27
+ "RB": 32
28
+ "R1": 32
29
+
30
+ "L": 16
31
+ "LB": 16
32
+ "L1": 16
33
+
34
+ "SELECT": 64
35
+ "BACK": 64
36
+
37
+ "START": 128
38
+
39
+ "HOME": 256
40
+ "GUIDE": 256
41
+
42
+ "TL": 512
43
+ "TR": 1024
44
+
45
+ "ANY": 0xFFFFFF
46
+
47
+ buttonMappingOSX =
48
+ "A": 2048
49
+ "B": 4096
50
+
51
+ "C": 8192
52
+ "D": 16384
53
+ "X": 8192
54
+ "Y": 16384
55
+
56
+ "R": 512
57
+
58
+ "L": 256
59
+
60
+ "SELECT": 32
61
+ "BACK": 32
62
+
63
+ "START": 16
64
+
65
+ "HOME": 1024
66
+
67
+ "LT": 64
68
+ "TR": 128
69
+
70
+ "ANY": 0xFFFFFF0
71
+
72
+ axisMappingDefault =
73
+ 0: 0
74
+ 1: 1
75
+ 2: 2
76
+ 3: 3
77
+ 4: 4
78
+ 5: 5
79
+
80
+ axisMappingOSX =
81
+ 0: 2
82
+ 1: 3
83
+ 2: 4
84
+ 3: 5
85
+ 4: 0
86
+ 5: 1
87
+
88
+ displayInstallPrompt = (text, url) ->
89
+ $ "<a />",
90
+ css:
91
+ backgroundColor: "yellow"
92
+ boxSizing: "border-box"
93
+ color: "#000"
94
+ display: "block"
95
+ fontWeight: "bold"
96
+ left: 0
97
+ padding: "1em"
98
+ position: "absolute"
99
+ textDecoration: "none"
100
+ top: 0
101
+ width: "100%"
102
+ zIndex: 2000
103
+ href: url
104
+ target: "_blank"
105
+ text: text
106
+ .appendTo("body")
107
+
108
+ Controller = (i, remapOSX) ->
109
+ if remapOSX == undefined
110
+ remapOSX = navigator.platform.match(/^Mac/)
111
+
112
+ if remapOSX
113
+ buttonMapping = buttonMappingOSX
114
+ axisMapping = axisMappingOSX
115
+ else
116
+ buttonMapping = buttonMappingDefault
117
+ axisMapping = axisMappingDefault
118
+
119
+ currentState = ->
120
+ joysticks[i]
121
+
122
+ previousState = ->
123
+ previousJoysticks[i]
124
+
125
+ axisTrips = []
126
+
127
+ self = Core().include(Bindable).extend
128
+ actionDown: (buttons...) ->
129
+ if state = currentState()
130
+ buttons.inject false, (down, button) ->
131
+ down || state.buttons & buttonMapping[button]
132
+ else
133
+ false
134
+
135
+ # true if button was just pressed
136
+ buttonPressed: (button) ->
137
+ buttonId = buttonMapping[button]
138
+
139
+ return (self.buttons() & buttonId) && !(previousState().buttons & buttonId)
140
+
141
+ position: (stick=0) ->
142
+ if state = currentState()
143
+ p = Point(self.axis(2*stick), self.axis(2*stick+1))
144
+
145
+ magnitude = p.magnitude()
146
+
147
+ if magnitude > AXIS_MAX
148
+ p.norm()
149
+ else if magnitude < DEAD_ZONE
150
+ Point(0, 0)
151
+ else
152
+ ratio = magnitude / AXIS_MAX
153
+
154
+ p.scale(ratio / AXIS_MAX)
155
+
156
+ else
157
+ Point(0, 0)
158
+
159
+ axis: (n) ->
160
+ n = axisMapping[n]
161
+
162
+ self.axes()[n] || 0
163
+
164
+ axes: ->
165
+ if state = currentState()
166
+ state.axes
167
+ else
168
+ []
169
+
170
+ buttons: ->
171
+ if state = currentState()
172
+ state.buttons
173
+
174
+ processEvents: ->
175
+ [x, y] = [0, 1].map (n) ->
176
+ if !axisTrips[n] && self.axis(n).abs() > TRIP_HIGH
177
+ axisTrips[n] = true
178
+
179
+ return self.axis(n).sign()
180
+
181
+ if axisTrips[n] && self.axis(n).abs() < TRIP_LOW
182
+ axisTrips[n] = false
183
+
184
+ return 0
185
+
186
+ self.trigger("tap", Point(x, y)) if !x || !y
187
+
188
+ drawDebug: (canvas) ->
189
+ lineHeight = 18
190
+ canvas.fillColor("#FFF")
191
+
192
+ for axis, i in self.axes()
193
+ canvas.fillText(axis, 0, i * lineHeight)
194
+
195
+ canvas.fillText(self.buttons(), 0, i * lineHeight)
196
+
197
+ getController: (i) ->
198
+ controllers[i] ||= Controller(i)
199
+
200
+ init: ->
201
+ unless plugin
202
+ plugin = document.createElement("object")
203
+ plugin.type = type
204
+ plugin.width = 0
205
+ plugin.height = 0
206
+
207
+ $("body").append(plugin)
208
+
209
+ plugin.maxAxes = 6
210
+
211
+ unless plugin.status
212
+ promptElement = displayInstallPrompt("Your browser does not yet handle joysticks, please click here to install the Boomstick plugin!", "https://github.com/STRd6/Boomstick/wiki")
213
+
214
+ # The periodic check will remove the prompt if the player
215
+ # needs to accept or run the plugin manually
216
+ periodicCheck = ->
217
+ if plugin.status
218
+ promptElement.remove()
219
+ else
220
+ setTimeout periodicCheck, 500
221
+
222
+ periodicCheck()
223
+
224
+ status: ->
225
+ plugin?.status
226
+
227
+ update: ->
228
+ if plugin.joysticksJSON
229
+ previousJoysticks = joysticks
230
+ joysticks = JSON.parse(plugin.joysticksJSON())
231
+
232
+ for controller in controllers
233
+ controller?.processEvents()
234
+
235
+ joysticks: ->
236
+ joysticks
237
+ )()
238
+
@@ -0,0 +1,161 @@
1
+ ###*
2
+ jQuery Hotkeys Plugin
3
+ Copyright 2010, John Resig
4
+ Dual licensed under the MIT or GPL Version 2 licenses.
5
+
6
+ Based upon the plugin by Tzury Bar Yochay:
7
+ http://github.com/tzuryby/hotkeys
8
+
9
+ Original idea by:
10
+ Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
11
+ ###
12
+
13
+ ((jQuery) ->
14
+ isTextAcceptingInput = (element) ->
15
+ /textarea|select/i.test(element.nodeName) || element.type == "text" || element.type == "password"
16
+
17
+ isFunctionKey = (event) ->
18
+ (event.type != "keypress") && (112 <= event.which <= 123)
19
+
20
+ jQuery.hotkeys =
21
+ version: "0.8"
22
+
23
+ specialKeys:
24
+ 8: "backspace"
25
+ 9: "tab"
26
+ 13: "return"
27
+ 16: "shift"
28
+ 17: "ctrl"
29
+ 18: "alt"
30
+ 19: "pause"
31
+ 20: "capslock"
32
+ 27: "esc"
33
+ 32: "space"
34
+ 33: "pageup"
35
+ 34: "pagedown"
36
+ 35: "end"
37
+ 36: "home"
38
+ 37: "left"
39
+ 38: "up"
40
+ 39: "right"
41
+ 40: "down"
42
+ 45: "insert"
43
+ 46: "del"
44
+ 96: "0"
45
+ 97: "1"
46
+ 98: "2"
47
+ 99: "3"
48
+ 100: "4"
49
+ 101: "5"
50
+ 102: "6"
51
+ 103: "7"
52
+ 104: "8"
53
+ 105: "9"
54
+ 106: "*"
55
+ 107: "+"
56
+ 109: "-"
57
+ 110: "."
58
+ 111 : "/"
59
+ 112: "f1"
60
+ 113: "f2"
61
+ 114: "f3"
62
+ 115: "f4"
63
+ 116: "f5"
64
+ 117: "f6"
65
+ 118: "f7"
66
+ 119: "f8"
67
+ 120: "f9"
68
+ 121: "f10"
69
+ 122: "f11"
70
+ 123: "f12"
71
+ 144: "numlock"
72
+ 145: "scroll"
73
+ 186: ";"
74
+ 187: "="
75
+ 188: ","
76
+ 189: "-"
77
+ 190: "."
78
+ 191: "/"
79
+ 219: "["
80
+ 220: "\\"
81
+ 221: "]"
82
+ 222: "'"
83
+ 224: "meta"
84
+
85
+ shiftNums:
86
+ "`": "~"
87
+ "1": "!"
88
+ "2": "@"
89
+ "3": "#"
90
+ "4": "$"
91
+ "5": "%"
92
+ "6": "^"
93
+ "7": "&"
94
+ "8": "*"
95
+ "9": "("
96
+ "0": ")"
97
+ "-": "_"
98
+ "=": "+"
99
+ ";": ":"
100
+ "'": "\""
101
+ ",": "<"
102
+ ".": ">"
103
+ "/": "?"
104
+ "\\": "|"
105
+
106
+ keyHandler = (handleObj) ->
107
+ # Only care when a possible input has been specified
108
+ if typeof handleObj.data != "string"
109
+ return
110
+
111
+ origHandler = handleObj.handler
112
+ keys = handleObj.data.toLowerCase().split(" ")
113
+
114
+ handleObj.handler = (event) ->
115
+ # Keypress represents characters, not special keys
116
+ special = event.type != "keypress" && jQuery.hotkeys.specialKeys[ event.which ]
117
+ character = String.fromCharCode( event.which ).toLowerCase()
118
+ modif = ""
119
+ possible = {}
120
+ target = event.target
121
+
122
+ # check combinations (alt|ctrl|shift+anything)
123
+ if event.altKey && special != "alt"
124
+ modif += "alt+"
125
+
126
+ if event.ctrlKey && special != "ctrl"
127
+ modif += "ctrl+"
128
+
129
+ # TODO: Need to make sure this works consistently across platforms
130
+ if event.metaKey && !event.ctrlKey && special != "meta"
131
+ modif += "meta+"
132
+
133
+ # Don't fire in text-accepting inputs that we didn't directly bind to
134
+ # unless a non-shift modifier key or function key is pressed
135
+ unless this == target
136
+ if isTextAcceptingInput(target) && !modif && !isFunctionKey(event)
137
+ return
138
+
139
+ if event.shiftKey && special != "shift"
140
+ modif += "shift+"
141
+
142
+ if special
143
+ possible[ modif + special ] = true
144
+ else
145
+ possible[ modif + character ] = true
146
+ possible[ modif + jQuery.hotkeys.shiftNums[ character ] ] = true
147
+
148
+ # "$" can be triggered as "Shift+4" or "Shift+$" or just "$"
149
+ if modif == "shift+"
150
+ possible[ jQuery.hotkeys.shiftNums[ character ] ] = true
151
+
152
+ for key in keys
153
+ if possible[key]
154
+ return origHandler.apply( this, arguments )
155
+
156
+
157
+ jQuery.each [ "keydown", "keyup", "keypress" ], ->
158
+ jQuery.event.special[ this ] = { add: keyHandler }
159
+
160
+ )(jQuery)
161
+