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,116 @@
1
+ module "Cooldown"
2
+
3
+ test "objects count down each of their cooldowns", 2, ->
4
+ obj = GameObject
5
+ bullet: 83
6
+ cooldowns:
7
+ bullet:
8
+ target: 3
9
+ approachBy: 1
10
+
11
+ 5.times ->
12
+ obj.update(1)
13
+
14
+ equals obj.I.bullet, 78, "bullet should decrease by 5"
15
+
16
+ 100.times ->
17
+ obj.update(1)
18
+
19
+ equals obj.I.bullet, 3, "bullet should not cool down part target value"
20
+
21
+ test "should handle negative value", ->
22
+ obj = GameObject
23
+ powerup: -70
24
+ cooldowns:
25
+ powerup:
26
+ target: 0
27
+ approachBy: 1
28
+
29
+ 11.times ->
30
+ obj.update(1)
31
+
32
+ equals obj.I.powerup, -59, "powerup should increase by 11"
33
+
34
+ 70.times ->
35
+ obj.update(1)
36
+
37
+ equals obj.I.powerup, 0, "powerup should not cooldown past target value"
38
+
39
+ test "adding many cooldowns to default instance variables", 3, ->
40
+ obj = GameObject
41
+ cool: 20
42
+ rad: 0
43
+ tubular: 0
44
+ cooldowns:
45
+ cool:
46
+ approachBy: 5
47
+ target: -5
48
+ rad:
49
+ approachBy: 0.5
50
+ target: 1.5
51
+ tubular:
52
+ approachBy: 1
53
+ target: 1000
54
+
55
+ 4.times ->
56
+ obj.update(1)
57
+
58
+ equals obj.I.cool, 0
59
+ equals obj.I.rad, 1.5
60
+ equals obj.I.tubular, 4
61
+
62
+ test "#cooldown", 3, ->
63
+ obj = GameObject()
64
+
65
+ obj.cooldown 'health',
66
+ value: 100
67
+
68
+ 3.times ->
69
+ obj.update(1)
70
+
71
+ equals obj.I.health, 97, "health cooldown should exist and equal 97"
72
+
73
+ obj.cooldown 'turbo',
74
+ target: 5
75
+ approachBy: 3
76
+ value: 50
77
+
78
+ 4.times ->
79
+ obj.update(1)
80
+
81
+ equals obj.I.health, 93, "health should continue of cool down when new cooldowns are added"
82
+ equals obj.I.turbo, 38, "turbo should cool down normally"
83
+
84
+ test "should not blow up if cooldowns aren't specified", ->
85
+ obj = GameObject()
86
+
87
+ obj.update(1)
88
+ obj.trigger "afterUpdate", 1
89
+
90
+ equals obj.I.age, 1, "should successfully update"
91
+
92
+ test "use existing value of instance variable as starting value if no value param given", ->
93
+ obj = GameObject()
94
+
95
+ obj.I.health = 3
96
+
97
+ obj.cooldown 'health',
98
+ target: 10
99
+
100
+ 5.times ->
101
+ obj.update(1)
102
+
103
+ equals obj.I.health, 8
104
+
105
+ test "initialize property to 0 if no current value", ->
106
+ obj = GameObject()
107
+
108
+ obj.cooldown 'health',
109
+ target: 10
110
+
111
+ 5.times ->
112
+ obj.update(1)
113
+
114
+ equals obj.I.health, 5
115
+
116
+ module()
@@ -0,0 +1,71 @@
1
+ module "Debuggable"
2
+
3
+ test 'should exist', ->
4
+ obj = GameObject()
5
+
6
+ obj.include Debuggable
7
+
8
+ ok obj.debug
9
+
10
+ test 'should accept x, y for debug position', ->
11
+ obj = GameObject()
12
+
13
+ obj.include Debuggable
14
+
15
+ obj.debug
16
+ x: 40
17
+ y: 90
18
+
19
+ equals obj.I.debug.position.x, 40
20
+ equals obj.I.debug.position.y, 90
21
+
22
+ test 'position should override x, y for debug position', ->
23
+ obj = GameObject()
24
+
25
+ obj.include Debuggable
26
+
27
+ obj.debug
28
+ x: 2
29
+ y: 40
30
+ position:
31
+ x: 67
32
+ y: 34
33
+
34
+ equals obj.I.debug.position.x, 67
35
+ equals obj.I.debug.position.y, 34
36
+
37
+ test '#debug', ->
38
+ obj = GameObject()
39
+
40
+ obj.include Debuggable
41
+
42
+ equals obj.I.debug.enabled, false
43
+
44
+ obj.debug()
45
+
46
+ equals obj.I.debug.enabled, true
47
+
48
+ test '#toggleDebug', ->
49
+ obj = GameObject()
50
+
51
+ obj.include Debuggable
52
+
53
+ equals obj.I.debug.enabled, false
54
+
55
+ obj.toggleDebug()
56
+
57
+ equals obj.I.debug.enabled, true
58
+
59
+ obj.toggleDebug()
60
+
61
+ equals obj.I.debug.enabled, false
62
+
63
+ obj.toggleDebug(false)
64
+
65
+ equals obj.I.debug.enabled, false
66
+
67
+ obj.toggleDebug(true)
68
+
69
+ equals obj.I.debug.enabled, true
70
+
71
+ module()
@@ -0,0 +1,31 @@
1
+ module "Drawable"
2
+
3
+ test "alpha", ->
4
+ object = GameObject()
5
+
6
+ equal object.I.alpha, 1
7
+
8
+ object2 = GameObject
9
+ alpha: 0.5
10
+
11
+ equal object2.I.alpha, 0.5
12
+
13
+ test "scale", ->
14
+ object = GameObject()
15
+
16
+ transform = object.transform()
17
+
18
+ equal transform.a, 1
19
+ equal transform.d, 1
20
+
21
+ object = GameObject
22
+ scale: 2
23
+ scaleX: -1
24
+ scaleY: 0.5
25
+
26
+ transform = object.transform()
27
+
28
+ equal transform.a, -2
29
+ equal transform.d, 1
30
+
31
+ module()
File without changes
@@ -0,0 +1,15 @@
1
+ module "Emitter"
2
+
3
+ test "Particles should move", ->
4
+ e = Emitter()
5
+
6
+ xVelocity = e.I.particleData.velocity.x
7
+
8
+ e.update(1)
9
+
10
+ ok e.I.particles.length
11
+
12
+ equals e.I.particles.first().I.x, xVelocity
13
+
14
+ module()
15
+
@@ -0,0 +1,228 @@
1
+ module "Engine"
2
+
3
+ MockCanvas = ->
4
+ clear: ->
5
+ context: ->
6
+ beginPath: ->
7
+ clip: ->
8
+ rect: ->
9
+ drawRect: ->
10
+ fill: ->
11
+ withTransform: (t, fn) ->
12
+ fn(@)
13
+ clip: ->
14
+
15
+ test "#play, #pause, and #paused", ->
16
+ engine = Engine()
17
+
18
+ equal engine.paused(), false
19
+ engine.pause()
20
+ equal engine.paused(), true
21
+ engine.play()
22
+ equal engine.paused(), false
23
+
24
+ engine.pause()
25
+ equal engine.paused(), true
26
+ engine.pause()
27
+ equal engine.paused(), false
28
+
29
+ engine.pause(false)
30
+ equal engine.paused(), false
31
+
32
+ engine.pause(true)
33
+ equal engine.paused(), true
34
+
35
+ test "#save and #restore", ->
36
+ engine = Engine()
37
+
38
+ engine.add {}
39
+ engine.add {}
40
+
41
+ equals(engine.objects().length, 2)
42
+
43
+ engine.saveState()
44
+
45
+ engine.add {}
46
+
47
+ equals(engine.objects().length, 3)
48
+
49
+ engine.loadState()
50
+
51
+ equals(engine.objects().length, 2)
52
+
53
+ test "before add event", 1, ->
54
+ engine = Engine()
55
+
56
+ engine.bind "beforeAdd", (data) ->
57
+ equals data.test, "test"
58
+
59
+ engine.add
60
+ test: "test"
61
+
62
+ test "#add", ->
63
+ engine = Engine()
64
+
65
+ engine.add "GameObject",
66
+ test: true
67
+
68
+ ok engine.first("GameObject")
69
+
70
+ test "#add class name only", ->
71
+ engine = Engine()
72
+
73
+ engine.add "GameObject"
74
+
75
+ ok engine.first("GameObject")
76
+
77
+ test "zSort", ->
78
+ engine = Engine
79
+ canvas: MockCanvas()
80
+ zSort: true
81
+
82
+ n = 0
83
+ bindDraw = (o) ->
84
+ o.bind 'draw', ->
85
+ n += 1
86
+ o.I.drawnAt = n
87
+
88
+ o2 = engine.add
89
+ zIndex: 2
90
+ o1 = engine.add
91
+ zIndex: 1
92
+
93
+ bindDraw(o1)
94
+ bindDraw(o2)
95
+
96
+ engine.frameAdvance()
97
+
98
+ equals o1.I.drawnAt, 1, "Object with zIndex #{o1.I.zIndex} should be drawn first"
99
+ equals o2.I.drawnAt, 2, "Object with zIndex #{o2.I.zIndex} should be drawn second"
100
+
101
+ test "invalid module throws error", ->
102
+ raises ->
103
+ engine = Engine
104
+ includedModules: ["HellaInvalidModule"]
105
+
106
+ test "excluded modules", ->
107
+ engine = Engine
108
+ excludedModules: "Developer"
109
+
110
+ engine = Engine
111
+ excludedModules: ["Developer"]
112
+
113
+ test "draw events", 2, ->
114
+ engine = Engine
115
+ canvas: MockCanvas()
116
+ backgroundColor: false
117
+
118
+ engine.bind "beforeDraw", ->
119
+ ok true
120
+
121
+ engine.bind "draw", ->
122
+ ok true
123
+
124
+ engine.frameAdvance()
125
+
126
+ test "Remove event", 1, ->
127
+ engine = Engine
128
+ backgroundColor: false
129
+
130
+ object = engine.add
131
+ active: false
132
+
133
+ object.bind "remove", ->
134
+ ok true, "remove called"
135
+
136
+ engine.frameAdvance()
137
+
138
+ test "#find", ->
139
+ engine = Engine()
140
+
141
+ engine.add
142
+ id: "testy"
143
+
144
+ engine.add
145
+ test: true
146
+
147
+ engine.add
148
+ solid: true
149
+ opaque: false
150
+
151
+ equal engine.find("#no_testy").length, 0
152
+ equal engine.find("#testy").length, 1
153
+ equal engine.find(".test").length, 1
154
+ equal engine.find(".solid=true").length, 1
155
+ equal engine.find(".opaque=false").length, 1
156
+
157
+ test "Selector.parse", ->
158
+ a = Engine.Selector.parse("#foo")
159
+ equal a.length, 1
160
+ equal a.first(), "#foo"
161
+
162
+ a = Engine.Selector.parse("#boo, baz")
163
+ equal a.length, 2
164
+ equal a.first(), "#boo"
165
+ equal a.last(), "baz"
166
+
167
+ a = Engine.Selector.parse("#boo,Light.flicker,baz")
168
+ equal a.length, 3
169
+ equal a.first(), "#boo"
170
+ equal a[1], "Light.flicker"
171
+ equal a.last(), "baz"
172
+
173
+ test "Selector.process", ->
174
+ [type, id, attr, value] = Engine.Selector.process("Foo#test.cool=1")
175
+
176
+ equal type, "Foo"
177
+ equal id, "test"
178
+ equal attr, "cool"
179
+ equal value, 1
180
+
181
+ [type, id, attr, value] = Engine.Selector.process(".baz=false")
182
+
183
+ equal type, undefined
184
+ equal id, undefined
185
+ equal attr, "baz"
186
+ equal value, false
187
+
188
+ test "#camera", ->
189
+ engine = Engine()
190
+
191
+ equal engine.camera(), engine.cameras().first()
192
+
193
+ test "#collides", ->
194
+ engine = Engine()
195
+
196
+ engine.collides(Rectangle(0, 0, 10, 10), null)
197
+
198
+ test "Integration", ->
199
+ engine = Engine
200
+ FPS: 30
201
+
202
+ object = engine.add
203
+ class: "GameObject"
204
+ velocity: Point(30, 0)
205
+
206
+ engine.frameAdvance()
207
+
208
+ equals object.I.x, 1
209
+ equals object.I.age, 1/30
210
+
211
+ test "#setState", 3, ->
212
+ engine = Engine()
213
+
214
+ nextState = GameState()
215
+
216
+ engine.setState nextState
217
+
218
+ # Test state change events
219
+ engine.bind "stateEntered", ->
220
+ ok true
221
+ engine.bind "stateExited", ->
222
+ ok true
223
+
224
+ engine.update()
225
+
226
+ equal engine.I.currentState, nextState
227
+
228
+ module()
@@ -0,0 +1,12 @@
1
+ module "Engine"
2
+
3
+ test "#data", ->
4
+ engine = Engine
5
+ backgroundColor: false
6
+
7
+ engine.data.score = 0
8
+ engine.data.score += 50
9
+
10
+ equals engine.data.score, 50
11
+
12
+ module()
@@ -0,0 +1,14 @@
1
+ module "Engine"
2
+
3
+ test "#delay", 1, ->
4
+ engine = Engine
5
+ backgroundColor: false
6
+
7
+ 3.times (n) ->
8
+ engine.delay n, ->
9
+ ok(true)
10
+
11
+ engine.frameAdvance()
12
+
13
+ module()
14
+
@@ -0,0 +1,100 @@
1
+ module "Engine"
2
+
3
+ test "#closest", ->
4
+ engine = Engine()
5
+
6
+ player = engine.add
7
+ x: 0
8
+ y: 0
9
+
10
+ enemy1 = engine.add
11
+ enemy: true
12
+ x: 10
13
+ y: 0
14
+
15
+ enemy2 = engine.add
16
+ enemy: true
17
+ x: 0
18
+ y: 15
19
+
20
+ player2 = engine.add
21
+ x: 0
22
+ y: 10
23
+
24
+ equals engine.closest(".enemy", player.position()), enemy1
25
+ equals engine.closest(".enemy", player2.position()), enemy2
26
+
27
+ test "#each", ->
28
+ engine = Engine()
29
+
30
+ obj1 = engine.add
31
+ rad: "Awesome"
32
+ x: 0
33
+ y: 5
34
+
35
+ obj2 = engine.add
36
+ rad: "Awesome"
37
+ x: 5
38
+ y: 10
39
+
40
+ obj3 = engine.add
41
+ rad: "Awesome"
42
+ x: 5
43
+ y: 10
44
+
45
+ obj4 = engine.add
46
+ rad: "Awesome"
47
+ x: 40
48
+ y: 320
49
+
50
+ indexSum = 0
51
+
52
+ engine.each '.rad=Awesome', (obj, index) ->
53
+ indexSum += index
54
+
55
+ if index is 0
56
+ equals obj, obj1
57
+ else if index is 1
58
+ equals obj, obj2
59
+ else if index is 2
60
+ equals obj, obj3
61
+ else if index is 3
62
+ equals obj, obj4
63
+
64
+ equals indexSum, 6
65
+
66
+ test "#find", ->
67
+ engine = Engine()
68
+
69
+ engine.add
70
+ findable: true
71
+ x: 0
72
+ y: 50
73
+
74
+ equals engine.find('.findable').length, 1
75
+
76
+ engine.add
77
+ findable: true
78
+ x: 50
79
+ y: 30
80
+
81
+ equals engine.find('.findable').length, 2
82
+
83
+ test "#first", ->
84
+ engine = Engine()
85
+
86
+ obj1 = engine.add
87
+ type: 'testObj'
88
+ x: 4
89
+ y: 20
90
+
91
+ equals engine.first('.type=testObj'), obj1, "should find obj1"
92
+
93
+ obj2 = engine.add
94
+ type: 'testObj'
95
+ x: 9
96
+ y: 10
97
+
98
+ equals engine.first('.type=testObj'), obj1, "should only find the first object"
99
+
100
+ module()
@@ -0,0 +1,35 @@
1
+ module "Expirable"
2
+
3
+ test "objects become inactive after their duration", ->
4
+ obj = GameObject
5
+ duration: 5
6
+
7
+ obj.include Expirable
8
+
9
+ 4.times ->
10
+ obj.update(1)
11
+ obj.trigger "afterUpdate", 1
12
+
13
+ equals obj.I.active, true, "object is active until duration is exceeded"
14
+
15
+ 5.times ->
16
+ obj.update(1)
17
+ obj.trigger "afterUpdate", 1
18
+
19
+ equals obj.I.active, false, "object is inactive after duration"
20
+
21
+ test "should fade out if that option is set", ->
22
+ obj = GameObject
23
+ duration: 10
24
+ alpha: 0.8
25
+ fadeOut: true
26
+
27
+ obj.include Expirable
28
+
29
+ 5.times ->
30
+ obj.update(1)
31
+ obj.trigger "afterUpdate", 1
32
+
33
+ equals obj.I.alpha, 0.48
34
+
35
+ module()
@@ -0,0 +1,51 @@
1
+ module "Flickerable"
2
+
3
+ test 'it should set up defaults', ->
4
+ player = GameObject()
5
+
6
+ player.include Flickerable
7
+
8
+ player.flicker()
9
+
10
+ equals player.I.flickerAlpha, 0.5
11
+ equals player.I.flickerFrequency, 0.1
12
+ equals player.I.flickerDuration, 2
13
+
14
+ test 'it should be able to set one param at a time', ->
15
+ player = GameObject()
16
+
17
+ player.include Flickerable
18
+
19
+ player.flicker
20
+ frequency: 20
21
+
22
+ equals player.I.flickerAlpha, 0.5
23
+ equals player.I.flickerFrequency, 20
24
+ equals player.I.flickerDuration, 2
25
+
26
+ enemy = GameObject()
27
+
28
+ enemy.include Flickerable
29
+
30
+ enemy.flicker
31
+ alpha: 0.4
32
+
33
+ equals enemy.I.flickerAlpha, 0.4
34
+ equals enemy.I.flickerFrequency, 0.1
35
+ equals enemy.I.flickerDuration, 2
36
+
37
+ boss = GameObject()
38
+
39
+ boss.include Flickerable
40
+
41
+ boss.flicker
42
+ duration: 3
43
+
44
+ equals boss.I.flickerAlpha, 0.5
45
+ equals boss.I.flickerFrequency, 0.1
46
+ equals boss.I.flickerDuration, 3
47
+
48
+ #TODO test this with new time step stuff
49
+ #test 'it should change the alpha value when the flicker duration has elapsed', ->
50
+
51
+ module()
@@ -0,0 +1,34 @@
1
+ module "Follow"
2
+
3
+ test "should set the correct velocity", ->
4
+ player = GameObject
5
+ x: 50
6
+ y: 50
7
+ width: 10
8
+ height: 10
9
+
10
+ enemy = GameObject
11
+ x: 0
12
+ y: 50
13
+ widht: 10
14
+ height: 10
15
+ speed: 1
16
+
17
+ enemy.include(Follow)
18
+ enemy.follow(player)
19
+
20
+ ok enemy.I.velocity.equal(Point(1, 0)), 'enemy should head toward player with a velocity Point(1, 0)'
21
+
22
+ rightEnemy = GameObject
23
+ x: 100
24
+ y: 50
25
+ width: 10
26
+ height: 10
27
+ speed: 1
28
+
29
+ rightEnemy.include(Follow)
30
+ rightEnemy.follow(player)
31
+
32
+ ok rightEnemy.I.velocity.equal(Point(-1, 0)), 'rightEnemy should head toward player with a velocity Point(-1, 0)'
33
+
34
+ module()