zyps 0.7.5 → 0.7.6

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/bin/zyps_demo CHANGED
@@ -149,30 +149,35 @@ class Demo < Wx::App
149
149
  test_behaviors_2
150
150
  say "-" * 30
151
151
  when 600:
152
- @environment.objects = []
153
- test_change_color
154
- say "-" * 30
155
- when 800:
156
152
  @environment.objects = []
157
153
  test_accelerate
158
154
  say "-" * 30
159
- when 1000:
155
+ when 700:
160
156
  @environment.objects = []
161
157
  test_turn
162
158
  say "-" * 30
163
- when 1200:
159
+ when 900:
164
160
  @environment.objects = []
165
161
  test_approach
166
162
  say "-" * 30
167
- when 1400:
163
+ when 1100:
168
164
  @environment.objects = []
169
165
  test_flee
170
166
  say "-" * 30
171
- when 1600:
167
+ when 1300:
172
168
  @environment.objects = []
173
169
  test_eat
174
170
  say "-" * 30
175
- when 1800:
171
+ when 1400:
172
+ @environment.objects = []
173
+ test_explode
174
+ say "-" * 30
175
+ when 1500:
176
+ @environment.objects = []
177
+ @environment.environmental_factors = []
178
+ test_shoot
179
+ say "-" * 30
180
+ when 1600:
176
181
  finish
177
182
  end
178
183
  @update_count += 1
@@ -180,11 +185,12 @@ class Demo < Wx::App
180
185
 
181
186
 
182
187
  #Populate an environment with the given number of creatures.
183
- def populate(environment, count = 50)
184
- @log.debug "Add #{count} creatures to #{environment}."
188
+ def generate_creatures(count = 50)
189
+ @log.debug "Generating #{count} creatures."
190
+ objects = []
185
191
  count.times do |i|
186
192
  multiplier = i / count.to_f
