zyps 0.6.3 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
data/bin/zyps_demo CHANGED
@@ -18,196 +18,225 @@
18
18
  # along with this program. If not, see <http://www.gnu.org/licenses/>.
19
19
 
20
20
 
21
+ gems_loaded = false
21
22
  begin
23
+ require 'logger'
24
+ require 'wx'
22
25
  require 'zyps'
23
26
  require 'zyps/actions'
24
27
  require 'zyps/conditions'
25
28
  require 'zyps/environmental_factors'
26
29
  require 'zyps/views/trails'
30
+ require 'zyps/views/canvas/wx'
27
31
  rescue LoadError
28
- require 'rubygems'
29
- require 'zyps'
30
- require 'zyps/actions'
31
- require 'zyps/conditions'
32
- require 'zyps/views/trails'
32
+ if gems_loaded == false
33
+ require 'rubygems'
34
+ gems_loaded = true
35
+ retry
36
+ else
37
+ raise
38
+ end
33
39
  end
34
40
 
35
41
 
36
42
  include Zyps
37
43
 
38
44
 
39
- class Demo
45
+ LOG_LEVEL = Logger::WARN
46
+ LOG_HANDLE = STDOUT
47
+
48
+
49
+ class Demo < Wx::App
50
+
40
51
 
41
52
  #The view width.
42
53
  WIDTH = 400
43
54
  #The view height.
44
55
  HEIGHT = 300
45
- #Number of frames to draw per demo.
46
- FRAME_COUNT = 80
47
56
  #Number of frames per second.
48
57
  FRAMES_PER_SECOND = 30
49
58
  #Default size of game objects.
50
59
  DEFAULT_OBJECT_SIZE = 78.5 #5 units in radius.
51
60
 
52
- #Set up a window, a canvas, and an object environment, then run the given block.
53
- def demo
54
-
55
- #Create a window, and set GTK up to quit when it is closed.
56
- window = Gtk::Window.new
57
- window.signal_connect("delete_event") {false}
58
- window.signal_connect("destroy") {Gtk.main_quit}
59
-
60
- #Add view to window.
61
- @view = TrailsView.new(WIDTH, HEIGHT)
62
- window.add(@view.canvas)
63
- window.show_all
61
+
62
+ #Initialize an Environment and a View. Then run the demos.
63
+ def on_init
64
+
65
+ @log = Logger.new(LOG_HANDLE)
66
+ @log.level = LOG_LEVEL
67
+ @log.progname = self
68
+
69
+ say "We're using wxRuby as the GUI framework for this demo."
70
+ say "First, we need to create a Frame (window) to hold everything."
71
+ frame = Wx::Frame.new(nil, :size => [WIDTH, HEIGHT], :title => "Zyps Demo")
72
+ frame.evt_close {|event| exit}
73
+ frame.show
74
+
75
+ say "Zyps environments are displayed using Views."
76
+ say "A TrailsView shows game objects with little light trails behind them."
77
+ view = TrailsView.new(
78
+ :width => WIDTH,
79
+ :height => HEIGHT
80
+ )
81
+ say "We also assign the View a Canvas to draw to."
82
+ say "Since our framework is wxWidgets, we'll use a WxCanvas."
83
+ view.canvas = WxCanvas.new(frame)
64
84
 
65
- #Create environment.
85
+ say "The world is called an Environment in Zyps. Let's create a new one."
66
86
  @environment = Environment.new
67
-
68
- #Point view at environment.
69
- @environment.add_observer(@view)
70
-
71
- #Run the given block.
72
- yield
73
-
74
- #Activate the GUI.
75
- Gtk.main
76
-
77
- #A divider for explanation text between demos.
78
- say("-" * 30)
87
+ say "We tell the View to display our Environment by adding it as an Observer."
88
+ @environment.add_observer(view)
89
+ say "We'll also add this application as an observer, to track the number of updates."
90
+ @update_count = 0
91
+ @environment.add_observer(self)
92
+
93
+ say "We want to update the environment #{FRAMES_PER_SECOND} times per second."
94
+ milliseconds_per_frame = (1.0 / FRAMES_PER_SECOND * 1000).to_int
95
+ say "So, we'll set up a timer to fire every #{milliseconds_per_frame} milliseconds."
96
+ timer_id = Wx::ID_HIGHEST + 1
97
+ timer = Wx::Timer.new(self, timer_id)
98
+ say "The timer will trigger the environment update."
99
+ say "We also call the Ruby garbage collector with each update."
100
+ say "This keeps dead objects from accumulating and causing hiccups later."
101
+ evt_timer(timer_id) do
102
+ @environment.interact
103
+ GC.start
104
+ end
105
+ timer.start(milliseconds_per_frame)
79
106
 
