pixie_dust 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. data/.gitignore +18 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE.txt +22 -0
  4. data/README +16 -0
  5. data/README.md +29 -0
  6. data/Rakefile +1 -0
  7. data/game.js +9200 -0
  8. data/lib/corelib.js +3331 -0
  9. data/lib/pixie_dust/version.rb +3 -0
  10. data/lib/pixie_dust.rb +14 -0
  11. data/pixie.json +15 -0
  12. data/pixie_dust.gemspec +29 -0
  13. data/source/active_bounds.coffee +48 -0
  14. data/source/ageable.coffee +23 -0
  15. data/source/bounded.coffee +282 -0
  16. data/source/camera.coffee +138 -0
  17. data/source/camera.fade.coffee +69 -0
  18. data/source/camera.flash.coffee +69 -0
  19. data/source/camera.rotate.coffee +11 -0
  20. data/source/camera.shake.coffee +27 -0
  21. data/source/camera.zoom.coffee +25 -0
  22. data/source/camera.zsort.coffee +13 -0
  23. data/source/clampable.coffee +61 -0
  24. data/source/collidable.coffee +126 -0
  25. data/source/collision.coffee +272 -0
  26. data/source/collision_response.coffee +28 -0
  27. data/source/color.coffee +1113 -0
  28. data/source/color_table.coffee +2534 -0
  29. data/source/controllable.coffee +66 -0
  30. data/source/cooldown.coffee +82 -0
  31. data/source/debuggable.coffee +253 -0
  32. data/source/drawable.coffee +167 -0
  33. data/source/dust_emitter.coffee +36 -0
  34. data/source/easing.coffee +38 -0
  35. data/source/emitter.coffee +7 -0
  36. data/source/emitterable.coffee +68 -0
  37. data/source/engine.coffee +274 -0
  38. data/source/engine.collision.coffee +77 -0
  39. data/source/engine.data.coffee +23 -0
  40. data/source/engine.delay.coffee +41 -0
  41. data/source/engine.fps_counter.coffee +32 -0
  42. data/source/engine.game_state.coffee +86 -0
  43. data/source/engine.joysticks.coffee +47 -0
  44. data/source/engine.keyboard.coffee +17 -0
  45. data/source/engine.levels.coffee +69 -0
  46. data/source/engine.mouse.coffee +16 -0
  47. data/source/engine.selector.coffee +166 -0
  48. data/source/engine.stats.coffee +16 -0
  49. data/source/engine.tilemap.coffee +41 -0
  50. data/source/engine_background.coffee +32 -0
  51. data/source/expirable.coffee +47 -0
  52. data/source/flickerable.coffee +78 -0
  53. data/source/follow.coffee +65 -0
  54. data/source/framerate.coffee +42 -0
  55. data/source/game_object.coffee +181 -0
  56. data/source/game_object.effect.coffee +33 -0
  57. data/source/game_object.meter.coffee +191 -0
  58. data/source/game_over.coffee +40 -0
  59. data/source/game_state.coffee +67 -0
  60. data/source/game_state.save_state.coffee +76 -0
  61. data/source/game_state.single_camera.coffee +40 -0
  62. data/source/game_state_cameras.coffee +33 -0
  63. data/source/level_state.coffee +32 -0
  64. data/source/movable.coffee +57 -0
  65. data/source/oscillator.coffee +18 -0
  66. data/source/pixie_dust.coffee +2 -0
  67. data/source/resource_loader.coffee +35 -0
  68. data/source/rotatable.coffee +38 -0
  69. data/source/sprite.coffee +181 -0
  70. data/source/text_effect.coffee +74 -0
  71. data/source/text_effect.floating.coffee +22 -0
  72. data/source/text_screen.coffee +38 -0
  73. data/source/tilemap.coffee +56 -0
  74. data/source/timed_events.coffee +78 -0
  75. data/source/title_screen.coffee +38 -0
  76. data/source/tween.coffee +70 -0
  77. data/test/active_bounds.coffee +67 -0
  78. data/test/bounded.coffee +98 -0
  79. data/test/camera.coffee +29 -0
  80. data/test/clampable.coffee +18 -0
  81. data/test/collidable.coffee +51 -0
  82. data/test/collision.coffee +70 -0
  83. data/test/color.coffee +533 -0
  84. data/test/controllable.coffee +108 -0
  85. data/test/cooldown.coffee +116 -0
  86. data/test/debuggable.coffee +71 -0
  87. data/test/drawable.coffee +31 -0
  88. data/test/emitter.coffee +0 -0
  89. data/test/emitterable.coffee +15 -0
  90. data/test/engine.coffee +228 -0
  91. data/test/engine_data.coffee +12 -0
  92. data/test/engine_delay.coffee +14 -0
  93. data/test/engine_selector.coffee +100 -0
  94. data/test/expirable.coffee +35 -0
  95. data/test/flickerable.coffee +51 -0
  96. data/test/follow.coffee +34 -0
  97. data/test/game_object.coffee +78 -0
  98. data/test/game_object_effect.coffee +17 -0
  99. data/test/metered.coffee +33 -0
  100. data/test/movable.coffee +46 -0
  101. data/test/oscillator.coffee +28 -0
  102. data/test/resource_loader.coffee +7 -0
  103. data/test/rotatable.coffee +20 -0
  104. data/test/sprite.coffee +21 -0
  105. data/test/text.coffee +25 -0
  106. data/test/timed_events.coffee +23 -0
  107. data/test/tweening.coffee +18 -0
  108. metadata +233 -0
