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.
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README +16 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/game.js +9200 -0
- data/lib/corelib.js +3331 -0
- data/lib/pixie_dust/version.rb +3 -0
- data/lib/pixie_dust.rb +14 -0
- data/pixie.json +15 -0
- data/pixie_dust.gemspec +29 -0
- data/source/active_bounds.coffee +48 -0
- data/source/ageable.coffee +23 -0
- data/source/bounded.coffee +282 -0
- data/source/camera.coffee +138 -0
- data/source/camera.fade.coffee +69 -0
- data/source/camera.flash.coffee +69 -0
- data/source/camera.rotate.coffee +11 -0
- data/source/camera.shake.coffee +27 -0
- data/source/camera.zoom.coffee +25 -0
- data/source/camera.zsort.coffee +13 -0
- data/source/clampable.coffee +61 -0
- data/source/collidable.coffee +126 -0
- data/source/collision.coffee +272 -0
- data/source/collision_response.coffee +28 -0
- data/source/color.coffee +1113 -0
- data/source/color_table.coffee +2534 -0
- data/source/controllable.coffee +66 -0
- data/source/cooldown.coffee +82 -0
- data/source/debuggable.coffee +253 -0
- data/source/drawable.coffee +167 -0
- data/source/dust_emitter.coffee +36 -0
- data/source/easing.coffee +38 -0
- data/source/emitter.coffee +7 -0
- data/source/emitterable.coffee +68 -0
- data/source/engine.coffee +274 -0
- data/source/engine.collision.coffee +77 -0
- data/source/engine.data.coffee +23 -0
- data/source/engine.delay.coffee +41 -0
- data/source/engine.fps_counter.coffee +32 -0
- data/source/engine.game_state.coffee +86 -0
- data/source/engine.joysticks.coffee +47 -0
- data/source/engine.keyboard.coffee +17 -0
- data/source/engine.levels.coffee +69 -0
- data/source/engine.mouse.coffee +16 -0
- data/source/engine.selector.coffee +166 -0
- data/source/engine.stats.coffee +16 -0
- data/source/engine.tilemap.coffee +41 -0
- data/source/engine_background.coffee +32 -0
- data/source/expirable.coffee +47 -0
- data/source/flickerable.coffee +78 -0
- data/source/follow.coffee +65 -0
- data/source/framerate.coffee +42 -0
- data/source/game_object.coffee +181 -0
- data/source/game_object.effect.coffee +33 -0
- data/source/game_object.meter.coffee +191 -0
- data/source/game_over.coffee +40 -0
- data/source/game_state.coffee +67 -0
- data/source/game_state.save_state.coffee +76 -0
- data/source/game_state.single_camera.coffee +40 -0
- data/source/game_state_cameras.coffee +33 -0
- data/source/level_state.coffee +32 -0
- data/source/movable.coffee +57 -0
- data/source/oscillator.coffee +18 -0
- data/source/pixie_dust.coffee +2 -0
- data/source/resource_loader.coffee +35 -0
- data/source/rotatable.coffee +38 -0
- data/source/sprite.coffee +181 -0
- data/source/text_effect.coffee +74 -0
- data/source/text_effect.floating.coffee +22 -0
- data/source/text_screen.coffee +38 -0
- data/source/tilemap.coffee +56 -0
- data/source/timed_events.coffee +78 -0
- data/source/title_screen.coffee +38 -0
- data/source/tween.coffee +70 -0
- data/test/active_bounds.coffee +67 -0
- data/test/bounded.coffee +98 -0
- data/test/camera.coffee +29 -0
- data/test/clampable.coffee +18 -0
- data/test/collidable.coffee +51 -0
- data/test/collision.coffee +70 -0
- data/test/color.coffee +533 -0
- data/test/controllable.coffee +108 -0
- data/test/cooldown.coffee +116 -0
- data/test/debuggable.coffee +71 -0
- data/test/drawable.coffee +31 -0
- data/test/emitter.coffee +0 -0
- data/test/emitterable.coffee +15 -0
- data/test/engine.coffee +228 -0
- data/test/engine_data.coffee +12 -0
- data/test/engine_delay.coffee +14 -0
- data/test/engine_selector.coffee +100 -0
- data/test/expirable.coffee +35 -0
- data/test/flickerable.coffee +51 -0
- data/test/follow.coffee +34 -0
- data/test/game_object.coffee +78 -0
- data/test/game_object_effect.coffee +17 -0
- data/test/metered.coffee +33 -0
- data/test/movable.coffee +46 -0
- data/test/oscillator.coffee +28 -0
- data/test/resource_loader.coffee +7 -0
- data/test/rotatable.coffee +20 -0
- data/test/sprite.coffee +21 -0
- data/test/text.coffee +25 -0
- data/test/timed_events.coffee +23 -0
- data/test/tweening.coffee +18 -0
- metadata +233 -0
@@ -0,0 +1,181 @@
|
|
1
|
+
###*
|
2
|
+
The Sprite class provides a way to load images for use in games.
|
3
|
+
|
4
|
+
By default, images are loaded asynchronously. A proxy object is
|
5
|
+
returned immediately. Even though it has a draw method it will not
|
6
|
+
draw anything to the screen until the image has been loaded.
|
7
|
+
|
8
|
+
@name Sprite
|
9
|
+
@constructor
|
10
|
+
###
|
11
|
+
|
12
|
+
( ->
|
13
|
+
LoaderProxy = ->
|
14
|
+
draw: ->
|
15
|
+
fill: ->
|
16
|
+
frame: ->
|
17
|
+
update: ->
|
18
|
+
width: null
|
19
|
+
height: null
|
20
|
+
image: null
|
21
|
+
|
22
|
+
# Cache loaded images
|
23
|
+
spriteCache = {}
|
24
|
+
|
25
|
+
Sprite = (image, sourceX, sourceY, width, height) ->
|
26
|
+
sourceX ||= 0
|
27
|
+
sourceY ||= 0
|
28
|
+
width ||= image.width
|
29
|
+
height ||= image.height
|
30
|
+
|
31
|
+
###*
|
32
|
+
Draw this sprite on the given canvas at the given position.
|
33
|
+
|
34
|
+
@name draw
|
35
|
+
@methodOf Sprite#
|
36
|
+
@param {PowerCanvas} canvas Reference to the canvas to draw the sprite on
|
37
|
+
@param {Number} x Position on the x axis to draw the sprite
|
38
|
+
@param {Number} y Position on the y axis to draw the sprite
|
39
|
+
###
|
40
|
+
draw: (canvas, x, y) ->
|
41
|
+
canvas.drawImage(
|
42
|
+
image,
|
43
|
+
sourceX,
|
44
|
+
sourceY,
|
45
|
+
width,
|
46
|
+
height,
|
47
|
+
x,
|
48
|
+
y,
|
49
|
+
width,
|
50
|
+
height
|
51
|
+
)
|
52
|
+
|
53
|
+
###*
|
54
|
+
Draw this sprite on the given canvas tiled to the x, y,
|
55
|
+
width, and height dimensions specified.
|
56
|
+
|
57
|
+
@name fill
|
58
|
+
@methodOf Sprite#
|
59
|
+
@param {PowerCanvas} canvas Reference to the canvas to draw the sprite on
|
60
|
+
@param {Number} x Position on the x axis to draw the sprite
|
61
|
+
@param {Number} y Position on the y axis to draw the sprite
|
62
|
+
@param {Number} width How far to tile the sprite on the x-axis
|
63
|
+
@param {Number} height How far to tile the sprite on the y-axis
|
64
|
+
@param {String} repeat Repeat options. Can be `repeat-x`, `repeat-y`, `no-repeat`, or `repeat`. Defaults to `repeat`
|
65
|
+
###
|
66
|
+
fill: (canvas, x, y, width, height, repeat="repeat") ->
|
67
|
+
pattern = canvas.createPattern(image, repeat)
|
68
|
+
canvas.drawRect({x, y, width, height, color: pattern})
|
69
|
+
|
70
|
+
width: width
|
71
|
+
height: height
|
72
|
+
image: image
|
73
|
+
|
74
|
+
###*
|
75
|
+
Loads all sprites from a sprite sheet found in
|
76
|
+
your images directory, specified by the name passed in.
|
77
|
+
|
78
|
+
@name loadSheet
|
79
|
+
@methodOf Sprite
|
80
|
+
@param {String} name Name of the spriteSheet image in your images directory
|
81
|
+
@param {Number} tileWidth Width of each sprite in the sheet
|
82
|
+
@param {Number} tileHeight Height of each sprite in the sheet
|
83
|
+
@returns {Array} An array of sprite objects
|
84
|
+
###
|
85
|
+
Sprite.loadSheet = (name, tileWidth, tileHeight) ->
|
86
|
+
url = ResourceLoader.urlFor("images", name)
|
87
|
+
|
88
|
+
sprites = []
|
89
|
+
image = new Image()
|
90
|
+
|
91
|
+
image.onload = ->
|
92
|
+
imgElement = this
|
93
|
+
(image.height / tileHeight).times (row) ->
|
94
|
+
(image.width / tileWidth).times (col) ->
|
95
|
+
sprites.push(Sprite(imgElement, col * tileWidth, row * tileHeight, tileWidth, tileHeight))
|
96
|
+
|
97
|
+
image.src = url
|
98
|
+
|
99
|
+
return sprites
|
100
|
+
|
101
|
+
###*
|
102
|
+
Loads a sprite from a given url.
|
103
|
+
|
104
|
+
@name load
|
105
|
+
@methodOf Sprite
|
106
|
+
@param {String} url
|
107
|
+
@param {Function} [loadedCallback]
|
108
|
+
@returns {Sprite} A sprite object
|
109
|
+
###
|
110
|
+
Sprite.load = (url, loadedCallback) ->
|
111
|
+
if sprite = spriteCache[url]
|
112
|
+
loadedCallback?.defer(sprite)
|
113
|
+
return sprite
|
114
|
+
|
115
|
+
img = new Image()
|
116
|
+
proxy = LoaderProxy()
|
117
|
+
|
118
|
+
img.onload = ->
|
119
|
+
spriteCache[url] = Object.extend(proxy, Sprite(this))
|
120
|
+
|
121
|
+
loadedCallback?(proxy)
|
122
|
+
|
123
|
+
img.src = url
|
124
|
+
|
125
|
+
return proxy
|
126
|
+
|
127
|
+
###*
|
128
|
+
Loads a sprite with the given pixie id.
|
129
|
+
|
130
|
+
@name fromPixieId
|
131
|
+
@methodOf Sprite
|
132
|
+
@param {Number} id Pixie Id of the sprite to load
|
133
|
+
@param {Function} [callback] Function to execute once the image is loaded. The sprite proxy data is passed to this as a parameter.
|
134
|
+
@returns {Sprite}
|
135
|
+
###
|
136
|
+
Sprite.fromPixieId = (id, callback) ->
|
137
|
+
Sprite.load("http://pixieengine.com/s3/sprites/#{id}/original.png", callback)
|
138
|
+
|
139
|
+
###*
|
140
|
+
A sprite that draws nothing.
|
141
|
+
|
142
|
+
@name EMPTY
|
143
|
+
@fieldOf Sprite
|
144
|
+
@constant
|
145
|
+
@returns {Sprite}
|
146
|
+
###
|
147
|
+
###*
|
148
|
+
A sprite that draws nothing.
|
149
|
+
|
150
|
+
@name NONE
|
151
|
+
@fieldOf Sprite
|
152
|
+
@constant
|
153
|
+
@returns {Sprite}
|
154
|
+
###
|
155
|
+
Sprite.EMPTY = Sprite.NONE = LoaderProxy()
|
156
|
+
|
157
|
+
###*
|
158
|
+
Loads a sprite from a given url.
|
159
|
+
|
160
|
+
@name fromURL
|
161
|
+
@methodOf Sprite
|
162
|
+
@param {String} url The url where the image to load is located
|
163
|
+
@param {Function} [callback] Function to execute once the image is loaded. The sprite proxy data is passed to this as a parameter.
|
164
|
+
@returns {Sprite}
|
165
|
+
###
|
166
|
+
Sprite.fromURL = Sprite.load
|
167
|
+
|
168
|
+
###*
|
169
|
+
Loads a sprite with the given name.
|
170
|
+
|
171
|
+
@name loadByName
|
172
|
+
@methodOf Sprite
|
173
|
+
@param {String} name The name of the image in your images directory
|
174
|
+
@param {Function} [callback] Function to execute once the image is loaded. The sprite proxy data is passed to this as a parameter.
|
175
|
+
@returns {Sprite}
|
176
|
+
###
|
177
|
+
Sprite.loadByName = (name, callback) ->
|
178
|
+
Sprite.load(ResourceLoader.urlFor("images", name), callback)
|
179
|
+
|
180
|
+
(exports ? this)["Sprite"] = Sprite
|
181
|
+
)()
|
@@ -0,0 +1,74 @@
|
|
1
|
+
###*
|
2
|
+
The Text Effect class provides a method to display moving text onscreen, fading out the text over the effect duration.
|
3
|
+
|
4
|
+
# adds a TextEffect to the engine at (60, 100)
|
5
|
+
engine.add 'TextEffect'
|
6
|
+
x: 60
|
7
|
+
y: 100
|
8
|
+
|
9
|
+
@name TextEffect
|
10
|
+
@constructor
|
11
|
+
###
|
12
|
+
|
13
|
+
###*
|
14
|
+
Updates the position of the text based on the effect velocity. Updates the
|
15
|
+
alpha based on the elapsed time since the effect creation.
|
16
|
+
|
17
|
+
@name update
|
18
|
+
@methodOf TextEffect#
|
19
|
+
@event
|
20
|
+
###
|
21
|
+
|
22
|
+
###*
|
23
|
+
Draws text from `I.textShadow` `I.text`.
|
24
|
+
|
25
|
+
@name draw
|
26
|
+
@methodOf TextEffect#
|
27
|
+
@param {PixieCanvas} canvas
|
28
|
+
@event
|
29
|
+
###
|
30
|
+
TextEffect = (I={}) ->
|
31
|
+
Object.reverseMerge I,
|
32
|
+
color: Color('green')
|
33
|
+
duration: -1
|
34
|
+
font: '20px Helvetica'
|
35
|
+
text: '100'
|
36
|
+
textShadow: Color('black')
|
37
|
+
alpha: 1
|
38
|
+
rotation: 0
|
39
|
+
velocity: Point(0, 0)
|
40
|
+
|
41
|
+
self = GameObject(I)
|
42
|
+
|
43
|
+
self.bind "update", ->
|
44
|
+
I.rotation += I.rotationalVelocity if I.rotationalVelocity?
|
45
|
+
|
46
|
+
I.alpha = (1 - (I.age / I.duration)).clamp(0, 1)
|
47
|
+
|
48
|
+
self.unbind "draw"
|
49
|
+
self.bind "draw", (canvas) ->
|
50
|
+
unless I.color.channels
|
51
|
+
I.color = Color(I.color)
|
52
|
+
|
53
|
+
unless I.textShadow.channels
|
54
|
+
I.textShadow = Color(I.textShadow)
|
55
|
+
|
56
|
+
I.color.a = I.alpha
|
57
|
+
I.textShadow.a = I.alpha
|
58
|
+
|
59
|
+
I.width = canvas.measureText(I.text)
|
60
|
+
|
61
|
+
canvas.font I.font
|
62
|
+
canvas.drawText
|
63
|
+
color: I.textShadow
|
64
|
+
x: 1 - I.width
|
65
|
+
y: 1
|
66
|
+
text: I.text
|
67
|
+
|
68
|
+
canvas.drawText
|
69
|
+
color: I.color
|
70
|
+
x: 0 - I.width
|
71
|
+
y: 0
|
72
|
+
text: I.text
|
73
|
+
|
74
|
+
return self
|
@@ -0,0 +1,22 @@
|
|
1
|
+
###*
|
2
|
+
`TextEffect.Floating` is a simple subclass of `TextEffect`. It provides some defaults
|
3
|
+
to move the text upward and fade it out over 0.5 seconds.
|
4
|
+
|
5
|
+
# adds a FloatingTextEffect to the engine
|
6
|
+
# at (50, 50). This effect will float upward
|
7
|
+
# at 90 pixels/sec and will fadeOut over 0.5 seconds
|
8
|
+
engine.add 'TextEffect.Floating'
|
9
|
+
x: 50
|
10
|
+
y: 50
|
11
|
+
|
12
|
+
@see TextEffect
|
13
|
+
@name Floating
|
14
|
+
@fieldOf TextEffect
|
15
|
+
@constructor
|
16
|
+
###
|
17
|
+
TextEffect.Floating = (I={}) ->
|
18
|
+
Object.reverseMerge I,
|
19
|
+
duration: 0.5
|
20
|
+
velocity: Point(0, -90)
|
21
|
+
|
22
|
+
return TextEffect(I)
|
@@ -0,0 +1,38 @@
|
|
1
|
+
###*
|
2
|
+
The Text Screen class is a GameState that provides convenience methods for drawing text to screen.
|
3
|
+
|
4
|
+
@name TextScreen
|
5
|
+
@constructor
|
6
|
+
###
|
7
|
+
TextScreen = (I={}) ->
|
8
|
+
Object.reverseMerge I,
|
9
|
+
font: 'Helvetica'
|
10
|
+
fontSize: 24
|
11
|
+
fontColor: 'white'
|
12
|
+
yPosition: App.height / 2
|
13
|
+
|
14
|
+
self = GameState(I).extend
|
15
|
+
###*
|
16
|
+
Draw center aligned text at the given y position.
|
17
|
+
|
18
|
+
screen = TextScreen()
|
19
|
+
screen.centerText canvas, 'Centering text is easy'
|
20
|
+
|
21
|
+
@name centerText
|
22
|
+
@methodOf TextScreen#
|
23
|
+
@param {PixieCanvas} canvas The canvas to draw on
|
24
|
+
@param {String} text The text to draw
|
25
|
+
@param {Object} options These include font, size, color, and yPosition
|
26
|
+
###
|
27
|
+
centerText: (canvas, text, options={}) ->
|
28
|
+
font = options.font || I.font
|
29
|
+
size = options.size || I.fontSize
|
30
|
+
color = options.color || I.fontColor
|
31
|
+
yPosition = options.y || I.yPosition
|
32
|
+
|
33
|
+
canvas.font "#{size}px #{font}"
|
34
|
+
|
35
|
+
canvas.centerText
|
36
|
+
y: yPosition
|
37
|
+
text: text
|
38
|
+
color: color
|
@@ -0,0 +1,56 @@
|
|
1
|
+
( ->
|
2
|
+
Map = (data, entityCallback) ->
|
3
|
+
tileHeight = data.tileHeight
|
4
|
+
tileWidth = data.tileWidth
|
5
|
+
|
6
|
+
spriteLookup = {}
|
7
|
+
|
8
|
+
for uuid, entity of App.entities
|
9
|
+
spriteLookup[uuid] = Sprite.fromURL(entity.tileSrc)
|
10
|
+
|
11
|
+
loadEntities = () ->
|
12
|
+
return unless entityCallback
|
13
|
+
|
14
|
+
data.layers.each (layer, layerIndex) ->
|
15
|
+
if instances = layer.instances
|
16
|
+
for instance in instances
|
17
|
+
{x, y, uuid} = instance
|
18
|
+
|
19
|
+
instanceData = Object.extend(
|
20
|
+
layer: layerIndex
|
21
|
+
sprite: spriteLookup[uuid]
|
22
|
+
x: x + tileWidth/2 # Centered Coordinates
|
23
|
+
y: y + tileHeight/2 # Centered Coordinates
|
24
|
+
, App.entities[uuid] # Global entity properties
|
25
|
+
#TODO: Maybe map specific properties?
|
26
|
+
, instance.properties) # Instance properties
|
27
|
+
|
28
|
+
entityCallback(instanceData)
|
29
|
+
|
30
|
+
loadEntities()
|
31
|
+
|
32
|
+
data
|
33
|
+
|
34
|
+
Tilemap = (name, callback, entityCallback) ->
|
35
|
+
fromPixieId(App.Tilemaps[name], callback, entityCallback)
|
36
|
+
|
37
|
+
loadByName = (name, callback, entityCallback) ->
|
38
|
+
url = ResourceLoader.urlFor("tilemaps", name)
|
39
|
+
|
40
|
+
proxy = {}
|
41
|
+
|
42
|
+
$.getJSON url, (data) ->
|
43
|
+
Object.extend(proxy, Map(data, entityCallback))
|
44
|
+
|
45
|
+
callback? proxy
|
46
|
+
|
47
|
+
return proxy
|
48
|
+
|
49
|
+
Tilemap.load = (options) ->
|
50
|
+
if options.pixieId
|
51
|
+
fromPixieId options.pixieId, options.complete, options.entity
|
52
|
+
else if options.name
|
53
|
+
loadByName options.name, options.complete, options.entity
|
54
|
+
|
55
|
+
(exports ? this)["Tilemap"] = Tilemap
|
56
|
+
)()
|
@@ -0,0 +1,78 @@
|
|
1
|
+
###*
|
2
|
+
The TimedEvents module allows arbitrary code to be executed at set intervals. <code>GameObject</code> includes this module by default
|
3
|
+
|
4
|
+
TimedEvents module
|
5
|
+
@name TimedEvents
|
6
|
+
@module
|
7
|
+
@constructor
|
8
|
+
@param {Object} I Instance variables
|
9
|
+
###
|
10
|
+
TimedEvents = (I={}, self) ->
|
11
|
+
Object.reverseMerge I,
|
12
|
+
everyEvents: []
|
13
|
+
delayEvents: []
|
14
|
+
|
15
|
+
self.bind "update", (elapsedTime) ->
|
16
|
+
for event in I.everyEvents
|
17
|
+
{fn, period} = event
|
18
|
+
while event.lastFired < I.age + elapsedTime
|
19
|
+
self.sendOrApply(fn)
|
20
|
+
event.lastFired += period
|
21
|
+
|
22
|
+
[I.delayEvents, firingEvents] = I.delayEvents.partition (event) ->
|
23
|
+
(event.delay -= elapsedTime) >= 0
|
24
|
+
|
25
|
+
firingEvents.each (event) ->
|
26
|
+
self.sendOrApply(event.fn)
|
27
|
+
|
28
|
+
###*
|
29
|
+
Execute <code>fn</code> every <code>n</code> frames.
|
30
|
+
|
31
|
+
player = GameObject()
|
32
|
+
|
33
|
+
player.include TimedEvents
|
34
|
+
|
35
|
+
# doSomething is called every 4 seconds
|
36
|
+
player.every 4, ->
|
37
|
+
doSomething()
|
38
|
+
|
39
|
+
@name every
|
40
|
+
@methodOf TimedEvents#
|
41
|
+
@param {Number} n Number of frames to wait before executing the callback
|
42
|
+
@param {Function} fn Code to execute after <code>n</code> frames has passed
|
43
|
+
###
|
44
|
+
every: (period, fn) ->
|
45
|
+
return unless period > 0
|
46
|
+
|
47
|
+
I.everyEvents.push
|
48
|
+
fn: fn
|
49
|
+
period: period
|
50
|
+
lastFired: I.age
|
51
|
+
|
52
|
+
###*
|
53
|
+
Execute a callback after a number of seconds have passed.
|
54
|
+
|
55
|
+
self.delay 5, ->
|
56
|
+
engine.add
|
57
|
+
class: "Ghost"
|
58
|
+
|
59
|
+
@name delay
|
60
|
+
@methodOf TimedEvents#
|
61
|
+
@param {Number} steps The number of steps to wait before executing the callback
|
62
|
+
@param {Function} callback The callback to be executed.
|
63
|
+
|
64
|
+
@returns {Engine} self
|
65
|
+
###
|
66
|
+
delay: (seconds, fn) ->
|
67
|
+
I.delayEvents.push
|
68
|
+
delay: seconds
|
69
|
+
fn: fn
|
70
|
+
|
71
|
+
return self
|
72
|
+
|
73
|
+
# TODO: Move this into a more core module
|
74
|
+
sendOrApply: (fn, args...) ->
|
75
|
+
if typeof fn is "function"
|
76
|
+
fn.apply(self, args)
|
77
|
+
else
|
78
|
+
self.send(fn, args...)
|
@@ -0,0 +1,38 @@
|
|
1
|
+
###*
|
2
|
+
The Title Screen class sets up a simple game title screen using <code>App.name</code>
|
3
|
+
|
4
|
+
@see TextScreen
|
5
|
+
@name TitleScreen
|
6
|
+
@constructor
|
7
|
+
###
|
8
|
+
|
9
|
+
###*
|
10
|
+
Goes to the next level on any user input.
|
11
|
+
|
12
|
+
@name update
|
13
|
+
@methodOf TitleScreen#
|
14
|
+
@event
|
15
|
+
###
|
16
|
+
|
17
|
+
###*
|
18
|
+
Overlays the title text in the middle of the screen. Uses <code>App.name</code>
|
19
|
+
|
20
|
+
@name overlay
|
21
|
+
@methodOf TitleScreen#
|
22
|
+
@param {PixieCanvas} canvas
|
23
|
+
@event
|
24
|
+
###
|
25
|
+
TitleScreen = (I={}) ->
|
26
|
+
self = TextScreen(I)
|
27
|
+
|
28
|
+
self.bind 'update', ->
|
29
|
+
engine.nextLevel() if justPressed.any
|
30
|
+
|
31
|
+
self.bind "overlay", (canvas) ->
|
32
|
+
self.centerText canvas, App.name
|
33
|
+
|
34
|
+
self.centerText canvas, "Press any key to start",
|
35
|
+
size: 12
|
36
|
+
y: App.height / 2 + 30
|
37
|
+
|
38
|
+
return self
|
data/source/tween.coffee
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
###*
|
2
|
+
The <code>Tween</code> module provides a method to tween object properties.
|
3
|
+
|
4
|
+
@name Tween
|
5
|
+
@module
|
6
|
+
@constructor
|
7
|
+
@param {Object} I Instance variables
|
8
|
+
@param {Core} self Reference to including object
|
9
|
+
###
|
10
|
+
Tween = (I={}, self) ->
|
11
|
+
Object.reverseMerge I,
|
12
|
+
activeTweens: {}
|
13
|
+
|
14
|
+
# Add events and methods here
|
15
|
+
self.bind "update", (elapsedTime) ->
|
16
|
+
t = I.age + elapsedTime
|
17
|
+
for property, data of I.activeTweens
|
18
|
+
if t >= data.endTime
|
19
|
+
I[property] = data.end
|
20
|
+
I.activeTweens[property].complete?()
|
21
|
+
delete I.activeTweens[property]
|
22
|
+
else
|
23
|
+
if data.easing.isString?()
|
24
|
+
easingFunction = Easing[data.easing](data.start, data.end)
|
25
|
+
else
|
26
|
+
easingFunction = data.easing
|
27
|
+
|
28
|
+
I[property] = easingFunction((t - data.startTime) / data.duration)
|
29
|
+
|
30
|
+
###*
|
31
|
+
Modify the object's properties over time.
|
32
|
+
|
33
|
+
player = GameObject()
|
34
|
+
|
35
|
+
player.tween 30,
|
36
|
+
x: 50
|
37
|
+
y: 50
|
38
|
+
easing: "quadratic"
|
39
|
+
|
40
|
+
player = GameObject()
|
41
|
+
|
42
|
+
player.tween 30,
|
43
|
+
x: 150
|
44
|
+
y: 150
|
45
|
+
complete: ->
|
46
|
+
player.dance()
|
47
|
+
|
48
|
+
@name tween
|
49
|
+
@methodOf Tween#
|
50
|
+
@param {Number} duration How long (in frames) until the object's properties reach their final values.
|
51
|
+
@param {Object} properties Which properties to tween. Set the `easing` property to specify the easing function.
|
52
|
+
###
|
53
|
+
tween: (duration, properties) ->
|
54
|
+
properties = Object.extend({}, properties) # Make a local copy
|
55
|
+
|
56
|
+
easing = properties.easing || "linear"
|
57
|
+
complete = properties.complete
|
58
|
+
|
59
|
+
delete properties.easing
|
60
|
+
delete properties.complete
|
61
|
+
|
62
|
+
for property, target of properties
|
63
|
+
I.activeTweens[property] =
|
64
|
+
complete: complete
|
65
|
+
end: target
|
66
|
+
start: I[property]
|
67
|
+
easing: easing
|
68
|
+
duration: duration
|
69
|
+
startTime: I.age
|
70
|
+
endTime: I.age + duration
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module "ActiveBounds"
|
2
|
+
|
3
|
+
window.App ||= {}
|
4
|
+
|
5
|
+
App.width = 640
|
6
|
+
App.height = 480
|
7
|
+
|
8
|
+
test "shouldn't remove object inside activeBounds", ->
|
9
|
+
obj = GameObject
|
10
|
+
x: 50
|
11
|
+
y: 50
|
12
|
+
width: 32
|
13
|
+
height: 32
|
14
|
+
|
15
|
+
obj.include ActiveBounds
|
16
|
+
|
17
|
+
destroySpy = false
|
18
|
+
|
19
|
+
obj.bind 'destroy', ->
|
20
|
+
destroySpy = true
|
21
|
+
|
22
|
+
obj.update(1)
|
23
|
+
|
24
|
+
equals destroySpy, false
|
25
|
+
|
26
|
+
test "should remove objects outside of activeBounds", 2, ->
|
27
|
+
obj = GameObject
|
28
|
+
x: 50
|
29
|
+
y: 50
|
30
|
+
width: 32
|
31
|
+
height: 32
|
32
|
+
|
33
|
+
obj.include ActiveBounds
|
34
|
+
|
35
|
+
destroySpy = false
|
36
|
+
|
37
|
+
obj.bind 'destroy', ->
|
38
|
+
destroySpy = true
|
39
|
+
|
40
|
+
obj.I.x = 10000
|
41
|
+
obj.I.y = 50
|
42
|
+
|
43
|
+
obj.update(1)
|
44
|
+
|
45
|
+
ok destroySpy, 'obj should be destroyed when it goes outside the x bounds'
|
46
|
+
|
47
|
+
obj2 = GameObject
|
48
|
+
x: 100
|
49
|
+
y: 250
|
50
|
+
width: 16
|
51
|
+
height: 26
|
52
|
+
|
53
|
+
obj2.include ActiveBounds
|
54
|
+
|
55
|
+
destroySpy = false
|
56
|
+
|
57
|
+
obj2.bind 'destroy', ->
|
58
|
+
destroySpy = true
|
59
|
+
|
60
|
+
obj2.I.x = 100
|
61
|
+
obj2.I.y = 50000
|
62
|
+
|
63
|
+
obj2.update(1)
|
64
|
+
|
65
|
+
ok destroySpy, 'obj2 should be destroyed when it goes outside the y bounds'
|
66
|
+
|
67
|
+
module()
|