80
107
  end
81
-
82
-
83
- #Animate an environment for a given number of frames.
84
- def animate(frame_count)
85
108
 
86
- #A clock to track frames to draw this second.
87
- clock = Clock.new
88
- time_per_frame = 1.0 / FRAMES_PER_SECOND
89
-
90
- begin
91
- (1..frame_count).each do |i|
92
- @environment.interact
93
- #Determine how much time is left in this frame.
94
- time_left_in_frame = (time_per_frame) - clock.elapsed_time
95
- #Sleep for the remaining time.
96
- if time_left_in_frame > 0
97
- sleep time_left_in_frame
98
- #Skip a frame if things are going too slow.
99
- else
100
- sleep time_per_frame
101
- end
102
- end
103
- rescue Exception => exception
104
- puts exception, exception.backtrace
109
+
110
+ #Watch for environment updates.
111
+ #After a certain number, run the next demo.
112
+ def update(environment)
113
+ case @update_count
114
+ when 0:
115
+ say "-" * 30
116
+ test_render
117
+ when 100:
118
+ test_render_2
119
+ say "-" * 30
120
+ when 200:
121
+ @environment.objects = []
122
+ test_environmental_factors
123
+ when 300:
124
+ test_environmental_factors_2
125
+ say "-" * 30
126
+ when 400:
127
+ @environment.objects = []
128
+ @environment.environmental_factors = []
129
+ test_behaviors
130
+ when 500:
131
+ test_behaviors_2
132
+ say "-" * 30
133
+ when 600:
134
+ @environment.objects = []
135
+ test_change_color
136
+ say "-" * 30
137
+ when 800:
138
+ @environment.objects = []
139
+ test_accelerate
140
+ say "-" * 30
141
+ when 1000:
142
+ @environment.objects = []
143
+ test_turn
144
+ say "-" * 30
145
+ when 1200:
146
+ @environment.objects = []
147
+ test_approach
148
+ say "-" * 30
149
+ when 1400:
150
+ @environment.objects = []
151
+ test_flee
152
+ say "-" * 30
153
+ when 1600:
154
+ @environment.objects = []
155
+ test_eat
156
+ say "-" * 30
157
+ when 1800:
158
+ finish
105
159
  end
106
-
160
+ @update_count += 1
107
161
  end
108
162
 
109
-
163
+
110
164
  #Populate an environment with the given number of creatures.
111
165
  def populate(environment, count = 50)
166
+ @log.debug "Add #{count} creatures to #{environment}."
112
167
  count.times do |i|
113
168
  multiplier = i / count.to_f
114
169
  environment.objects << Creature.new(
115
- i, #Name.
116
- Location.new(multiplier * @view.width, multiplier * @view.height),
117
- Color.new(multiplier, 1 - multiplier, multiplier / 2 + 0.5),
118
- Vector.new(100 * multiplier, multiplier * 360),
119
- 0, #Age.
120
- DEFAULT_OBJECT_SIZE #Size.
170
+ :name => i,
171
+ :location => Location.new(multiplier * WIDTH, multiplier * HEIGHT),
172
+ :color => Color.new(multiplier, 1 - multiplier, multiplier / 2 + 0.5),
173
+ :vector => Vector.new(100 * multiplier, multiplier * 360),
174
+ :size => DEFAULT_OBJECT_SIZE
121
175
  )
122
176
  end
123
177
  end
124
-
125
178
 
126
- #Explain what's going on to the user.
127
- def say(phrase)
128
- puts phrase
129
- end
130
-
131
-
179
+
132
180
  #Demonstrates drawing an environment and changing its size.
133
181
  def test_render
