shank 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+