@@ -0,0 +1,66 @@
1
+ ###*
2
+ The Controllable module adds simple movement
3
+ when up, down, left, or right are held.
4
+
5
+ # create a player and include Controllable
6
+ player = GameObject
7
+ width: 5
8
+ height: 17
9
+ x: 15
10
+ y: 30
11
+ speed: 2
12
+
13
+ player.include Controllable
14
+
15
+ # hold the left arrow key, then
16
+ # update the player
17
+ player.update()
18
+
19
+ # the player is moved left according to his speed
20
+ player.I.x
21
+ # => 13
22
+
23
+ # We keep track of the direction the object is
24
+ # facing in case you need that (eg. for attack direction)
25
+ player.I.facing
26
+ # => player.I.facing
27
+ # => Point(-1, 0)
28
+
29
+ @name Controllable
30
+ @module
31
+ @constructor
32
+ @param {Object} I Instance variables
33
+ @param {Core} self Reference to including object
34
+ ###
35
+ Controllable = (I={}, self) ->
36
+ Object.reverseMerge I,
37
+ facing: Point(1, 0)
38
+ speed: 1
39
+ velocity: Point(0, 0)
40
+
41
+ self.bind "update", ->
42
+ self.movement()
43
+
44
+ movement: ->
45
+ I.velocity.x = 0
46
+ I.velocity.y = 0
47
+
48
+ if keydown.left
49
+ I.velocity.x = -1
50
+
51
+ if keydown.right
52
+ I.velocity.x = 1
53
+
54
+ if keydown.up
55
+ I.velocity.y = -1
56
+
57
+ if keydown.down
58
+ I.velocity.y = 1
59
+
60
+ I.velocity = I.velocity.norm()
61
+
62
+ unless I.velocity.equal(Point.ZERO)
63
+ I.facing = I.velocity
64
+
65
+ I.velocity = I.velocity.scale(I.speed)
66
+
@@ -0,0 +1,82 @@
1
+ ###*
2
+ The Cooldown module provides a declarative way to manage cooldowns on
3
+ GameObject's properties.
4
+
5
+ # Health regeneration
6
+ player = GameObject
7
+ health: 50
8
+
9
+ # health will approach
10
+ # 100 by 1 every second
11
+ player.cooldown "health",
12
+ target: 100
13
+
14
+ elapsedTime = 1
15
+ player.update(elapsedTime)
16
+
17
+ player.I.health
18
+ # => 51
19
+
20
+ # Shoot Timeout
21
+ player = GameObject()
22
+
23
+ # by default the cooldown
24
+ # approaches 0 by 1 each second
25
+ player.cooldown "shootTimer"
26
+
27
+ player.I.shootTimer = 10 # => Pew! Pew!
28
+
29
+ player.update(elapsedTime)
30
+
31
+ player.I.shootTimer # => 9
32
+
33
+ # Turbo Cooldown
34
+ player = GameObject()
35
+
36
+ # turboTimer starts at 1000
37
+ # and approaches 12 by 5 each second
38
+ player.cooldown "turboTimer",
39
+ approachBy: 5
40
+ value: 1000
41
+ target: 12
42
+
43
+ player.I.turboTimer = 1000
44
+
45
+ player.update(elapsedTime)
46
+
47
+ player.I.turboTimer # => 995
48
+
49
+ @name Cooldown
50
+ @module
51
+ @constructor
52
+ @param {Object} I Instance variables
53
+ @param {Core} self Reference to including object
54
+ ###
55
+ Cooldown = (I, self) ->
56
+ Object.reverseMerge I,
57
+ cooldowns: {}
58
+
59
+ self.bind "update", (dt) ->
60
+ for name, cooldownOptions of I.cooldowns
61
+ {approachBy, target} = cooldownOptions
62
+
63
+ I[name] = I[name].approach(target, approachBy * dt)
64
+
65
+ cooldown: (name, options={}) ->
66
+ {target, approachBy, value} = options
67
+
68
+ target ||= 0
69
+ approachBy = 1 unless approachBy?
70
+
71
+ # Set the cooldown data
72
+ I.cooldowns[name] = {
73
+ target
74
+ approachBy
75
+ }
76
+
77
+ if value?
78
+ # Use the value given if any
79
+ I[name] = options.value
80
+ else
81
+ # Initialize field if it doesn't exist
82
+ I[name] = 0 unless I[name]
@@ -0,0 +1,253 @@
1
+ ###*
2
+ The Debuggable Module provides a simple API to easily display
3
+ an object's properties onscreen. This mixin comes with predefined
4
+ attribute filters so that you can exclude irrelevant data.
5
+
6
+ player = GameObject
7
+ x: 40
8
+ y: 14
9
+ spriteName: null
10
+ numericErrorProperty: NaN
11
+
12
+ player.include Debuggable
13
+
14
+ # sets up debug output for all player's properties
15
+ # at the starting position (0, 0)
16
+ player.debug
17
+ filter: 'all'
18
+
19
+ @name Debuggable
20
+ @module
21
+ @constructor
22
+ @param {Object} I Instance variables
23
+ @param {Core} self Reference to including object
24
+ ###
25
+ Debuggable = (I={}, self) ->
26
+ COL_HEIGHT = 175
27
+ ROW_HEIGHT = 9
28
+ FONT_SIZE = 9
29
+
30
+ debugX = 0
31
+ debugY = 0
32
+
33
+ Object.reverseMerge I,
34
+ debug:
35
+ enabled: false
36
+ color: 'black'
37
+ filter: 'all'
38
+ bounds: true
39
+ velocity: true
40
+ position:
41
+ x: 0
42
+ y: 0
43
+
44
+ initialI = Object.extend({}, I)
45
+
46
+ debugBounds = (canvas) ->
47
+ canvas.drawRect
48
+ color: 'rgba(255, 0, 255, 0.4)'
49
+ bounds: self.bounds()
50
+
51
+ debugVelocity = (canvas) ->
52
+ if I.velocity?
53
+ canvas.withTransform Matrix.translation(I.x, I.y), (canvas) ->
54
+ thickness = 4
55
+
56
+ color = 'rgba(255, 0, 0, 0.5)'
57
+
58
+ canvas.drawRect
59
+ x: 0
60
+ y: -thickness / 2
61
+ width: I.velocity.x
62
+ height: thickness
63
+ color: color
64
+
65
+ canvas.drawRect
66
+ x: -thickness / 2
67
+ y: 0
68
+ width: thickness
69
+ height: I.velocity.y
70
+ color: color
71
+
72
+ filterProperties = (properties) ->
73
+ results = {}
74
+
75
+ switch I.debug.filter
76
+ when 'all'
77
+ results = properties
78
+ when 'undefined'
79
+ for key, value of properties
80
+ results[key] = value if not value? or nan(value)
81
+ when 'changed'
82
+ for key, value of properties
83
+ results[key] = value if initialI[key] isnt value
84
+
85
+ return results
86
+
87
+ sortedKeys = ->
88
+ keys = []
89
+
90
+ for key, value of filterProperties(I)
91
+ keys.push key
92
+
93
+ keys.sort()
94
+
95
+ nan = (value) ->
96
+ typeof value is 'number' and isNaN(value)
97
+
98
+ drawDebugLine = (text, canvas, x, y) ->
99
+ canvas.drawText
100
+ color: I.debug.color
101
+ x: x + I.debug.position.x
102
+ y: y + I.debug.position.y
103
+ text: text
104
+
105
+ debugY += ROW_HEIGHT
106
+
107
+ getPropertyRow = (key, value, canvas) ->
108
+ # exclude functions returned by iterating over
109
+ # objects like Color, Point, etc.
110
+ if typeof value is 'function'
111
+ return
112
+ else if Object.isObject(value)
113
+ drawDebugLine(key, canvas, debugX, debugY)
114
+
115
+ debugX += 8
116
+
117
+ for k, v of value
118
+ getPropertyRow(k, v, canvas)
119
+
120
+ debugX -= 8
121
+ else if Object.isArray(value)
122
+ toStringArray = (for v in value
123
+ if Object.isObject(v)
124
+ v.I.class || v.toString()
125
+ else
126
+ v
127
+ )
128
+
129
+ drawDebugLine("#{key}(#{value.length}): #{toStringArray}", canvas, debugX, debugY)
130
+ else
131
+ value = processValue(value)
132
+
133
+ drawDebugLine("#{key}: #{value}", canvas, debugX, debugY)
134
+
135
+ processValue = (value) ->
136
+ output = value
137
+
138
+ try
139
+ parsedNumber = parseFloat(value)
140
+
141
+ if parsedNumber
142
+ if typeof value isnt 'string' and parsedNumber isnt parseInt(value)
143
+ output = value.toFixed(3)
144
+
145
+ return output
146
+
147
+ self.bind "update", ->
148
+ if justPressed['0']
149
+ self.toggleDebug()
150
+
151
+ self.bind "overlay", (canvas) ->
152
+ if I.debug.enabled
153
+ canvas.font "#{FONT_SIZE}px Monaco"
154
+
155
+ debugX = 0
156
+ debugY = ROW_HEIGHT
157
+
158
+ for key in sortedKeys()
159
+ getPropertyRow(key, I[key], canvas)
160
+
161
+ debugX += COL_HEIGHT
162
+ debugY = ROW_HEIGHT
163
+
164
+ debugBounds(canvas) if I.debug.bounds
165
+ debugVelocity(canvas) if I.debug.velocity
166
+
167
+ ###*
168
+ Enable debugging display for the calling GameObject.
169
+
170
+ player = GameObject
171
+ x: 40
172
+ y: 14
173
+ spriteName: null
174
+ numericErrorProperty: NaN
175
+
176
+ player.include Debuggable
177
+
178
+ # sets up debug output for all player's properties
179
+ # at the starting position (0, 0)
180
+ player.debug
181
+ filter: 'all'
182
+
183
+ player.I.y = 45
184
+
185
+ # sets up debug output for only properties that have
186
+ # changed since initialization. In this case only y
187
+ # would be displayed.
188
+ player.debug
189
+ filter: 'changed'
190
+
191
+ # sets up debug output for properties that are <code>undefined</code>,
192
+ # <code>null</code>, or <code>NaN</code>. In this case spriteName and
193
+ # numericErrorProperty would be displayed.
194
+ player.debug
195
+ filter: 'undefined'
196
+
197
+ # sets up debug output using all possible configuration options
198
+ player.debug
199
+ bounds: true # set this to false to disable visual debugging of the object's bounding box
200
+ color: 'red' # color of debug text
201
+ filter: 'all'
202
+ x: 30 # x position to start printing debug information
203
+ y: 50 # y position to start printing debug information
204
+ velocity: true # set this to false to disable visual debugging of the object's velocity
205
+
206
+ @name debug
207
+ @methodOf Debuggable#
208
+ @param {Object} Options to configure debug output
209
+ @param {Boolean} bounds Whether or not to visually debug the object's bounds
210
+ @param {Color|String} color The color of the debug text
211
+ @param {String} filter Choices include 'all', 'changed', and 'undefined'
212
+ @param {Number} x The x position to start drawing the debug information
213
+ @param {Number} y The y position to start drawing the debug information
214
+ @param {Boolean} velocity Whether or not to visually debug the object's velocity
215
+ ###
216
+ debug: (options={}) ->
217
+ {x, y} = options
218
+
219
+ I.debug.position.x = x if x?
220
+ I.debug.position.y = y if y?
221
+
222
+ Object.extend I.debug, options
223
+
224
+ I.debug.enabled = true
225
+
226
+ ###*
227
+ Toggle display of debug information.
228
+
229
+ player = GameObject()
230
+
231
+ player.include Debuggable
232
+
233
+ # enables debug display
234
+ player.debug()
235
+
236
+ # disables debug display
237
+ player.toggleDisable()
238
+
239
+ # if false is passed to toggleDisplay, then debugging is disabled.
240
+ player.toggleDisplay(false)
241
+
242
+ # if true is passed to toggleDisplay, then debugging is enabled.
243
+ player.toggleDisplay(true)
244
+
245
+ @name toggleDebug
246
+ @methodOf Debuggable#
247
+ @param {Boolean} newVal If true is passed then debugging is enabled, if false is passed then debugging is disabled, if nothing is passed, then debug state is toggled.
248
+ ###
249
+ toggleDebug: (newVal) ->
250
+ if newVal?
251
+ I.debug.enabled = newVal
252
+ else
253
+ I.debug.enabled = not I.debug.enabled
@@ -0,0 +1,167 @@
1
+ ###*
2
+ The Drawable module is used to provide a simple draw method to the including
3
+ object.
4
+
5
+ Binds a default draw listener to draw a rectangle or a sprite, if one exists.
6
+
7
+ Binds a step listener to update the transform of the object.
8
+
9
+ Autoloads the sprite specified in I.sprite, if any.
10
+
11
+ player = Core
12
+ x: 15
13
+ y: 30
14
+ width: 5
15
+ height: 5
16
+ sprite: "my_cool_sprite"
17
+
18
+ engine.bind 'draw', (canvas) ->
19
+ player.draw(canvas)
20
+ # => Uncaught TypeError: Object has no method 'draw'
21
+
22
+ player.include(Drawable)
23
+
24
+ engine.bind 'draw', (canvas) ->
25
+ player.draw(canvas)
26
+ # => if you have a sprite named "my_cool_sprite" in your images folder
27
+ # then it will be drawn. Otherwise, a rectangle positioned at x: 15 and
28
+ # y: 30 with width and height 5 will be drawn.
29
+
30
+ @name Drawable
31
+ @module
32
+ @constructor
33
+ @param {Object} I Instance variables
34
+ @param {Core} self Reference to including object
35
+ ###
36
+
37
+ ###*
38
+ Triggered every time the object should be drawn. A canvas is passed as
39
+ the first argument.
40
+
41
+ player = Core
42
+ x: 0
43
+ y: 10
44
+ width: 5
45
+ height: 5
46
+
47
+ player.bind "draw", (canvas) ->
48
+ # Text will be drawn positioned relatively to the object.
49
+ canvas.drawText
50
+ text: "Hey, drawing stuff is pretty easy."
51
+ color: "white"
52
+ x: 5
53
+ y: 5
54
+
55
+ @name draw
56
+ @methodOf Drawable#
57
+ @event
58
+ @param {PowerCanvas} canvas A reference to the canvas to draw on.
59
+ ###
60
+
61
+ ###*
62
+ Triggered before the object should be drawn. A canvas is passed as
63
+ the first argument. This does not apply the current transform.
64
+
65
+ @name beforeTransform
66
+ @methodOf Drawable#
67
+ @event
68
+ @param {PowerCanvas} canvas A reference to the canvas to draw on.
69
+ ###
70
+
71
+ ###*
72
+ Triggered after the object should be drawn. A canvas is passed as
73
+ the first argument. This applies the current transform.
74
+
75
+ @name afterTransform
76
+ @methodOf Drawable#
77
+ @event
78
+ @param {PowerCanvas} canvas A reference to the canvas to draw on.
79
+ ###
80
+
81
+ Drawable = (I={}, self) ->
82
+ Object.reverseMerge I,
83
+ alpha: 1
84
+ color: "#196"
85
+ scale: 1
86
+ scaleX: 1
87
+ scaleY: 1
88
+ zIndex: 0
89
+
90
+ cachedSprite = null
91
+
92
+ self.unbind ".Drawable"
93
+
94
+ self.bind 'draw.Drawable', (canvas) ->
95
+ if I.alpha? and I.alpha != 1
96
+ previousAlpha = canvas.context().globalAlpha
97
+ canvas.context().globalAlpha = I.alpha
98
+
99
+ if sprite = self.sprite()
100
+ if sprite.draw?
101
+ sprite.draw(canvas, -sprite.width / 2, -sprite.height / 2)
102
+ else
103
+ warn?("Sprite has no draw method!")
104
+ else
105
+ if I.radius?
106
+ canvas.drawCircle
107
+ x: 0
108
+ y: 0
109
+ radius: I.radius
110
+ color: I.color
111
+ else
112
+ canvas.drawRect
113
+ x: -I.width/2
114
+ y: -I.height/2
115
+ width: I.width
116
+ height: I.height
117
+ color: I.color
118
+
119
+ if I.alpha? and I.alpha != 1
120
+ canvas.context().globalAlpha = previousAlpha
121
+
122
+ ###*
123
+ Draw does not actually do any drawing itself, instead it triggers all of the draw events.
124
+ Listeners on the events do the actual drawing.
125
+
126
+ @name draw
127
+ @methodOf Drawable#
128
+ @returns self
129
+ ###
130
+ draw: (canvas) ->
131
+ self.trigger 'beforeTransform', canvas
132
+
133
+ canvas.withTransform self.transform(), (canvas) ->
134
+ self.trigger 'beforeDraw', canvas
135
+ self.trigger 'draw', canvas
136
+ self.trigger 'afterDraw', canvas
137
+
138
+ self.trigger 'afterTransform', canvas
139
+
140
+ return self
141
+
142
+ sprite: (newSprite) ->
143
+ if newSprite?
144
+ cachedSprite = newSprite
145
+ else
146
+ if I.sprite
147
+ Sprite.loadByName(I.sprite)
148
+
149
+ ###*
150
+ Returns the current transform, with translation, rotation, and flipping applied.
151
+
152
+ @name transform
153
+ @methodOf Drawable#
154
+ @returns {Matrix} The current transform
155
+ ###
156
+ transform: ->
157
+ center = self.center()
158
+
159
+ transform = Matrix.translation(center.x.floor(), center.y.floor())
160
+
161
+ transform = transform.concat(Matrix.scale(I.scale * I.scaleX, I.scale * I.scaleY))
162
+ transform = transform.concat(Matrix.rotation(I.rotation)) if I.rotation
163
+
164
+ if I.spriteOffset
165
+ transform = transform.concat(Matrix.translation(I.spriteOffset.x, I.spriteOffset.y))
166
+
167
+ return transform
@@ -0,0 +1,36 @@
1
+ DustParticle = (I={}, self) ->
2
+ Object.extend I,
3
+ color: 'rgb(100, 100, 100)'
4
+ duration: 0.2
5
+ fadeOut: true
6
+ maxSpeed: 90
7
+
8
+ I.velocity = [
9
+ Point(-60, -30)
10
+ Point(40, -15)
11
+ Point(-20, -7)
12
+ Point(60, -30)
13
+ Point(40, -15)
14
+ Point(20, -7)
15
+ ].rand()
16
+
17
+ I.acceleration = Point(0, 60)
18
+
19
+ return {}
20
+
21
+ DustEmitter = (I={}) ->
22
+ Object.reverseMerge I,
23
+ duration: 3
24
+ particleCount: 20
25
+ batchSize: 5
26
+ x: 0
27
+ y: 0
28
+ zIndex: 50
29
+ generator:
30
+ includedModules: ["DustParticle"]
31
+ radius: (n) ->
32
+ [2, 3, 1].wrap(n)
33
+
34
+ self = Emitter(I)
35
+
36
+ return self
@@ -0,0 +1,38 @@
1
+ ( ->
2
+ Easing =
3
+ sinusoidal: (begin, end) ->
4
+ change = end - begin
5
+ (t) -> begin + change * (1 - Math.cos(t * Math.TAU / 4))
6
+
7
+ sinusoidalOut: (begin, end) ->
8
+ change = end - begin
9
+ (t) -> begin + change * (0 + Math.sin(t * Math.TAU / 4))
10
+
11
+ polynomialEasings = ["linear", "quadratic", "cubic", "quartic", "quintic"]
12
+
13
+ polynomialEasings.each (easing, i) ->
14
+ exponent = i + 1
15
+ sign = if exponent % 2 then 1 else -1
16
+
17
+ Easing[easing] = (begin, end) ->
18
+ change = (end - begin)
19
+ (t) -> begin + change * Math.pow(t, exponent)
20
+
21
+ Easing["#{easing}Out"] = (begin, end) ->
22
+ change = end - begin
23
+ (t) -> begin + change * (1 + sign * Math.pow(t - 1, exponent))
24
+
25
+ ["sinusoidal"].concat(polynomialEasings).each (easing) ->
26
+ Easing["#{easing}InOut"] = (begin, end) ->
27
+ midpoint = (begin + end)/2
28
+ easeIn = Easing[easing](begin, midpoint)
29
+ easeOut = Easing["#{easing}Out"](midpoint, end)
30
+
31
+ (t) ->
32
+ if t < 0.5
33
+ easeIn(2 * t)
34
+ else
35
+ easeOut(2 * t - 1)
36
+
37
+ (exports ? this)["Easing"] = Easing
38
+ )()
@@ -0,0 +1,7 @@
1
+ # Just a placeholder class if you don't want to include the module yourself.
2
+ Emitter = (I={}) ->
3
+ self = GameObject(I)
4
+
5
+ self.include "Emitterable"
6
+
7
+ return self
@@ -0,0 +1,68 @@
1
+ # TODO: LOL at name
2
+ Emitterable = (I={}, self) ->
3
+ Object.reverseMerge I,
4
+ batchSize: 1
5
+ emissionRate: 1
6
+ width: 0
7
+ height: 0
8
+ sprite: Sprite.EMPTY
9
+ generator: {}
10
+ particles: []
11
+ particleCount: Infinity
12
+ x: I.x
13
+ y: I.y
14
+ particleData:
15
+ acceleration: Point(0, 0.1)
16
+ age: 0
17
+ color: "blue"
18
+ duration: 1.5
19
+ height: 2
20
+ maxSpeed: 120
21
+ offset: Point(0, 0)
22
+ sprite: false
23
+ spriteName: false
24
+ velocity: Point(-0.25, 1)
25
+ width: 2
26
+ x: 0
27
+ y: 0
28
+
29
+ n = 0
30
+
31
+ self.bind 'draw', (canvas) ->
32
+ I.particles.invoke "draw", canvas
33
+
34
+ self.bind 'overlay', (canvas) ->
35
+ I.particles.invoke "trigger", "overlay", canvas
36
+
37
+ self.bind 'beforeUpdate', (dt) ->
38
+ I.particles.invoke "trigger", "beforeUpdate", dt
39
+
40
+ self.bind 'afterUpdate', (dt) ->
41
+ I.particles.invoke "trigger", "afterUpdate", dt
42
+
43
+ self.bind 'update', (dt) ->
44
+ I.batchSize.times ->
45
+ if n < I.particleCount && rand() < I.emissionRate
46
+ particleProperties = Object.extend {}, I.particleData
47
+
48
+ for key, value of I.generator
49
+ if I.generator[key].call
50
+ particleProperties[key] = I.generator[key](n, I)
51
+ else
52
+ particleProperties[key] = I.generator[key]
53
+
54
+ particleProperties.x += particleProperties.offset.x
55
+ particleProperties.y += particleProperties.offset.y
56
+
57
+ I.particles.push(GameObject(particleProperties))
58
+
59
+ n += 1
60
+
61
+ I.particles = I.particles.select (particle) ->
62
+ particle.update(dt)
63
+
64
+ if n == I.particleCount && !I.particles.length
65
+ I.active = false
66
+
67
+ return {}
68
+