134
-
135
- thread = Thread.new do
136
-
137
- say("The things that populate an environment are called GameObjects. Each object has:")
138
- object = GameObject.new
139
- say("...a name")
140
- object.name = "Huey"
141
- say("...a size")
142
- object.size = DEFAULT_OBJECT_SIZE
143
- say("...a Location with x and y coordiates")
144
- object.location = Location.new(@view.width/2, @view.height/2)
145
- say("...a Color with red, green and blue components ranging from 0 to 1")
146
- object.color = Color.new(1, 0, 0)
147
- say("...and a Vector giving its speed and an angle from 0 to 360.")
148
- object.vector = Vector.new(10, 45)
149
-
150
- say("Once your object is ready, add it to the environment.")
151
- @environment.objects << object
152
-
153
- say("Add a view as an observer of an Environment, and it will draw the objects.")
154
- say("Call an environment's interact() method to have the objects in it move around.")
155
- say("Our demo's animate() method does this for us.")
156
- animate(FRAME_COUNT)
157
-
158
- say("Let's add a couple more objects with different colors and vectors.")
159
- @environment.objects << GameObject.new(
160
- "Duey", #Name.
161
- Location.new(@view.width/2, @view.height/2),
162
- Color.new(0, 1, 0),
163
- Vector.new(20, 135),
164
- 0, #Age.
165
- DEFAULT_OBJECT_SIZE * 2 #Size.
166
- )
167
- @environment.objects << GameObject.new(
168
- "Louie", #Name.
169
- Location.new(@view.width/2, @view.height/2),
170
- Color.new(0, 0, 1),
171
- Vector.new(30, 225),
172
- 0, #Age.
173
- DEFAULT_OBJECT_SIZE * 3 #Size.
174
- )
175
- animate(FRAME_COUNT)
176
-
177
- say("The viewing area can be resized at any time via its width and height attributes.")
178
- @view.width += 100
179
- @view.height += 100
180
- animate(FRAME_COUNT)
181
-
182
- say("TrailsView lets you set the length of the trails as well.")
183
- @view.trail_length = 50
184
- animate(FRAME_COUNT)
185
-
186
- end
187
-
188
- end
189
182
 
183
+ say("The things in an Environment are called GameObjects. Each object has:")
184
+ object = GameObject.new
185
+ say("...a name")
186
+ object.name = "Huey"
187
+ say("...a size")
188
+ object.size = DEFAULT_OBJECT_SIZE
189
+ say("...a Location with x and y coordiates")
190
+ object.location = Location.new(WIDTH/2, HEIGHT/2)
191
+ say("...a Color with red, green and blue components ranging from 0 to 1")
192
+ object.color = Color.new(1, 0, 0)
193
+ say("...and a Vector giving its speed and an angle from 0 to 360.")
194
+ object.vector = Vector.new(10, 45)
195
+
196
+ say("Once your object is ready, add it to the environment.")
197
+ @environment.objects << object
190
198
 
199
+ end
200
+
201
+ def test_render_2
202
+
203
+ say("Let's add a couple more objects with different colors and vectors.")
204
+ @environment.objects << GameObject.new(
205
+ :name => "Duey",
206
+ :location => Location.new(WIDTH/2, HEIGHT/2),
207
+ :color => Color.new(0, 1, 0),
208
+ :vector => Vector.new(20, 135),
209
+ :size => DEFAULT_OBJECT_SIZE * 2
210
+ )
211
+ @environment.objects << GameObject.new(
212
+ :name => "Louie",
213
+ :location => Location.new(WIDTH/2, HEIGHT/2),
214
+ :color => Color.new(0, 0, 1),
215
+ :vector => Vector.new(30, 225),
216
+ :size => DEFAULT_OBJECT_SIZE * 3
217
+ )
218
+
219
+ end
220
+
221
+
191
222
  #Demonstrates environmental factors by adding gravity to the environment.
192
223
  def test_environmental_factors
193
224
 
194
225
  populate(@environment)
195
226
 
196
- thread = Thread.new do
227
+ say("Without gravity, objects just travel on forever.")
228
+
229
+ end
230
+
231
+ def test_environmental_factors_2
232
+
233
+ say("Let's add a new EnvironmentalFactor to simulate gravity.")
234
+ gravity = Gravity.new(200)
197
235
 
