pixie_dust 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 (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
+