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,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)