198
- say("Without gravity, objects just travel on forever.")
199
- animate(FRAME_COUNT)
200
-
201
- say("Let's add a new EnvironmentalFactor to simulate gravity.")
202
- gravity = Gravity.new(200)
203
-
204
- say("We add gravity to the Environment.")
205
- @environment.environmental_factors << gravity
206
-
207
- say("Everything immediately drops.")
208
- animate(FRAME_COUNT)
209
-
210
- end
236
+ say("We add gravity to the Environment.")
237
+ @environment.environmental_factors << gravity
238
+
239
+ say("Everything immediately drops.")
211
240
 
212
241
  end
213
242
 
@@ -217,39 +246,38 @@ class Demo
217
246
 
218
247
  populate(@environment)
219
248
 
220
- thread = Thread.new do
221
-
222
- say("Let's add a Behavior to our creatures.")
223
- chase = Behavior.new
224
-
225
- say("A Behavior has one or more Action objects that define an action to take on the current target.")
226
- say("We'll add an Action that makes the creatures head straight toward their target.")
227
- chase.actions << FaceAction.new
228
-
229
- say("A Behavior also has one or more Condition objects.")
230
- say("Unless every Condition is true, the action(s) won't be carried out.")
231
- say("So that they don't target every creature on the screen, we'll add a condition to the behavior saying the target must have the label 'food'.")
232
- chase.conditions << TagCondition.new("food")
233
-
234
- say("We'll apply this behavior to all creatures currently in the environment.")
235
- @environment.objects.each {|creature| creature.behaviors << chase}
236
- animate(FRAME_COUNT)
237
-
238
- say("Then we'll toss a piece of food (a GameObject with the label 'food') into the environment.")
239
- @environment.objects << GameObject.new(
240
- "target", #Name.
241
- Location.new(@view.width / 2, @view.height / 2),
242
- Color.new(1, 1, 1),
243
- Vector.new(50, 315),
244
- 0, #Age.
245
- DEFAULT_OBJECT_SIZE * 2, #Size.
246
- ["food"] #Tags.
247
- )
248
-
249
- say("Let's see what the creatures do.")
250
- animate(FRAME_COUNT)
251
-
252
- end
249
+ say("Let's add a Behavior to our creatures.")
250
+ chase = Behavior.new
251
+
252
+ say("A Behavior has one or more Action objects that define an action to take on the current target.")
253
+ say("We'll add an Action that makes the creatures head straight toward their target.")
254
+ chase.actions << FaceAction.new
255
+
256
+ say("A Behavior also has one or more Condition objects.")
257
+ say("Unless every Condition is true, the action(s) won't be carried out.")
258
+ say("So that they don't target every creature on the screen, we'll add a condition to the behavior saying the target must have the label 'food'.")
259
+ chase.conditions << TagCondition.new("food")
260
+
261
+ say("We'll apply this behavior to all creatures currently in the environment.")
262
+ @environment.objects.each {|creature| creature.behaviors << chase}
263
+
264
+ end
265
+
266
+ def test_behaviors_2
267
+
268
+ say("Then we'll toss a piece of food into the environment.")
269
+ say("(It's just a GameObject with the tag 'food'.)")
270
+ @environment.objects << GameObject.new(
271
+ :name => "target",
272
+ :location => Location.new(WIDTH / 2, HEIGHT / 2),
273
+ :color => Color.new(1, 1, 1),
274
+ :vector => Vector.new(30, 315),
275
+ :size => DEFAULT_OBJECT_SIZE * 2, #Size.
276
+ :tags => ["food"]
277
+ )
278
+
279
+ say("Now there's a target in the environment for which the condition is true.")
280
+ say("All the Creatures will turn and chase it.")
253
281
 
254
282
  end
255
283
 
@@ -278,14 +306,28 @@ class Demo
278
306
  say("Morphers are created with a single behavior, which shifts the color of any nearby target to match the Morpher's color.")
279
307
 
280
308
  say("Let's place a red Morpher...")
