shank 0.0.5 → 0.0.6
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.
- data/lib/shank/version.rb +1 -1
- data/lib/shank.rb +9 -2
- data/pixie.json +13 -0
- data/shank.gemspec +2 -0
- data/source/{init.coffee → _init.coffee} +0 -0
- data/source/engine.gamepads.coffee +6 -8
- data/source/error_handler.coffee +1 -3
- data/source/gamepads.coffee +21 -7
- data/source/gamepads.combined_controller.coffee +38 -0
- data/source/gamepads.controller.coffee +25 -23
- data/source/gamepads.keyboard_controller.coffee +90 -0
- data/source/keydown.coffee +5 -2
- data/source/mouse.coffee +10 -3
- data/source/music.coffee +1 -3
- data/source/shank.coffee +1 -17
- data/source/sound.coffee +27 -12
- metadata +82 -68
- data/source/engine_stats.coffee +0 -12
- data/source/joysticks.coffee +0 -240
- data/source/jquery.reverse_merge.coffee +0 -21
- data/test/jquery.reverse_merge.coffee +0 -43
- data/test/xstats.coffee +0 -7
- data/vendor/assets/javascripts/xstats.js +0 -767
data/lib/shank/version.rb
CHANGED
data/lib/shank.rb
CHANGED
@@ -1,7 +1,14 @@
|
|
1
1
|
require 'sprockets'
|
2
2
|
|
3
|
-
|
3
|
+
require 'pixie_dust'
|
4
|
+
|
5
|
+
if defined? ::Rails
|
6
|
+
class Engine < ::Rails::Engine
|
7
|
+
config.paths['app/assets'] = "source"
|
8
|
+
end
|
9
|
+
else
|
4
10
|
root_dir = File.expand_path(File.dirname(File.dirname(__FILE__)))
|
11
|
+
asset_dir = File.join(root_dir, "source")
|
5
12
|
|
6
|
-
::Sprockets.append_path
|
13
|
+
::Sprockets.append_path asset_dir
|
7
14
|
end
|
data/pixie.json
ADDED
data/shank.gemspec
CHANGED
File without changes
|
@@ -3,17 +3,17 @@ The <code>Gamepads</code> module gives the engine access to gamepads.
|
|
3
3
|
|
4
4
|
# First you need to add the `Gamepads` module to the engine
|
5
5
|
Engine.defaultModules.push "Gamepads"
|
6
|
-
|
6
|
+
|
7
7
|
window.engine = Engine
|
8
8
|
...
|
9
|
-
|
9
|
+
|
10
10
|
# Then you need to get a controller reference
|
11
11
|
# id = 0 for player 1, etc.
|
12
12
|
controller = engine.controller(id)
|
13
|
-
|
13
|
+
|
14
14
|
# Point indicating direction primary axis is held
|
15
15
|
direction = controller.position()
|
16
|
-
|
16
|
+
|
17
17
|
# Check if buttons are held
|
18
18
|
controller.actionDown("A")
|
19
19
|
controller.actionDown("B")
|
@@ -27,11 +27,9 @@ The <code>Gamepads</code> module gives the engine access to gamepads.
|
|
27
27
|
@param {Object} I Instance variables
|
28
28
|
@param {Object} self Reference to the engine
|
29
29
|
###
|
30
|
-
|
31
|
-
|
32
|
-
root.Engine.Gamepads = (I, self) ->
|
30
|
+
Engine.Gamepads = (I, self) ->
|
33
31
|
gamepads = Gamepads()
|
34
|
-
|
32
|
+
|
35
33
|
self.bind "beforeUpdate", ->
|
36
34
|
# Update the gamepads
|
37
35
|
gamepads.update()
|
data/source/error_handler.coffee
CHANGED
@@ -2,9 +2,7 @@
|
|
2
2
|
This error handler captures any runtime errors and reports them to the IDE
|
3
3
|
if present.
|
4
4
|
###
|
5
|
-
|
6
|
-
|
7
|
-
root.onerror = (message, url, lineNumber) ->
|
5
|
+
window.onerror = (message, url, lineNumber) ->
|
8
6
|
errorContext = $('script').last().text().split('\n')[(lineNumber-5)..(lineNumber+4)]
|
9
7
|
|
10
8
|
errorContext[4] = "<b style='font-weight: bold; text-decoration: underline;'>" + errorContext[4] + "</b>"
|
data/source/gamepads.coffee
CHANGED
@@ -1,19 +1,30 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
root.Gamepads = (I={}) ->
|
1
|
+
Gamepads = (I={}) ->
|
4
2
|
state = {} # holds current and previous states
|
5
3
|
controllers = [] # controller cache
|
6
4
|
|
7
5
|
# Capture the current gamepad state
|
8
6
|
snapshot = ->
|
9
|
-
Array::map.call navigator.webkitGamepads || navigator.webkitGetGamepads(), (x) ->
|
7
|
+
Array::map.call navigator.webkitGamepads || navigator.webkitGetGamepads?() || [], (x) ->
|
10
8
|
axes: x.axes
|
11
9
|
buttons: x.buttons
|
12
10
|
|
13
11
|
controller: (index=0) ->
|
14
|
-
controllers[index]
|
15
|
-
|
16
|
-
|
12
|
+
if controller = controllers[index]
|
13
|
+
return controller
|
14
|
+
|
15
|
+
gamepadIndex = index # (index + 1) % 4 # Offsetting gamepads
|
16
|
+
|
17
|
+
gamepad =
|
18
|
+
Gamepads.Controller
|
19
|
+
index: gamepadIndex
|
20
|
+
state: state
|
21
|
+
|
22
|
+
if index is 0 # TODO Second keyboard controls
|
23
|
+
keyboardController = Gamepads.KeyboardController()
|
24
|
+
|
25
|
+
controllers[index] ||= Gamepads.CombinedController(gamepad, keyboardController)
|
26
|
+
else
|
27
|
+
controllers[index] ||= gamepad
|
17
28
|
|
18
29
|
update: ->
|
19
30
|
state.previous = state.current
|
@@ -21,3 +32,6 @@ root.Gamepads = (I={}) ->
|
|
21
32
|
|
22
33
|
controllers.each (controller) ->
|
23
34
|
controller?.update()
|
35
|
+
|
36
|
+
# window.addEventListener "MozGamepadConnected", (event) ->
|
37
|
+
# console.log event
|
@@ -0,0 +1,38 @@
|
|
1
|
+
Gamepads.CombinedController = (sources...) ->
|
2
|
+
|
3
|
+
self = Core().extend
|
4
|
+
buttonDown: (buttons...) ->
|
5
|
+
sources.inject false, (memo, source) ->
|
6
|
+
memo or source.buttonDown buttons...
|
7
|
+
|
8
|
+
# true if button was just pressed
|
9
|
+
buttonPressed: (button) ->
|
10
|
+
sources.inject false, (memo, source) ->
|
11
|
+
memo or source.buttonPressed(button)
|
12
|
+
|
13
|
+
# true if button was just released
|
14
|
+
buttonReleased: (button) ->
|
15
|
+
sources.inject false, (memo, source) ->
|
16
|
+
memo or source.buttonPressed(button)
|
17
|
+
|
18
|
+
position: (stick=0) ->
|
19
|
+
raw = sources.inject Point(0, 0), (point, source) ->
|
20
|
+
point.add(source.position(stick))
|
21
|
+
|
22
|
+
# TODO: This could be a point method
|
23
|
+
if raw.length() > 1
|
24
|
+
raw.norm()
|
25
|
+
else
|
26
|
+
raw
|
27
|
+
|
28
|
+
tap: ->
|
29
|
+
raw = sources.inject Point(0, 0), (point, source) ->
|
30
|
+
point.add(source.tap())
|
31
|
+
|
32
|
+
Point(raw.x.sign(), raw.y.sign())
|
33
|
+
|
34
|
+
update: ->
|
35
|
+
sources.invoke "update"
|
36
|
+
|
37
|
+
drawDebug: (canvas) ->
|
38
|
+
sources.invoke "drawDebug", canvas
|
@@ -1,12 +1,10 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
root.Gamepads.Controller = (I={}) ->
|
1
|
+
Gamepads.Controller = (I={}) ->
|
4
2
|
Object.reverseMerge I,
|
5
3
|
debugColor: "#000"
|
6
4
|
|
7
5
|
MAX_BUFFER = 0.03
|
8
6
|
AXIS_MAX = 1 - MAX_BUFFER
|
9
|
-
DEAD_ZONE = AXIS_MAX * 0.
|
7
|
+
DEAD_ZONE = AXIS_MAX * 0.25
|
10
8
|
TRIP_HIGH = AXIS_MAX * 0.75
|
11
9
|
TRIP_LOW = AXIS_MAX * 0.5
|
12
10
|
|
@@ -16,30 +14,24 @@ root.Gamepads.Controller = (I={}) ->
|
|
16
14
|
"A": 0
|
17
15
|
"B": 1
|
18
16
|
|
19
|
-
# X/C, Y/D are interchangeable
|
20
|
-
"C": 2
|
21
|
-
"D": 3
|
22
17
|
"X": 2
|
23
18
|
"Y": 3
|
24
19
|
|
25
|
-
"L": 4
|
26
20
|
"LB": 4
|
27
|
-
"L1": 4
|
28
|
-
|
29
|
-
"R": 5
|
30
21
|
"RB": 5
|
31
|
-
"R1": 5
|
32
22
|
|
33
|
-
"
|
34
|
-
"
|
23
|
+
"LT": 6
|
24
|
+
"RT": 7
|
25
|
+
|
26
|
+
"SELECT": 8
|
27
|
+
"BACK": 8
|
35
28
|
|
36
|
-
"START":
|
29
|
+
"START": 9
|
37
30
|
|
38
|
-
"
|
39
|
-
"
|
31
|
+
"TL": 10
|
32
|
+
"TR": 11
|
40
33
|
|
41
|
-
"
|
42
|
-
"TR": 10
|
34
|
+
"HOME": 16
|
43
35
|
|
44
36
|
currentState = ->
|
45
37
|
I.state.current?[I.index]
|
@@ -65,7 +57,7 @@ root.Gamepads.Controller = (I={}) ->
|
|
65
57
|
tap = Point(x, y)
|
66
58
|
|
67
59
|
self = Core().include(Bindable).extend
|
68
|
-
|
60
|
+
buttonDown: (buttons...) ->
|
69
61
|
if state = currentState()
|
70
62
|
buttons.inject false, (down, button) ->
|
71
63
|
down || if button is "ANY"
|
@@ -82,6 +74,11 @@ root.Gamepads.Controller = (I={}) ->
|
|
82
74
|
|
83
75
|
return (self.buttons()[buttonId] > BUTTON_THRESHOLD) && !(previousState()?.buttons[buttonId] > BUTTON_THRESHOLD)
|
84
76
|
|
77
|
+
buttonReleased: (button) ->
|
78
|
+
buttonId = buttonMapping[button]
|
79
|
+
|
80
|
+
return !(self.buttons()[buttonId] > BUTTON_THRESHOLD) && (previousState()?.buttons[buttonId] > BUTTON_THRESHOLD)
|
81
|
+
|
85
82
|
position: (stick=0) ->
|
86
83
|
if state = currentState()
|
87
84
|
p = Point(self.axis(2*stick), self.axis(2*stick+1))
|
@@ -129,12 +126,17 @@ root.Gamepads.Controller = (I={}) ->
|
|
129
126
|
color: I.debugColor
|
130
127
|
text: axis
|
131
128
|
x: 0
|
132
|
-
y: i * lineHeight
|
129
|
+
y: (i + 1) * lineHeight
|
133
130
|
|
134
131
|
self.buttons().each (button, i) ->
|
132
|
+
canvas.drawText
|
133
|
+
color: I.debugColor
|
134
|
+
text: "#{i}:"
|
135
|
+
x: 230
|
136
|
+
y: (i + 1) * lineHeight
|
137
|
+
|
135
138
|
canvas.drawText
|
136
139
|
color: I.debugColor
|
137
140
|
text: button
|
138
141
|
x: 250
|
139
|
-
y: i * lineHeight
|
140
|
-
|
142
|
+
y: (i + 1) * lineHeight
|
@@ -0,0 +1,90 @@
|
|
1
|
+
Gamepads.KeyboardController = (I={}) ->
|
2
|
+
Object.reverseMerge I,
|
3
|
+
axisMapping: [
|
4
|
+
["left", "right"]
|
5
|
+
["up", "down"]
|
6
|
+
]
|
7
|
+
buttonMapping:
|
8
|
+
"A": 'z'
|
9
|
+
"B": 'x'
|
10
|
+
|
11
|
+
# X/C, Y/D are interchangeable
|
12
|
+
"C": 'c'
|
13
|
+
"D": 'v'
|
14
|
+
"X": 'c'
|
15
|
+
"Y": 'v'
|
16
|
+
|
17
|
+
"SELECT": "shift"
|
18
|
+
"START": "return"
|
19
|
+
|
20
|
+
debugColor: "#000"
|
21
|
+
|
22
|
+
tap = Point(0, 0)
|
23
|
+
buttonKeys = Object.keys(I.buttonMapping)
|
24
|
+
buttonValues = buttonKeys.map (key) ->
|
25
|
+
I.buttonMapping[key]
|
26
|
+
|
27
|
+
# Init any keys used
|
28
|
+
I.axisMapping.each (axis) ->
|
29
|
+
axis.each (key) ->
|
30
|
+
keydown[key] = false
|
31
|
+
|
32
|
+
buttonKeys.each (key) ->
|
33
|
+
keydown[key] = false
|
34
|
+
|
35
|
+
processTaps = ->
|
36
|
+
[x, y] = I.axisMapping.map ([negative, positive]) ->
|
37
|
+
justPressed[positive] - justPressed[negative]
|
38
|
+
|
39
|
+
tap = Point(x, y)
|
40
|
+
|
41
|
+
self = Core().include(Bindable).extend
|
42
|
+
buttonDown: (buttons...) ->
|
43
|
+
buttons.inject false, (down, button) ->
|
44
|
+
down || if button is "ANY"
|
45
|
+
buttonValues.inject false, (down, button) ->
|
46
|
+
down || keydown[button]
|
47
|
+
else
|
48
|
+
keydown[I.buttonMapping[button]]
|
49
|
+
|
50
|
+
# true if button was just pressed
|
51
|
+
buttonPressed: (button) ->
|
52
|
+
keyname = I.buttonMapping[button]
|
53
|
+
|
54
|
+
return justPressed[keyname]
|
55
|
+
|
56
|
+
buttonReleased: (button) ->
|
57
|
+
keyname = I.buttonMapping[button]
|
58
|
+
|
59
|
+
return justReleased[keyname]
|
60
|
+
|
61
|
+
position: (stick=0) ->
|
62
|
+
[x, y] = I.axisMapping.map ([negative, positive]) ->
|
63
|
+
keydown[positive] - keydown[negative]
|
64
|
+
|
65
|
+
tap = Point(x, y)
|
66
|
+
|
67
|
+
tap: ->
|
68
|
+
tap
|
69
|
+
|
70
|
+
update: ->
|
71
|
+
processTaps()
|
72
|
+
|
73
|
+
drawDebug: (canvas) ->
|
74
|
+
lineHeight = 18
|
75
|
+
|
76
|
+
p = self.position()
|
77
|
+
|
78
|
+
["x", "y"].each (key, i) ->
|
79
|
+
canvas.drawText
|
80
|
+
color: I.debugColor
|
81
|
+
text: p[key]
|
82
|
+
x: 0
|
83
|
+
y: i * lineHeight
|
84
|
+
|
85
|
+
buttonKeys.each (button, i) ->
|
86
|
+
canvas.drawText
|
87
|
+
color: I.debugColor
|
88
|
+
text: self.buttonDown(button)
|
89
|
+
x: 250
|
90
|
+
y: i * lineHeight
|
data/source/keydown.coffee
CHANGED
@@ -21,7 +21,7 @@ $ ->
|
|
21
21
|
###
|
22
22
|
|
23
23
|
###*
|
24
|
-
The global justPressed property lets your query the status of keys. However,
|
24
|
+
The global justPressed property lets your query the status of keys. However,
|
25
25
|
unlike keydown it will only trigger once for each time the key is pressed.
|
26
26
|
|
27
27
|
<code><pre>
|
@@ -43,6 +43,7 @@ $ ->
|
|
43
43
|
###
|
44
44
|
window.keydown = {}
|
45
45
|
window.justPressed = {}
|
46
|
+
window.justReleased = {}
|
46
47
|
|
47
48
|
prevKeysDown = {}
|
48
49
|
|
@@ -60,10 +61,12 @@ $ ->
|
|
60
61
|
|
61
62
|
window.updateKeys = () ->
|
62
63
|
window.justPressed = {}
|
64
|
+
window.justReleased = {}
|
63
65
|
keydown.any = false
|
64
66
|
|
65
67
|
for key, value of keydown
|
66
|
-
justPressed[key] = value
|
68
|
+
justPressed[key] = value and !prevKeysDown[key]
|
69
|
+
justReleased[key] = !value and prevKeysDown[key]
|
67
70
|
|
68
71
|
justPressed.any = true if (justPressed[key] || mousePressed.left || mousePressed.right)
|
69
72
|
keydown.any = true if (value || mouseDown.left || mouseDown.right)
|
data/source/mouse.coffee
CHANGED
@@ -32,6 +32,7 @@ $ ->
|
|
32
32
|
###
|
33
33
|
window.mouseDown = {}
|
34
34
|
window.mousePressed = {}
|
35
|
+
window.mouseReleased = {}
|
35
36
|
window.mousePosition = Point(0, 0)
|
36
37
|
|
37
38
|
prevButtonsDown = {}
|
@@ -45,9 +46,11 @@ $ ->
|
|
45
46
|
buttonNames[event.which]
|
46
47
|
|
47
48
|
$(document).bind "mousemove", (event) ->
|
48
|
-
#
|
49
|
-
|
50
|
-
|
49
|
+
# Position relative to canvas element
|
50
|
+
offset = $("canvas").offset()
|
51
|
+
|
52
|
+
mousePosition.x = event.pageX - offset.left
|
53
|
+
mousePosition.y = event.pageY - offset.top
|
51
54
|
|
52
55
|
$(document).bind "mousedown", (event) ->
|
53
56
|
mouseDown[buttonName(event)] = true
|
@@ -57,10 +60,14 @@ $ ->
|
|
57
60
|
|
58
61
|
window.updateMouse = ->
|
59
62
|
window.mousePressed = {}
|
63
|
+
window.mouseReleased = {}
|
60
64
|
|
61
65
|
for button, value of mouseDown
|
62
66
|
mousePressed[button] = value unless prevButtonsDown[button]
|
63
67
|
|
68
|
+
for button, value of mouseDown
|
69
|
+
mouseReleased[button] = !value if prevButtonsDown[button]
|
70
|
+
|
64
71
|
prevButtonsDown = {}
|
65
72
|
for button, value of mouseDown
|
66
73
|
prevButtonsDown[button] = value
|
data/source/music.coffee
CHANGED
data/source/shank.coffee
CHANGED
@@ -1,17 +1 @@
|
|
1
|
-
#=
|
2
|
-
|
3
|
-
#= require engine.gamepads
|
4
|
-
#= require engine_stats
|
5
|
-
#= require error_handler
|
6
|
-
#= require gamepads
|
7
|
-
#= require gamepads.controller
|
8
|
-
#= require joysticks
|
9
|
-
#= require jquery.hotkeys
|
10
|
-
#= require jquery.reverse_merge
|
11
|
-
#= require keydown
|
12
|
-
#= require mouse
|
13
|
-
#= require music
|
14
|
-
#= require pixie_canvas
|
15
|
-
#= require request_animation_frame
|
16
|
-
#= require sound
|
17
|
-
#= require storage
|
1
|
+
#= require_tree .
|
data/source/sound.coffee
CHANGED
@@ -29,24 +29,24 @@
|
|
29
29
|
Object.extend Sound,
|
30
30
|
###*
|
31
31
|
Set the global volume modifier for all sound effects.
|
32
|
-
|
32
|
+
|
33
33
|
Any value set is clamped between 0 and 1. This is multiplied
|
34
34
|
into each individual effect that plays.
|
35
|
-
|
35
|
+
|
36
36
|
If no argument is given return the current global sound effect volume.
|
37
|
-
|
38
|
-
@name
|
37
|
+
|
38
|
+
@name volume
|
39
39
|
@methodOf Sound
|
40
40
|
@param {Number} [newVolume] The volume to set
|
41
41
|
###
|
42
|
-
|
42
|
+
volume: (newVolume) ->
|
43
43
|
if newVolume?
|
44
44
|
globalVolume = newVolume.clamp(0, 1)
|
45
45
|
|
46
46
|
return globalVolume
|
47
47
|
|
48
48
|
###*
|
49
|
-
Play a sound from your sounds
|
49
|
+
Play a sound from your sounds
|
50
50
|
directory with the name of `id`.
|
51
51
|
|
52
52
|
<code><pre>
|
@@ -59,7 +59,7 @@
|
|
59
59
|
|
60
60
|
@param {String} id id or name of the sound file to play
|
61
61
|
@param {String} maxChannels max number of sounds able to be played simultaneously
|
62
|
-
###
|
62
|
+
###
|
63
63
|
play: (id, maxChannels) ->
|
64
64
|
# TODO: Too many channels crash Chrome!!!1
|
65
65
|
maxChannels ||= 4
|
@@ -100,7 +100,7 @@
|
|
100
100
|
@param {String} url location of sound file to play
|
101
101
|
|
102
102
|
@returns {Sound} this sound object
|
103
|
-
###
|
103
|
+
###
|
104
104
|
playFromUrl: (url) ->
|
105
105
|
sound = $('<audio />').get(0)
|
106
106
|
sound.src = url
|
@@ -114,8 +114,8 @@
|
|
114
114
|
Stop a sound while it is playing.
|
115
115
|
|
116
116
|
<code><pre>
|
117
|
-
# stops the sound 'explode' from
|
118
|
-
# playing if it is currently playing
|
117
|
+
# stops the sound 'explode' from
|
118
|
+
# playing if it is currently playing
|
119
119
|
Sound.stop('explode')
|
120
120
|
</pre></code>
|
121
121
|
|
@@ -123,9 +123,24 @@
|
|
123
123
|
@methodOf Sound
|
124
124
|
|
125
125
|
@param {String} id id or name of sound to stop playing.
|
126
|
-
###
|
126
|
+
###
|
127
127
|
stop: (id) ->
|
128
128
|
sounds[id]?.stop()
|
129
129
|
|
130
|
-
|
130
|
+
###*
|
131
|
+
Set the global volume modifier for all sound effects.
|
132
|
+
|
133
|
+
Any value set is clamped between 0 and 1. This is multiplied
|
134
|
+
into each individual effect that plays.
|
135
|
+
|
136
|
+
If no argument is given return the current global sound effect volume.
|
137
|
+
|
138
|
+
@name globalVolume
|
139
|
+
@deprecated
|
140
|
+
@methodOf Sound
|
141
|
+
@param {Number} [newVolume] The volume to set
|
142
|
+
###
|
143
|
+
Sound.globalVolume = Sound.volume
|
144
|
+
|
145
|
+
(exports ? this)["Sound"] = Sound
|
131
146
|
)(jQuery)
|