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,3 @@
1
+ module PixieDust
2
+ VERSION = "0.0.1"
3
+ end
data/lib/pixie_dust.rb ADDED
@@ -0,0 +1,14 @@
1
+ require "pixie_dust/version"
2
+
3
+ require "cornerstone-source"
4
+
5
+ if defined? ::Rails
6
+ class Engine < ::Rails::Engine
7
+ config.paths['app/assets'] = "source"
8
+ end
9
+ elsif defined? ::Sprockets
10
+ root_dir = File.expand_path(File.dirname(File.dirname(__FILE__)))
11
+ asset_dir = File.join(root_dir, "source")
12
+
13
+ ::Sprockets.append_path asset_dir
14
+ end
data/pixie.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "author": "STRd6",
3
+ "main": null,
4
+ "name": "gamelib",
5
+ "library": true,
6
+ "libs": {
7
+ "corelib.js": "https://raw.github.com/PixieEngine/Cornerstone/pixie/game.js"
8
+ },
9
+ "directories": {
10
+ "lib": "lib",
11
+ "source": "source",
12
+ "test": "test"
13
+ },
14
+ "autosave": true
15
+ }
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'pixie_dust/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "pixie_dust"
8
+ spec.version = PixieDust::VERSION
9
+ spec.authors = ["Daniel Moore"]
10
+ spec.email = ["yahivin@gmail.com"]
11
+ spec.description = %q{
12
+ Amazing libraries for developing games.
13
+ Defines the main PixieEngine GameObject and includes mixins to easily augment their behavior.
14
+ }
15
+
16
+ spec.summary = %q{Amazing libraries for developing games}
17
+ spec.homepage = ""
18
+ spec.license = "MIT"
19
+
20
+ spec.files = `git ls-files`.split($/)
21
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
22
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
23
+ spec.require_paths = ["lib"]
24
+
25
+ spec.add_development_dependency "bundler", "~> 1.3"
26
+ spec.add_development_dependency "rake"
27
+
28
+ spec.add_dependency "cornerstone-source"
29
+ end
@@ -0,0 +1,48 @@
1
+ ###*
2
+ The ActiveBounds module automatically destroys objects that
3
+ are outside of the specified bounds. The default bounds are
4
+ the dimensions of your game. Useful for bullet type objects.
5
+
6
+ bullet = GameObject
7
+ x: 10
8
+ y: 50
9
+ width: 20
10
+ height: 20
11
+ velocity: Point(120, 0)
12
+
13
+ bullet.include ActiveBounds
14
+
15
+ # => bullet will be removed when it
16
+ goes outside of the game bounds.
17
+
18
+ bullet2 = GameObject
19
+ x: 50
20
+ y: 50
21
+ width: 30
22
+ height: 20
23
+ activeBounds: Rectangle
24
+ x: 30
25
+ y: 20
26
+ width: 100
27
+ height 100
28
+
29
+ # => bullet2 will be removed unless 30 <= I.x <= 130
30
+ and 20 <= I.y <= 120
31
+
32
+ @name ActiveBounds
33
+ @module
34
+ @constructor
35
+ @param {Object} I Instance variables
36
+ @param {Core} self Reference to including object
37
+ ###
38
+ ActiveBounds = (I={}, self) ->
39
+ Object.reverseMerge I,
40
+ activeBounds: Rectangle
41
+ x: 0
42
+ y: 0
43
+ width: App.width
44
+ height: App.height
45
+
46
+ self.bind 'update', ->
47
+ self.destroy() unless I.activeBounds.left <= I.x <= I.activeBounds.right
48
+ self.destroy() unless I.activeBounds.top <= I.y <= I.activeBounds.bottom
@@ -0,0 +1,23 @@
1
+ ###*
2
+ The Ageable module handles keeping track of an object's age.
3
+
4
+ player = GameObject()
5
+
6
+ player.update(1)
7
+
8
+ #=> player.I.age == 1
9
+
10
+ @name Ageable
11
+ @module
12
+ @constructor
13
+ @param {Object} I Instance variables
14
+ @param {Core} self Reference to including object
15
+ ###
16
+ Ageable = (I={}, self) ->
17
+ Object.reverseMerge I,
18
+ age: 0
19
+
20
+ self.bind 'afterUpdate', (dt) ->
21
+ I.age += dt
22
+
23
+ return {}
@@ -0,0 +1,282 @@
1
+ ###*
2
+ The Bounded module is used to provide basic data about the
3
+ location and dimensions of the including object. This module is included
4
+ by default in `GameObject`.
5
+
6
+ player = Core
7
+ x: 10
8
+ y: 50
9
+ width: 20
10
+ height: 20
11
+ other: "stuff"
12
+ more: "properties"
13
+
14
+ player.position()
15
+ # => Uncaught TypeError: Object has no method 'position'
16
+
17
+ player.include(Bounded)
18
+
19
+ # now player has all the methods provided by this module
20
+ player.position()
21
+ # => {x: 10, y: 50}
22
+
23
+ @see GameObject
24
+
25
+ Bounded module
26
+ @name Bounded
27
+ @module
28
+ @constructor
29
+ @param {Object} I Instance variables
30
+ @param {Core} self Reference to including object
31
+ ###
32
+
33
+ Bounded = (I={}, self) ->
34
+ Object.reverseMerge I,
35
+ x: 0
36
+ y: 0
37
+ width: 8
38
+ height: 8
39
+ collisionMargin: Point(0, 0)
40
+
41
+ ###*
42
+ Get the object closest to this one.
43
+
44
+ @name closest
45
+ @methodOf Bounded#
46
+ @param {Object|Array|String} selector An object or set of objects to find the closest from.
47
+ ###
48
+ closest: (selector) ->
49
+ if Object.isString(selector)
50
+ selector = engine.find(selector)
51
+ else
52
+ selector = [].concat(selector)
53
+
54
+ position = self.position()
55
+
56
+ selector.sort (a, b) ->
57
+ Point.distanceSquared(position, a.position()) - Point.distanceSquared(position, b.position())
58
+ .first()
59
+
60
+ ###*
61
+ Distance between two objects. Proxies to Point.distance.
62
+ In order for this to work, `otherObj` must have a
63
+ position method.
64
+
65
+ player = GameObject
66
+ x: 50
67
+ y: 50
68
+ width: 10
69
+ height: 10
70
+
71
+ player.include Bounded
72
+
73
+ enemy = GameObject
74
+ x: 110
75
+ y: 120
76
+ width: 7
77
+ height: 20
78
+
79
+ player.distance(enemy)
80
+ # => 92.19544457292888
81
+
82
+ @name distance
83
+ @methodOf Bounded#
84
+ @see Point.distance
85
+ @returns {Number} Distance between the two objects
86
+ ###
87
+ distance: (otherObj) ->
88
+ Point.distance(self.position(), otherObj.position())
89
+
90
+ ###*
91
+ The position of this game object. By default it is the top left point.
92
+ Redefining the center method will change the relative position.
93
+
94
+ player = Core
95
+ x: 50
96
+ y: 40
97
+
98
+ player.include(Bounded)
99
+
100
+ player.position()
101
+ # => {x: 50, y: 40}
102
+
103
+ @name position
104
+ @methodOf Bounded#
105
+ @returns {Point} The position of this object
106
+ ###
107
+ position: (newPosition) ->
108
+ if newPosition?
109
+ I.x = newPosition.x
110
+ I.y = newPosition.y
111
+ else
112
+ Point(I.x, I.y)
113
+
114
+ changePosition: (delta) ->
115
+ I.x += delta.x
116
+ I.y += delta.y
117
+
118
+ self
119
+
120
+ ###*
121
+ Does a check to see if this object is overlapping
122
+ with the bounds passed in.
123
+
124
+ player = Core
125
+ x: 4
126
+ y: 6
127
+ width: 20
128
+ height: 20
129
+
130
+ player.include(Bounded)
131
+
132
+ player.collides({x: 5, y: 7, width: 20, height: 20})
133
+ # => true
134
+
135
+ @name collides
136
+ @methodOf Bounded#
137
+ @returns {Point} The position of this object
138
+ ###
139
+ collides: (bounds) ->
140
+ Collision.rectangular(self.bounds(), bounds)
141
+
142
+ ###*
143
+ This returns a modified bounds based on the collision margin.
144
+ The area of the bounds is reduced if collision margin is positive
145
+ and increased if collision margin is negative.
146
+
147
+ player = Core
148
+ collisionMargin:
149
+ x: -2
150
+ y: -4
151
+ x: 50
152
+ y: 50
153
+ width: 20
154
+ height: 20
155
+
156
+ player.include(Bounded)
157
+
158
+ player.collisionBounds()
159
+ # => {x: 38, y: 36, height: 28, width: 24}
160
+
161
+ player.collisionBounds(10, 10)
162
+ # => {x: 48, y: 46, height: 28, width: 24}
163
+
164
+ @name collisionBounds
165
+ @methodOf Bounded#
166
+ @param {Number} xOffset the amount to shift the x position
167
+ @param {Number} yOffset the amount to shift the y position
168
+ @returns {Object} The collision bounds
169
+ ###
170
+ collisionBounds: (xOffset, yOffset) ->
171
+ bounds = self.bounds(xOffset, yOffset)
172
+
173
+ bounds.x += I.collisionMargin.x
174
+ bounds.y += I.collisionMargin.y
175
+ bounds.width -= 2 * I.collisionMargin.x
176
+ bounds.height -= 2 * I.collisionMargin.y
177
+
178
+ return bounds
179
+
180
+ ###*
181
+ Returns infomation about the location of the object and its dimensions with optional offsets.
182
+
183
+ player = Core
184
+ x: 3
185
+ y: 6
186
+ width: 2
187
+ height: 2
188
+
189
+ player.include(Bounded)
190
+
191
+ player.bounds()
192
+ # => {x: 3, y: 6, width: 2, height: 2}
193
+
194
+ player.bounds(7, 4)
195
+ # => {x: 10, y: 10, width: 2, height: 2}
196
+
197
+ @name bounds
198
+ @methodOf Bounded#
199
+ @param {Number} xOffset the amount to shift the x position
200
+ @param {Number} yOffset the amount to shift the y position
201
+ ###
202
+ bounds: (xOffset, yOffset) ->
203
+ center = self.center()
204
+
205
+ x: center.x - I.width/2 + (xOffset || 0)
206
+ y: center.y - I.height/2 + (yOffset || 0)
207
+ width: I.width
208
+ height: I.height
209
+
210
+ ###*
211
+ The centeredBounds method returns infomation about the center
212
+ of the object along with the midpoint of the width and height.
213
+
214
+ player = Core
215
+ x: 3
216
+ y: 6
217
+ width: 2
218
+ height: 2
219
+
220
+ player.include(Bounded)
221
+
222
+ player.centeredBounds()
223
+ # => {x: 4, y: 7, xw: 1, yw: 1}
224
+
225
+ @name centeredBounds
226
+ @methodOf Bounded#
227
+ ###
228
+ centeredBounds: () ->
229
+ center = self.center()
230
+
231
+ x: center.x
232
+ y: center.y
233
+ xw: I.width/2
234
+ yw: I.height/2
235
+
236
+ ###*
237
+ The center method returns the {@link Point} that is
238
+ the center of the object.
239
+
240
+ player = Core
241
+ x: 50
242
+ y: 40
243
+ width: 10
244
+ height: 30
245
+
246
+ player.include(Bounded)
247
+
248
+ player.center()
249
+ # => {x: 30, y: 35}
250
+
251
+ @name center
252
+ @methodOf Bounded#
253
+ @returns {Point} The middle of the calling object
254
+ ###
255
+ center: (newCenter) ->
256
+ self.position(newCenter)
257
+
258
+ ###*
259
+ Return the circular bounds of the object. The circle is
260
+ centered at the midpoint of the object.
261
+
262
+ player = Core
263
+ radius: 5
264
+ x: 50
265
+ y: 50
266
+ other: "stuff"
267
+
268
+ player.include(Bounded)
269
+
270
+ player.circle()
271
+ # => {radius: 5, x: 50, y: 50}
272
+
273
+ @name circle
274
+ @methodOf Bounded#
275
+ @returns {Object} An object with a position and a radius
276
+ ###
277
+ circle: () ->
278
+ circle = self.center()
279
+ circle.radius = I.radius || I.width/2 || I.height/2
280
+
281
+ return circle
282
+
@@ -0,0 +1,138 @@
1
+ oldCamera = Camera
2
+
3
+ Camera = (I={}) ->
4
+ Object.reverseMerge I,
5
+ cameraBounds: Rectangle # World Coordinates
6
+ x: 0
7
+ y: 0
8
+ width: App.width
9
+ height: App.height
10
+ screen: Rectangle # Screen Coordinates
11
+ x: 0
12
+ y: 0
13
+ width: App.width
14
+ height: App.height
15
+ deadzone: Point(0, 0) # Screen Coordinates
16
+ zoom: 1
17
+ transform: Matrix()
18
+ x: App.width/2 # World Coordinates
19
+ y: App.height/2 # World Coordinates
20
+ velocity: Point.ZERO
21
+ maxSpeed: 25
22
+ t90: 2 # Time in seconds for camera to move 90% of the way to the target
23
+
24
+ currentType = "centered"
25
+ currentObject = null
26
+
27
+ objectFilters = []
28
+ transformFilters = []
29
+
30
+ focusOn = (object, elapsedTime) ->
31
+ dampingFactor = 2
32
+
33
+ #TODO: Different t90 value inside deadzone?
34
+
35
+ c = elapsedTime * 3.75 / I.t90
36
+ if c >= 1
37
+ # Spring is configured to be too intense, just snap to target
38
+ self.position(target)
39
+ I.velocity = Point.ZERO
40
+ else
41
+ objectCenter = object.center()
42
+
43
+ target = objectCenter
44
+
45
+ delta = target.subtract(self.position())
46
+
47
+ force = delta.subtract(I.velocity.scale(dampingFactor))
48
+ self.changePosition(I.velocity.scale(c).clamp(I.maxSpeed))
49
+ I.velocity = I.velocity.add(force.scale(c))
50
+
51
+ followTypes =
52
+ centered: (object, elapsedTime) ->
53
+ I.deadzone = Point(0, 0)
54
+
55
+ focusOn(object, elapsedTime)
56
+
57
+ topdown: (object, elapsedTime) ->
58
+ helper = Math.max(I.screen.width, I.screen.height) / 4
59
+
60
+ I.deadzone = Point(helper, helper)
61
+
62
+ focusOn(object, elapsedTime)
63
+
64
+ platformer: (object, elapsedTime) ->
65
+ width = I.screen.width / 8
66
+ height = I.screen.height / 3
67
+
68
+ I.deadzone = Point(width, height)
69
+
70
+ focusOn(object, elapsedTime)
71
+
72
+ self = Core(I).extend
73
+ follow: (object, type="centered") ->
74
+ currentObject = object
75
+ currentType = type
76
+
77
+ objectFilterChain: (fn) ->
78
+ objectFilters.push fn
79
+
80
+ transformFilterChain: (fn) ->
81
+ transformFilters.push fn
82
+
83
+ screenToWorld: (point) ->
84
+ self.transform().inverse().transformPoint(point)
85
+
86
+ self.attrAccessor "transform"
87
+
88
+ self.bind "afterUpdate", (elapsedTime) ->
89
+ if currentObject
90
+ followTypes[currentType](currentObject, elapsedTime)
91
+
92
+ # Hard clamp camera to world bounds
93
+ I.x = I.x.clamp(I.cameraBounds.left + I.screen.width/2, I.cameraBounds.right - I.screen.width/2)
94
+ I.y = I.y.clamp(I.cameraBounds.top + I.screen.height/2, I.cameraBounds.bottom - I.screen.height/2)
95
+
96
+ I.transform = Matrix.translate(I.screen.width/2 - I.x.floor(), I.screen.height/2 - I.y.floor())
97
+
98
+ self.bind "draw", (canvas, objects) ->
99
+ # Move to correct screen coordinates
100
+ canvas.withTransform Matrix.translate(I.screen.x, I.screen.y), (canvas) ->
101
+ canvas.clip(0, 0, I.screen.width, I.screen.height)
102
+
103
+ objects = objectFilters.pipeline(objects)
104
+ transform = transformFilters.pipeline(self.transform().copy())
105
+
106
+ canvas.withTransform transform, (canvas) ->
107
+ self.trigger "beforeDraw", canvas
108
+ objects.invoke "draw", canvas
109
+
110
+ self.trigger 'flash', canvas
111
+
112
+ self.bind "overlay", (canvas, objects) ->
113
+ canvas.withTransform Matrix.translate(I.screen.x, I.screen.y), (canvas) ->
114
+ canvas.clip(0, 0, I.screen.width, I.screen.height)
115
+ objects = objectFilters.pipeline(objects)
116
+
117
+ objects.invoke "trigger", "overlay", canvas
118
+
119
+ self.include "Bounded"
120
+
121
+ # The order of theses includes is important for
122
+ # the way in wich they modify the camera view transform
123
+
124
+ for moduleName in Camera.defaultModules
125
+ self.include "Camera.#{moduleName}"
126
+
127
+ return self
128
+
129
+ Camera.defaultModules = [
130
+ "ZSort"
131
+ "Zoom"
132
+ "Rotate"
133
+ "Shake"
134
+ "Flash"
135
+ "Fade"
136
+ ]
137
+
138
+ Object.extend Camera, oldCamera
@@ -0,0 +1,69 @@
1
+ ###*
2
+ The <code>Fade</code> module provides convenience methods for accessing common Engine.Flash presets.
3
+
4
+ @name Fade
5
+ @fieldOf Camera
6
+ @module
7
+ @param {Object} I Instance variables
8
+ @param {Object} self Reference to the engine
9
+ @see Camera.Flash
10
+ ###
11
+ Camera.Fade = (I, self) ->
12
+ fadeInDefaults =
13
+ alpha: 0
14
+ color: 'black'
15
+ duration: 30
16
+
17
+ fadeOutDefaults =
18
+ alpha: 1
19
+ color: 'transparent'
20
+ duration: 30
21
+
22
+ configureFade = (duration, color, alpha) ->
23
+ I.flashDuration = duration
24
+ I.flashCooldown = duration
25
+ I.flashColor = Color(color)
26
+ I.flashTargetAlpha = alpha
27
+
28
+ ###*
29
+ A convenient way to set the flash effect instance variables. This provides a shorthand for fading the screen in
30
+ from a given color over a specified duration.
31
+
32
+ engine.fadeIn()
33
+ # => Sets the effect variables to their default state. This will the screen to go from black to transparent over the next 30 frames.
34
+
35
+ engine.fadeIn('blue', 50)
36
+ # => This effect will start off blue and fade to transparent over 50 frames.
37
+
38
+ @name fadeIn
39
+ @methodOf Camera#
40
+ @param {Number} [duration=30] How long the effect lasts
41
+ @param {Color} [color="black"] The color to fade from
42
+ ###
43
+ fadeIn: (options={}) ->
44
+ {alpha, color, duration} = Object.reverseMerge(options, fadeInDefaults)
45
+
46
+ configureFade(duration, color, alpha)
47
+
48
+ ###*
49
+ A convenient way to set the flash effect instance variables. This provides a shorthand for fading
50
+ the screen to a given color over a specified duration.
51
+
52
+ camera.fadeOut()
53
+ # => Sets the effect variables to their default state. This will the screen to fade from ransparent to black over the next 30 frames.
54
+
55
+ camera.fadeOut
56
+ color: blue
57
+ duration: 30
58
+ # => This effect will start off transparent and change to blue over 50 frames.
59
+
60
+ @name fadeOut
61
+ @methodOf Camera#
62
+ @param {Number} [duration=30] How long the effect lasts
63
+ @param {Color} [color="transparent"] The color to fade to
64
+ ###
65
+ fadeOut: (options={}) ->
66
+ {alpha, color, duration} = Object.reverseMerge(options, fadeOutDefaults)
67
+
68
+ configureFade(duration, color, alpha)
69
+
@@ -0,0 +1,69 @@
1
+ ###*
2
+ The <code>Flash</code> module allows you to flash a color onscreen and then fade to transparent over a time period.
3
+ This is nice for lightning type effects or to accentuate major game events.
4
+
5
+ @name Flash
6
+ @fieldOf Camera
7
+ @module
8
+ @param {Object} I Instance variables
9
+ @param {Object} self Reference to the camera
10
+ ###
11
+ Camera.Flash = (I, self) ->
12
+ Object.reverseMerge I,
13
+ flashColor: Color(0, 0, 0, 0)
14
+ flashDuration: 12
15
+ flashCooldown: 0
16
+ flashTargetAlpha: 0
17
+
18
+ defaultParams =
19
+ color: 'white'
20
+ duration: 12
21
+ targetAlpha: 0
22
+
23
+ self.bind 'afterUpdate', ->
24
+ if I.flashCooldown > 0
25
+ I.flashColor.a = I.flashColor.a.approach(I.flashTargetAlpha, 1 / I.flashDuration).clamp(0, 1)
26
+ I.flashColor.a = 0 if I.flashColor.a < 0.00001
27
+ I.flashColor.a = 1 if I.flashColor.a > 0.9999
28
+
29
+ I.flashCooldown = I.flashCooldown.approach(0, 1)
30
+
31
+ self.bind 'flash', (canvas) ->
32
+ canvas.fill I.flashColor
33
+
34
+ ###*
35
+ A convenient way to set the flash effect instance variables. Alternatively, you can modify them by hand, but
36
+ using Camera#flash is the suggested approach.
37
+
38
+ camera.flash()
39
+ # => Sets the flash effect variables to their default state. This will cause a white flash that will turn transparent in the next 12 frames.
40
+
41
+ camera.flash
42
+ color: 'green'
43
+ duration: 30
44
+ # => This flash effect will start off green and fade to transparent over 30 frames.
45
+
46
+ camera.flash
47
+ color: Color(255, 0, 0, 0)
48
+ duration: 20
49
+ targetAlpha: 1
50
+ # => This flash effect will start off transparent and move toward red over 20 frames
51
+
52
+ @name flash
53
+ @methodOf Camera#
54
+ @param {Color} [color="white"] The flash color
55
+ @param {Number} [duration=12] How long the effect lasts
56
+ @param {Number} [targetAlpha=0] The alpha value to fade to. By default, this is set to 0, which fades the color to transparent.
57
+ ###
58
+ flash: (options={}) ->
59
+ Object.reverseMerge(options, defaultParams)
60
+
61
+ {color, duration, targetAlpha} = options
62
+
63
+ I.flashColor = Color(color)
64
+ I.flashTargetAlpha = targetAlpha
65
+ I.flashCooldown = duration
66
+ I.flashDuration = duration
67
+
68
+ self
69
+
@@ -0,0 +1,11 @@
1
+ Camera.Rotate = (I, self) ->
2
+ Object.reverseMerge I,
3
+ rotation: 0
4
+
5
+ self.transformFilterChain (transform) ->
6
+ transform.rotate(I.rotation, self.position())
7
+
8
+ self.attrAccessor "rotation"
9
+
10
+ rotate: (amount) ->
11
+ self.rotation(I.rotation + amount)