281
- @environment.objects << Morpher.new(nil, Location.new(0, 100), Color.new(1, 0, 0), Vector.new(100, 0), 0, DEFAULT_OBJECT_SIZE)
309
+ @environment.objects << Morpher.new(
310
+ :location => Location.new(0, 100),
311
+ :color => Color.new(1, 0, 0),
312
+ :vector => Vector.new(100, 0),
313
+ :size => DEFAULT_OBJECT_SIZE
314
+ )
282
315
  say("a green one...")
283
- @environment.objects << Morpher.new(nil, Location.new(0, 150), Color.new(0, 1, 0), Vector.new(200, 0), 0, DEFAULT_OBJECT_SIZE)
316
+ @environment.objects << Morpher.new(
317
+ :location => Location.new(0, 150),
318
+ :color => Color.new(0, 1, 0),
319
+ :vector => Vector.new(200, 0),
320
+ :size => DEFAULT_OBJECT_SIZE
321
+ )
284
322
  say("and a blue one...")
285
- @environment.objects << Morpher.new(nil, Location.new(0, 200), Color.new(0, 0, 1), Vector.new(300, 0), 0, DEFAULT_OBJECT_SIZE)
323
+ @environment.objects << Morpher.new(
324
+ :location => Location.new(0, 200),
325
+ :color => Color.new(0, 0, 1),
326
+ :vector => Vector.new(300, 0),
327
+ :size => DEFAULT_OBJECT_SIZE
328
+ )
286
329
 
287
- say("And see what they do.")
288
- thread = Thread.new {animate(FRAME_COUNT)}
330
+ say("...and see what they do.")
289
331
 
290
332
  end
291
333
 
@@ -293,50 +335,32 @@ class Demo
293
335
  #Demonstrates altering object speed.
294
336
  def test_accelerate
295
337
 
338
+ say("Here are some Creatures, just plodding along.")
296
339
  populate(@environment)
297
340
 
298
- thread = Thread.new do
299
-
300
-
301
- say("Here are some Creatures, just plodding along.")
302
- animate(FRAME_COUNT / 4)
303
- say("We're going to have them pick up the pace.")
304
-
305
- say("We add a Behavior with an AccelerateAction to all the creatures, and specify they should increase their speed by 100 units/second...")
306
- @environment.objects.each do |creature|
307
- accelerate = Behavior.new
308
- accelerate.actions << AccelerateAction.new(100)
309
- creature.behaviors << accelerate
310
- end
311
-
312
- say("And watch them rocket away.")
313
- animate(FRAME_COUNT)
314
-
341
+ say("We're going to have them pick up the pace.")
342
+ say("We add a Behavior with an AccelerateAction to all the creatures.")
343
+ say("This AccelerateAction specifies they should increase their speed by 50 units/second.")
344
+ @environment.objects.each do |creature|
345
+ accelerate = Behavior.new
346
+ accelerate.actions << AccelerateAction.new(50)
347
+ creature.behaviors << accelerate
315
348
  end
316
-
349
+
317
350
  end
318
351
 
319
352
 
320
353
  #Demonstrates altering object vectors.
321
354
  def test_turn
322
355
 
323
- populate(@environment, 20)
324
-
325
- thread = Thread.new do
356
+ populate(@environment)
326
357
 
327
- say("This time we'll use the TurnAction class.")
328
- animate(FRAME_COUNT / 2)
329
-
330
- say("We tell each creature it should turn by 90 degrees/second...")
331
- @environment.objects.each do |creature|
332
- turn = Behavior.new
333
- turn.actions << TurnAction.new(90)
334
- creature.behaviors << turn
335
- end
336
-
337
- say("And watch things spiral out of control.")
338
- animate(FRAME_COUNT)
339
-
358
+ say("This time we'll use the TurnAction class.")
359
+ say("We tell each creature it should turn 90 degrees.")
360
+ @environment.objects.each do |creature|
361
+ turn = Behavior.new
362
+ turn.actions << TurnAction.new(100, 90)
363
+ creature.behaviors << turn
340
364
  end
341
365
 
342
366
  end
@@ -360,17 +384,14 @@ class Demo
360
384
 
361
385
  say("Add a target...")