187
- environment.objects << Creature.new(
193
+ objects << Creature.new(
188
194
  :name => i,
189
195
  :location => Location.new(multiplier * WIDTH, multiplier * HEIGHT),
190
196
  :color => Color.new(multiplier, 1 - multiplier, multiplier / 2 + 0.5),
@@ -192,6 +198,7 @@ class Demo < Wx::App
192
198
  :size => DEFAULT_OBJECT_SIZE
193
199
  )
194
200
  end
201
+ objects
195
202
  end
196
203
 
197
204
 
@@ -240,7 +247,7 @@ class Demo < Wx::App
240
247
  #Demonstrates environmental factors by adding gravity to the environment.
241
248
  def test_environmental_factors
242
249
 
243
- populate(@environment)
250
+ @environment.objects = generate_creatures
244
251
 
245
252
  say("Without gravity, objects just travel on forever.")
246
253
 
@@ -262,7 +269,7 @@ class Demo < Wx::App
262
269
  #Demonstrates creature behaviors.
263
270
  def test_behaviors
264
271
 
265
- populate(@environment)
272
+ @environment.objects = generate_creatures
266
273
 
267
274
  say("Let's add a Behavior to our creatures.")
268
275
  chase = Behavior.new
@@ -288,7 +295,7 @@ class Demo < Wx::App
288
295
  @environment.objects << GameObject.new(
289
296
  :name => "target",
290
297
  :location => Location.new(WIDTH / 2, HEIGHT / 2),
291
- :color => Color.new(1, 1, 1),
298
+ :color => Color.white,
292
299
  :vector => Vector.new(30, 315),
293
300
  :size => DEFAULT_OBJECT_SIZE * 2, #Size.
294
301
  :tags => ["food"]
@@ -300,61 +307,11 @@ class Demo < Wx::App
300
307
  end
301
308
 
302
309
 
303
- #A Creature that changes the colors of other objects.
304
- class Morpher < Creature
305
- #Changes an object's color.
306
- def initialize(*arguments)
307
- super
308
- morph = Behavior.new
309
- #Shift the target's color to match the creature's.
310
- morph.actions << BlendAction.new(self.color)
311
- #Act only on nearby targets.
312
- morph.conditions << ProximityCondition.new(50)
313
- @behaviors << morph
314
- end
315
- end
316
-
317
- #Demonstrates changing object colors.
318
- def test_change_color
319
-
320
- populate(@environment)
321
-
322
- say("Creatures can influence any attribute of their target, such as its color.")
323
- say("This demo includes a Morpher class, which is a type of Creature.")
324
- say("Morphers are created with a single behavior, which shifts the color of any nearby target to match the Morpher's color.")
325
-
326
- say("Let's place a red Morpher...")
327
- @environment.objects << Morpher.new(
328
- :location => Location.new(0, 100),
329
- :color => Color.new(1, 0, 0),
330
- :vector => Vector.new(100, 0),
331
- :size => DEFAULT_OBJECT_SIZE
332
- )
333
- say("a green one...")
334
- @environment.objects << Morpher.new(
335
- :location => Location.new(0, 150),
336
- :color => Color.new(0, 1, 0),
337
- :vector => Vector.new(200, 0),
338
- :size => DEFAULT_OBJECT_SIZE
339
- )
340
- say("and a blue one...")
341
- @environment.objects << Morpher.new(
342
- :location => Location.new(0, 200),
343
- :color => Color.new(0, 0, 1),
344
- :vector => Vector.new(300, 0),
345
- :size => DEFAULT_OBJECT_SIZE
346
- )
347
-
348
- say("...and see what they do.")
349
-
350
- end
351
-
352
-
353
310
  #Demonstrates altering object speed.
354
311
  def test_accelerate
355
312
 
356
313
  say("Here are some Creatures, just plodding along.")
357
- populate(@environment)
314
+ @environment.objects = generate_creatures
358
315
 
359
316
  say("We're going to have them pick up the pace.")
360
317
  say("We add a Behavior with an AccelerateAction to all the creatures.")
@@ -371,7 +328,7 @@ class Demo < Wx::App
371
328
  #Demonstrates altering object vectors.
372
329
  def test_turn
373
330
 
374
- populate(@environment)
331
+ @environment.objects = generate_creatures
375
332
 
376
333
  say("This time we'll use the TurnAction class.")
377
334
  say("We tell each creature it should turn 90 degrees.")
@@ -387,7 +344,7 @@ class Demo < Wx::App
387
344
  #Demonstrates adding vectors.
388
345
  def test_approach
389
346
 
390
- populate(@environment, 50)
347
+ @environment.objects = generate_creatures
391
348
 
392
349
  say("When your car skids on ice, you might steer in a different direction, but you're going to keep following your original vector for a while.")
393
350
  say("Our ApproachAction adds the vector the creature WANTS to follow to the vector it's ACTUALLY following.")
@@ -418,12 +375,12 @@ class Demo < Wx::App
418
375
  #Demonstrates adding vectors.
419
376
  def test_flee
420
377
 
421
- populate(@environment, 50)
378
+ @environment.objects = generate_creatures
422
379
 
423
380
  say("A FleeAction is just like an ApproachAction, but we head in the OPPOSITE direction.")
424
381
  @environment.objects.each do |creature|
425
382
  flee = Behavior.new
426
- flee.actions << FleeAction.new(360, creature.vector)
383
+ flee.actions << FleeAction.new(300)
427
384
  flee.conditions << TagCondition.new("predator")
428
385
  creature.behaviors << flee
429
386
  end
@@ -442,13 +399,13 @@ class Demo < Wx::App
442
399
  #Demonstrates keeping a reference to an Environment so a Creature can alter it.
443
400
  def test_eat
444
401
 
445
- populate(@environment)
402
+ @environment.objects = generate_creatures
446
403
 
447
404
  say("Most games are all about destruction, but there hasn't been much so far.")
448
405
  say("Let's create a creature that causes some havoc.")
449
406
  predator = Creature.new(
450
407
  :location => Location.new(0, 150),
451
- :color => Color.new(0, 1, 0),
408
+ :color => Color.green,
452
409
  :vector => Vector.new(200, 0),
453
410
  :size => DEFAULT_OBJECT_SIZE * 5
454
411
  )
@@ -473,6 +430,116 @@ class Demo < Wx::App
473
430
  say("And - chomp!")
474
431
 
475
432
  end
433
+
434
+
435
+ #Demonstrates ElapsedTimeCondition.
436
+ def test_explode
437
+
438
+ say("Let's have some fireworks.")
439
+ say("First we'll create 'stars' to load into the rocket.")
440
+ star = Creature.new(:color => Color.red)
441
+ say("A BlendAction will make them fade to black over time.")
442
+ star.behaviors << Behavior.new(:actions => [BlendAction.new(0.5, Color.black)])
443
+ say("An ExplodeAction copies prototype objects into the environment.")
444
+ action = ExplodeAction.new(@environment)
445
+ say("We'll make copies of our star with random vectors.")
446
+ say("We'll load these copies into our ExplodeAction.")
447
+ 25.times do |i|
448
+ copy = star.copy
449
+ copy.vector = Vector.new(rand(50), rand(360))
450
+ action.prototypes << copy
451
+ end
452
+
453
+ say("It's just not smart to build fireworks without a fuse.")
454
+ say("An ElapsedTimeCondition should do nicely.")
455
+ condition = ElapsedTimeCondition.new
456
+ say("This will be a short fuse, though, say 2 seconds.")
457
+ condition.interval = 2
458
+
459
+ say("We set up a Behavior with the Action and Condition...")
460
+ explode = Behavior.new(:actions => [action], :conditions => [condition])
461
+ say("Add the behavior to rockets aimed at the sky...")
462
+ rocket = Creature.new(
463
+ :behaviors => [explode],
464
+ :vector => Vector.new(100, 260),
465
+ :location => Location.new(WIDTH / 2, HEIGHT),
466
+ :size => 50
467
+ )
468
+ rocket2 = rocket.copy
469
+ rocket2.vector = Vector.new(130, 275)
470
+ say("And light those suckers.")
471
+ @environment.objects << rocket << rocket2
472
+ @environment << Gravity.new(30)
473
+
474
+ end
475
+
476
+
477
+ #Demonstrates ShootAction.
478
+ def test_shoot
479
+
480
+ say("I'm a big fan of shoot-em-up games.")
481
+ say("The ability to make them easily is a major goal of Zyps.")
482
+
483
+ say("Every shooter needs someone to play it, so let's make a player.")
484
+ say("We give him a 'player' tag so enemies can target him.")
485
+ player = Creature.new(
486
+ :location => Location.new(WIDTH / 2, HEIGHT / 2),
487
+ :behaviors => [
488
+ Behavior.new(
489
+ :actions => [FleeAction.new(100)],
490
+ :conditions => [ProximityCondition.new(30)]
491
+ )
492
+ ],
493
+ :size => DEFAULT_OBJECT_SIZE,
494
+ :vector => Vector.new(10, 0),
495
+ :tags => ['player']
496
+ )
497
+
498
+ say("Shooters need lots of bullets, of course.")
499
+ say("A bullet doesn't need to be smart, but it should destroy the player when he gets too close.")
500
+ bullet = Creature.new(
501
+ :behaviors => [
502
+ Behavior.new(
503
+ :actions => [DestroyAction.new(@environment)],
504
+ :conditions => [
505
+ ProximityCondition.new(7),
506
+ TagCondition.new('player')
507
+ ]
508
+ )
509
+ ],
510
+ :vector => Vector.new(100, 0)
511
+ )
512
+
513
+ say("We're going to fire groups of 3 bullets at once.")
514
+ bullets = [bullet, bullet.copy, bullet.copy]
515
+ say("There's no point firing all 3 at the same spot...")
516
+ say("We'll vary their angles a bit.")
517
+ bullets.first.vector.pitch -= 10
518
+ bullets.last.vector.pitch += 10
519
+
520
+ say("And lastly, we need an enemy to fire the bullets at the player.")
521
+ say("We'll give him a ShootAction, and assign it our group of bullets.")
522
+ say("The action copies the bullets into the Environment and aims them at its target.")
523
+ say("An ElapsedTimeCondition makes it fire every 0.5 seconds.")
524
+ enemy = Creature.new(
525
+ :vector => Vector.new(30, 45),
526
+ :behaviors => [
527
+ Behavior.new(
528
+ :actions => [ShootAction.new(@environment, [bullets])],
529
+ :conditions => [
530
+ ElapsedTimeCondition.new(0.5),
531
+ TagCondition.new('player'),
532
+ ]
533
+ )
534
+ ],
535
+ :color => Color.green,
536
+ :size => DEFAULT_OBJECT_SIZE
537
+ )
538
+
539
+ say("Game on!")
540
+ @environment.objects << player << enemy
541
+
542
+ end
476
543
 
477
544
 
478
545
  #End the demos.
data/lib/zyps.rb CHANGED
@@ -111,6 +111,19 @@ class Environment
111
111
 
112
112
  end
113
113
 
114
+ #Overloads the << operator to put the new item into the correct list.
115
+ #This allows one to simply call env << <valid_object> instead of
116
+ #having to choose a specific list, such as objects or environmental factors.
117
+ def <<(item)
118
+ if(item.kind_of? Zyps::GameObject)
119
+ self.objects << item
120
+ elsif(item.kind_of? Zyps::EnvironmentalFactor)
121
+ self.environmental_factors << item
122
+ else
123
+ raise "Invalid item: #{item.class}"
124
+ end
125
+ end
126
+
114
127
  end
115
128
 
116
129
 
@@ -164,7 +177,7 @@ class GameObject
164
177
  copy.location = @location.copy
165
178
  copy.tags = @tags.clone
166
179
  copy.identifier = generate_identifier
167
- copy.name = @name ? "Copy of " + @name : nil
180
+ copy.name = @name ? "Copy of " + @name.to_s : nil
168
181
  copy
169
182
  end
170
183
 
@@ -187,6 +200,21 @@ class GameObject
187
200
  @identifier = value
188
201
  end
189
202
 
203
+ #Overloads the << operator to put the new item into the correct
204
+ #list or assign it to the correct attribute.
205
+ #Assignment is done based on item's class or a parent class of item.
206
+ def <<(item)
207
+ if item.kind_of? Zyps::Location:
208
+ self.location = item
209
+ elsif item.kind_of? Zyps::Color:
210
+ self.color = item
211
+ elsif item.kind_of? Zyps::Vector:
212
+ self.vector = item
213
+ else
214
+ raise "Invalid item: #{item.class}"
215
+ end
216
+ end
217
+
190
218
  private
191
219
 
192
220
  #Make a unique GameObject identifier.
@@ -236,6 +264,20 @@ class Creature < GameObject
236
264
  behaviors.each {|behavior| behavior.perform(self, targets)}
237
265
  end
238
266
 
267
+ #See GameObject#<<.
268
+ #Adds ability to stream in behaviors as well.
269
+ def <<(item)
270
+ begin
271
+ super
272
+ rescue
273
+ if(item.kind_of? Zyps::Behavior)
274
+ self.behaviors << item
275
+ else
276
+ raise "invalid item: #{item.class}"
277
+ end
278
+ end
279
+ end
280
+
239
281
  end
240
282
 
241
283
 
@@ -434,6 +476,19 @@ class Color
434
476
  )
435
477
  end
436
478
 
479
+ #Pre-defined color value.
480
+ def self.red; Color.new(1, 0, 0); end
481
+ def self.orange; Color.new(1, 0.63, 0); end
482
+ def self.yellow; Color.new(1, 1, 0); end
483
+ def self.green; Color.new(0, 1, 0); end
484
+ def self.blue; Color.new(0, 0, 1); end
485
+ def self.indigo; Color.new(0.4, 0, 1); end
486
+ def self.violet; Color.new(0.9, 0.5, 0.9); end
487
+ def self.white; Color.new(1, 1, 1); end
488
+ def self.black; Color.new(0, 0, 0); end
489
+ def self.grey; Color.new(0.5, 0.5, 0.5); end
490
+
491
+
437
492
  end
438
493
 
439
494
 
@@ -451,6 +506,9 @@ class Location
451
506
  #Make a deep copy.
452
507
  def copy; self.clone; end
453
508
 
509
+ #True if x and y coordinates are the same.
510
+ def ==(other); self.x == other.x and self.y == other.y; end
511
+
454
512
  end
455
513
 
456
514
 
@@ -478,7 +536,7 @@ class Vector
478
536
  #Store as radians internally.
479
537
  @pitch = Utility.to_radians(value)
480
538
  end
481
-
539
+
482
540
  #The X component.
483
541
  def x; @speed.to_f * Math.cos(@pitch); end
484
542
  def x=(value)
@@ -503,6 +561,9 @@ class Vector
503
561
  Vector.new(new_length, new_angle)
504
562
  end
505
563
 
564
+ #True if x and y coordinates are the same.
565
+ def ==(other); self.speed == other.speed and self.pitch == other.pitch; end
566
+
506
567
  end
507
568
 
508
569
 
@@ -522,13 +583,20 @@ class Clock
522
583
  time = Time.new.to_f
523
584
  elapsed_time = time - @last_check_time
524
585
  @last_check_time = time
525
- elapsed_time
586
+ elapsed_time * @@speed
526
587
  end
527
588
 
528
589
  def reset_elapsed_time
529
590
  @last_check_time = Time.new.to_f
530
591
  end
531
592
 
593
+ #Speed at which all Clocks are operating.
594
+ @@speed = 1.0
595
+ def Clock.speed; @@speed; end
596
+ #Set speed at which all Clocks will operate.
597
+ #1 is real-time, 2 is double speed, 0 is paused.
598
+ def Clock.speed=(value); @@speed = value; end
599
+
532
600
  end
533
601
 
534
602