362
386
  @environment.objects << Creature.new(
363
- "target",
364
- Location.new(@view.width / 2, @view.height / 3),
365
- Color.new(1, 1, 1),
366
- Vector.new(3, 0),
367
- 0, #Age.
368
- DEFAULT_OBJECT_SIZE, #Size.
369
- ["food"] #Tags.
387
+ :name => "target",
388
+ :location => Location.new(WIDTH / 2, HEIGHT / 3),
389
+ :vector => Vector.new(10, 0),
390
+ :size => DEFAULT_OBJECT_SIZE,
391
+ :tags => ["food"]
370
392
  )
371
393
 
372
394
  say("And watch them all TRY to catch it.")
373
- thread = Thread.new {animate(FRAME_COUNT)}
374
395
 
375
396
  end
376
397
 
@@ -390,20 +411,15 @@ class Demo
390
411
  end
391
412
 
392
413
  @environment.objects << Creature.new(
393
- "target",
394
- Location.new(@view.width / 2, @view.height / 2),
395
- Color.new(1, 1, 1),
396
- Vector.new(3, 0),
397
- 0, #Age.
398
- DEFAULT_OBJECT_SIZE, #Size.
399
- ["predator"] #Tags.
414
+ :name => "hunter",
415
+ :location => Location.new(WIDTH / 2, HEIGHT / 2),
416
+ :vector => Vector.new(10, 0),
417
+ :size => DEFAULT_OBJECT_SIZE,
418
+ :tags => ["predator"]
400
419
  )
401
420
 
402
- thread = Thread.new {animate(FRAME_COUNT)}
403
-
404
421
  end
405
422
 
406
-
407
423
 
408
424
  #Demonstrates keeping a reference to an Environment so a Creature can alter it.
409
425
  def test_eat
@@ -412,7 +428,12 @@ class Demo
412
428
 
413
429
  say("Most games are all about destruction, but there hasn't been much so far.")
414
430
  say("Let's create a creature that causes some havoc.")
415
- predator = Creature.new(nil, Location.new(0, 150), Color.new(0, 1, 0), Vector.new(200, 0), 0, DEFAULT_OBJECT_SIZE * 2)
431
+ predator = Creature.new(
432
+ :location => Location.new(0, 150),
433
+ :color => Color.new(0, 1, 0),
434
+ :vector => Vector.new(200, 0),
435
+ :size => DEFAULT_OBJECT_SIZE * 5
436
+ )
416
437
 
417
438
  say("The EatAction eats targets by removing them from their environment.")
418
439
  say("Creatures and their Actions normally know nothing about the Environment they belong to, so EatAction takes an Environment in its constructor.")
@@ -432,38 +453,35 @@ class Demo
432
453
  @environment.objects << predator
433
454
 
434
455
  say("And - chomp!")
435
- thread = Thread.new {animate(FRAME_COUNT)}
436
456
 
437
457
  end
438
458
 
439
459
 
440
- #Run all the demos.
441
- def main
442
- say "This is a demonstration of the Zyps library."
443
- say "After each demo, close the window to proceed."
444
- say("-" * 30)
445
- demo {test_render}
446
- demo {test_environmental_factors}
447
- demo {test_behaviors}
448
- demo {test_change_color}
449
- demo {test_accelerate}
450
- demo {test_turn}
451
- demo {test_approach}
452
- demo {test_flee}
453
- demo {test_eat}
460
+ #End the demos.
461
+ def finish
454
462
  say "To learn more about how the library works, you can read the source code in the 'bin/zyps_demo' file in the Zyps distribution."
455
463
  say "And if you want to code your own Actions, Conditions, EnvironmentalFactors, or Views, see the distribution's 'lib' folder for examples."
456
464
  say "Thanks for watching!"
457
465
  end
466
+
467
+
468
+ private
469
+
470
+ #Explain what's going on to the user.
471
+ def say(phrase)
472
+ puts phrase
473
+ end
458
474
 
459
-
475
+
460
476
  end
461
477
 
462
478
 
463
479
  begin
464
480
  #Run the demos.
465
- Demo.new.main
466
- rescue => exception
481
+ Demo.new.main_loop
482
+ rescue SystemExit
483
+ #No action.
484
+ rescue Exception => exception
467
485
  #Print error to STDERR and exit with an abnormal status.
468
486
  abort "Error: " + exception.message
469
487
  end