zyps 0.3.1 → 0.4.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/bin/zyps +22 -346
- data/bin/zyps_demo +116 -188
- data/doc/classes/AccelerateAction.html +182 -0
- data/doc/classes/{Vector.src/M000006.html → AccelerateAction.src/M000009.html} +5 -5
- data/doc/classes/AccelerateAction.src/M000010.html +18 -0
- data/doc/classes/Action.html +118 -0
- data/doc/classes/AgeCondition.html +181 -0
- data/doc/classes/AgeCondition.src/M000039.html +18 -0
- data/doc/classes/AgeCondition.src/M000040.html +18 -0
- data/doc/classes/ApproachAction.html +189 -0
- data/doc/classes/ApproachAction.src/M000048.html +19 -0
- data/doc/classes/ApproachAction.src/M000049.html +38 -0
- data/doc/classes/Behavior.html +23 -26
- data/doc/classes/Behavior.src/{M000003.html → M000001.html} +1 -1
- data/doc/classes/Behavior.src/{M000004.html → M000002.html} +2 -2
- data/doc/classes/BlendAction.html +181 -0
- data/doc/classes/BlendAction.src/M000043.html +18 -0
- data/doc/classes/BlendAction.src/M000044.html +18 -0
- data/doc/classes/Clock.html +10 -10
- data/doc/classes/Clock.src/{M000026.html → M000041.html} +0 -0
- data/doc/classes/Clock.src/{M000027.html → M000042.html} +0 -0
- data/doc/classes/CollisionCondition.html +148 -0
- data/doc/classes/CollisionCondition.src/M000053.html +18 -0
- data/doc/classes/Color.html +36 -36
- data/doc/classes/Color.src/{M000015.html → M000022.html} +0 -0
- data/doc/classes/Color.src/{M000016.html → M000023.html} +0 -0
- data/doc/classes/Color.src/{M000017.html → M000024.html} +0 -0
- data/doc/classes/Color.src/{M000018.html → M000025.html} +0 -0
- data/doc/classes/Color.src/{M000019.html → M000026.html} +0 -0
- data/doc/classes/Color.src/{M000020.html → M000027.html} +3 -3
- data/doc/classes/Condition.html +118 -0
- data/doc/classes/Creature.html +28 -13
- data/doc/classes/Creature.src/{M000005.html → M000011.html} +4 -4
- data/doc/classes/{Responsive.src/M000030.html → Creature.src/M000012.html} +2 -2
- data/doc/classes/DestroyAction.html +181 -0
- data/doc/classes/DestroyAction.src/M000030.html +18 -0
- data/doc/classes/DestroyAction.src/M000031.html +18 -0
- data/doc/classes/EatAction.html +149 -0
- data/doc/classes/EatAction.src/M000045.html +21 -0
- data/doc/classes/Enclosure.html +206 -0
- data/doc/classes/Enclosure.src/M000005.html +18 -0
- data/doc/classes/Enclosure.src/M000006.html +31 -0
- data/doc/classes/Environment.html +11 -11
- data/doc/classes/Environment.src/{M000028.html → M000046.html} +1 -1
- data/doc/classes/Environment.src/{M000029.html → M000047.html} +0 -0
- data/doc/classes/EnvironmentalFactor.html +2 -51
- data/doc/classes/{Responsive.html → FaceAction.html} +21 -16
- data/doc/classes/FaceAction.src/M000052.html +18 -0
- data/doc/classes/FleeAction.html +189 -0
- data/doc/classes/FleeAction.src/M000054.html +19 -0
- data/doc/classes/FleeAction.src/M000055.html +38 -0
- data/doc/classes/GameObject.html +47 -21
- data/doc/classes/GameObject.src/{M000022.html → M000032.html} +3 -4
- data/doc/classes/GameObject.src/M000033.html +16 -0
- data/doc/classes/GameObject.src/{M000023.html → M000034.html} +1 -1
- data/doc/classes/GameObject.src/{M000024.html → M000035.html} +1 -1
- data/doc/classes/GameObject.src/{M000025.html → M000036.html} +1 -1
- data/doc/classes/Location.html +5 -5
- data/doc/classes/Location.src/{M000014.html → M000021.html} +1 -1
- data/doc/classes/ProximityCondition.html +182 -0
- data/doc/classes/ProximityCondition.src/M000037.html +18 -0
- data/doc/classes/ProximityCondition.src/M000038.html +18 -0
- data/doc/classes/TagAction.html +181 -0
- data/doc/classes/{EnvironmentalFactor.src/M000021.html → TagAction.src/M000028.html} +4 -4
- data/doc/classes/TagAction.src/M000029.html +18 -0
- data/doc/classes/TagCondition.html +181 -0
- data/doc/classes/TagCondition.src/M000007.html +18 -0
- data/doc/classes/TagCondition.src/M000008.html +18 -0
- data/doc/classes/TrailsView.html +13 -21
- data/doc/classes/TrailsView.src/{M000001.html → M000003.html} +3 -3
- data/doc/classes/TrailsView.src/{M000002.html → M000004.html} +4 -2
- data/doc/classes/TurnAction.html +182 -0
- data/doc/classes/TurnAction.src/M000050.html +19 -0
- data/doc/classes/TurnAction.src/M000051.html +18 -0
- data/doc/classes/Utility.html +48 -48
- data/doc/classes/Utility.src/{M000031.html → M000056.html} +0 -0
- data/doc/classes/Utility.src/{M000032.html → M000057.html} +0 -0
- data/doc/classes/Utility.src/{M000033.html → M000058.html} +0 -0
- data/doc/classes/Utility.src/{M000034.html → M000059.html} +0 -0
- data/doc/classes/Utility.src/{M000035.html → M000060.html} +0 -0
- data/doc/classes/Utility.src/{M000036.html → M000061.html} +0 -0
- data/doc/classes/Utility.src/M000062.html +21 -0
- data/doc/classes/Vector.html +41 -41
- data/doc/classes/Vector.src/M000013.html +5 -11
- data/doc/classes/Vector.src/{M000007.html → M000014.html} +0 -0
- data/doc/classes/Vector.src/{M000008.html → M000015.html} +0 -0
- data/doc/classes/Vector.src/{M000009.html → M000016.html} +0 -0
- data/doc/classes/Vector.src/{M000010.html → M000017.html} +0 -0
- data/doc/classes/Vector.src/{M000011.html → M000018.html} +0 -0
- data/doc/classes/Vector.src/{M000012.html → M000019.html} +0 -0
- data/doc/classes/Vector.src/M000020.html +25 -0
- data/doc/created.rid +1 -1
- data/doc/files/COPYING_LESSER_txt.html +1 -1
- data/doc/files/COPYING_txt.html +1 -1
- data/doc/files/README_txt.html +1 -1
- data/doc/files/lib/zyps/actions_rb.html +134 -0
- data/doc/files/lib/zyps/conditions_rb.html +134 -0
- data/doc/files/lib/zyps/environmental_factors_rb.html +134 -0
- data/doc/files/lib/zyps/views/trails_rb.html +1 -1
- data/doc/files/lib/zyps_rb.html +1 -1
- data/doc/fr_class_index.html +16 -1
- data/doc/fr_file_index.html +3 -0
- data/doc/fr_method_index.html +62 -37
- data/doc/index.html +2 -2
- data/lib/zyps.rb +46 -47
- data/lib/zyps/actions.rb +186 -0
- data/lib/zyps/conditions.rb +69 -0
- data/lib/zyps/environmental_factors.rb +55 -0
- data/lib/zyps/views/trails.rb +6 -6
- data/test/test_zyps.rb +159 -69
- data/test/zyps/test_actions.rb +183 -0
- data/test/zyps/test_conditions.rb +83 -0
- data/test/zyps/test_environmental_factors.rb +88 -0
- metadata +137 -75
- data/doc/classes/Utility.src/M000037.html +0 -22
data/bin/zyps
CHANGED
|
@@ -20,279 +20,20 @@
|
|
|
20
20
|
|
|
21
21
|
begin
|
|
22
22
|
require 'zyps'
|
|
23
|
+
require 'zyps/actions'
|
|
24
|
+
require 'zyps/conditions'
|
|
25
|
+
require 'zyps/environmental_factors'
|
|
23
26
|
require 'zyps/views/trails'
|
|
24
27
|
rescue LoadError
|
|
25
28
|
require 'rubygems'
|
|
26
29
|
require 'zyps'
|
|
30
|
+
require 'zyps/actions'
|
|
31
|
+
require 'zyps/conditions'
|
|
32
|
+
require 'zyps/environmental_factors'
|
|
27
33
|
require 'zyps/views/trails'
|
|
28
34
|
end
|
|
29
35
|
|
|
30
36
|
|
|
31
|
-
#Generates new creatures and places them in an environment.
|
|
32
|
-
class Generator
|
|
33
|
-
|
|
34
|
-
#Environment creatures will be spawned into.
|
|
35
|
-
attr_accessor :environment
|
|
36
|
-
#Boundary that all new objects must be inside.
|
|
37
|
-
attr_accessor :min_x, :min_y, :max_x, :max_y
|
|
38
|
-
#Array of tags to choose from when generating new one.
|
|
39
|
-
attr_accessor :tag_pool
|
|
40
|
-
#Array of colors to choose from when generating new one.
|
|
41
|
-
attr_accessor :color_pool
|
|
42
|
-
#The maximum speed a new creature should be going.
|
|
43
|
-
attr_accessor :max_speed
|
|
44
|
-
#The maximum number of behaviors a creature can have.
|
|
45
|
-
attr_accessor :max_behaviors
|
|
46
|
-
#The maximum number of conditions a Behavior can have.
|
|
47
|
-
attr_accessor :max_conditions
|
|
48
|
-
#The maximum number of actions a Behavior can have.
|
|
49
|
-
attr_accessor :max_actions
|
|
50
|
-
|
|
51
|
-
def initialize(environment, min_x, min_y, max_x, max_y)
|
|
52
|
-
@environment, @min_x, @min_y, @max_x, @max_y = environment, min_x, min_y, max_x, max_y
|
|
53
|
-
@tag_pool = %q{foo bar baz}
|
|
54
|
-
@color_pool = []
|
|
55
|
-
@max_behaviors = 2
|
|
56
|
-
@max_conditions = 2
|
|
57
|
-
@max_actions = 2
|
|
58
|
-
@max_speed = 100
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
#Create a creature.
|
|
62
|
-
def create_creature()
|
|
63
|
-
|
|
64
|
-
creature = Creature.new()
|
|
65
|
-
#Create a Color.
|
|
66
|
-
creature.color = create_color
|
|
67
|
-
#Create a Location.
|
|
68
|
-
creature.location = create_location
|
|
69
|
-
#Create a Vector.
|
|
70
|
-
creature.vector = create_vector()
|
|
71
|
-
#Create a random tag.
|
|
72
|
-
creature.tags << create_tag()
|
|
73
|
-
#Create a random number of behaviors.
|
|
74
|
-
generate_number(0, @max_behaviors).to_i.times {creature.behaviors << create_behavior()}
|
|
75
|
-
|
|
76
|
-
creature
|
|
77
|
-
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
#Create a random tag.
|
|
81
|
-
#Chooses from tag_pool.
|
|
82
|
-
def create_tag()
|
|
83
|
-
@tag_pool[generate_number(0, @tag_pool.length).to_i]
|
|
84
|
-
end
|
|
85
|
-
#Create a random Color.
|
|
86
|
-
#Chooses from color_pool, or creates a random one from scratch if color_pool is empty.
|
|
87
|
-
def create_color()
|
|
88
|
-
if (color_pool.length != 0) then
|
|
89
|
-
return @color_pool[generate_number(0, @color_pool.length).to_i]
|
|
90
|
-
else
|
|
91
|
-
return Color.new(generate_random_number(0, 1), generate_random_number(0, 1), generate_random_number(0, 1))
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
#Create a random Location.
|
|
95
|
-
def create_location()
|
|
96
|
-
Location.new(
|
|
97
|
-
generate_random_number(0, @max_x - @min_x) + @min_x,
|
|
98
|
-
generate_random_number(0, @max_y - @min_y) + @min_y
|
|
99
|
-
)
|
|
100
|
-
end
|
|
101
|
-
#Create a random Vector.
|
|
102
|
-
def create_vector()
|
|
103
|
-
Vector.new(generate_number(0, @max_speed), generate_number(0, 360))
|
|
104
|
-
end
|
|
105
|
-
#Create a random Behavior.
|
|
106
|
-
def create_behavior()
|
|
107
|
-
behavior = Behavior.new
|
|
108
|
-
action_count = generate_number(0, @max_actions).to_i
|
|
109
|
-
action_count.times do
|
|
110
|
-
behavior.actions << create_action()
|
|
111
|
-
end
|
|
112
|
-
#Only add conditions if there's an action.
|
|
113
|
-
if action_count > 0 then
|
|
114
|
-
#There should always be a proximity condition.
|
|
115
|
-
behavior.conditions << create_proximity_condition()
|
|
116
|
-
#Add some additional conditions.
|
|
117
|
-
generate_random_number(0, @max_conditions).to_i.times do
|
|
118
|
-
behavior.conditions << create_condition()
|
|
119
|
-
end
|
|
120
|
-
end
|
|
121
|
-
behavior
|
|
122
|
-
end
|
|
123
|
-
#Create a random condition.
|
|
124
|
-
def create_condition()
|
|
125
|
-
case generate_number(0, 2).to_i
|
|
126
|
-
when 0
|
|
127
|
-
return create_tag_condition()
|
|
128
|
-
when 1
|
|
129
|
-
return create_age_condition()
|
|
130
|
-
else
|
|
131
|
-
raise "Invalid condition"
|
|
132
|
-
end
|
|
133
|
-
end
|
|
134
|
-
#Create a condition that looks for a random tag.
|
|
135
|
-
def create_tag_condition()
|
|
136
|
-
tag = create_tag()
|
|
137
|
-
lambda {|creature, target| target.tags.include?(tag)}
|
|
138
|
-
end
|
|
139
|
-
#Create a condition that looks for a random age.
|
|
140
|
-
def create_age_condition()
|
|
141
|
-
age = generate_number(0, 60)
|
|
142
|
-
lambda {|creature, target| target.age > age}
|
|
143
|
-
end
|
|
144
|
-
#Create a condition that looks for a random proximity.
|
|
145
|
-
def create_proximity_condition()
|
|
146
|
-
proximity = generate_number(0, 100)
|
|
147
|
-
lambda do |creature, target|
|
|
148
|
-
Utility.find_distance(creature.location, target.location) < proximity
|
|
149
|
-
end
|
|
150
|
-
end
|
|
151
|
-
#Create a random action.
|
|
152
|
-
def create_action()
|
|
153
|
-
case generate_random_number(0, 9).to_i
|
|
154
|
-
when 0
|
|
155
|
-
return create_accelerate_action()
|
|
156
|
-
when 1
|
|
157
|
-
return create_approach_action()
|
|
158
|
-
when 2
|
|
159
|
-
return create_flee_action()
|
|
160
|
-
when 3
|
|
161
|
-
return create_blend_action()
|
|
162
|
-
when 4
|
|
163
|
-
return create_mate_action()
|
|
164
|
-
when 5
|
|
165
|
-
return create_spawn_action()
|
|
166
|
-
when 6
|
|
167
|
-
return create_turn_action()
|
|
168
|
-
when 7
|
|
169
|
-
return create_eat_action()
|
|
170
|
-
when 8
|
|
171
|
-
return create_tag_action()
|
|
172
|
-
else
|
|
173
|
-
raise "Invalid action"
|
|
174
|
-
end
|
|
175
|
-
end
|
|
176
|
-
#Create an action that accelerates at a random rate.
|
|
177
|
-
def create_accelerate_action()
|
|
178
|
-
clock = Clock.new()
|
|
179
|
-
rate = generate_number(0, 10)
|
|
180
|
-
lambda {|creature, target| creature.vector.speed += rate * clock.elapsed_time}
|
|
181
|
-
end
|
|
182
|
-
#Create an action that turns in a circle.
|
|
183
|
-
def create_turn_action()
|
|
184
|
-
clock = Clock.new()
|
|
185
|
-
rate = generate_number(0, 360)
|
|
186
|
-
lambda {|creature, target| creature.vector.pitch += rate * clock.elapsed_time}
|
|
187
|
-
end
|
|
188
|
-
#Create an action that approaches the target.
|
|
189
|
-
def create_approach_action()
|
|
190
|
-
heading = Vector.new
|
|
191
|
-
rate = generate_number(0, 20)
|
|
192
|
-
lambda do |creature, target|
|
|
193
|
-
#Find the difference between the current heading and the angle to the target.
|
|
194
|
-
turn_angle = Utility.find_angle(creature.location, target.location) - heading.pitch
|
|
195
|
-
#If the angle is the long way around from the current heading, change it to the smaller angle.
|
|
196
|
-
if turn_angle > 180 then
|
|
197
|
-
turn_angle -= 360.0
|
|
198
|
-
elsif turn_angle < -180 then
|
|
199
|
-
turn_angle += 360.0
|
|
200
|
-
end
|
|
201
|
-
#If turn angle is greater than allowed turn speed, reduce it.
|
|
202
|
-
turn_angle = Utility.constrain_value(turn_angle, rate)
|
|
203
|
-
#Turn the appropriate amount.
|
|
204
|
-
heading.pitch += turn_angle
|
|
205
|
-
#Apply the heading to the creature's movement vector.
|
|
206
|
-
creature.vector += heading
|
|
207
|
-
end
|
|
208
|
-
end
|
|
209
|
-
#Create an action that flees from the target.
|
|
210
|
-
def create_flee_action()
|
|
211
|
-
heading = Vector.new
|
|
212
|
-
rate = generate_number(0, 20)
|
|
213
|
-
lambda do |creature, target|
|
|
214
|
-
#Find the difference between the current heading and the angle AWAY from the target.
|
|
215
|
-
turn_angle = Utility.find_angle(creature.location, target.location) - heading.pitch + 180
|
|
216
|
-
#If the angle is the long way around from the current heading, change it to the smaller angle.
|
|
217
|
-
if turn_angle > 180 then
|
|
218
|
-
turn_angle -= 360.0
|
|
219
|
-
elsif turn_angle < -180 then
|
|
220
|
-
turn_angle += 360.0
|
|
221
|
-
end
|
|
222
|
-
#If turn angle is greater than allowed turn speed, reduce it.
|
|
223
|
-
turn_angle = Utility.constrain_value(turn_angle, rate)
|
|
224
|
-
#Turn the appropriate amount.
|
|
225
|
-
heading.pitch += turn_angle
|
|
226
|
-
#Apply the heading to the creature's movement vector.
|
|
227
|
-
creature.vector += heading
|
|
228
|
-
end
|
|
229
|
-
end
|
|
230
|
-
#Create an action that shifts the subject's color to match the target.
|
|
231
|
-
def create_blend_action()
|
|
232
|
-
lambda {|creature, target| creature.color += target.color}
|
|
233
|
-
end
|
|
234
|
-
#Create an action that mates with the target.
|
|
235
|
-
def create_mate_action()
|
|
236
|
-
#TODO
|
|
237
|
-
lambda {|creature, target| }
|
|
238
|
-
end
|
|
239
|
-
#Create an action that spawns a new creature.
|
|
240
|
-
def create_spawn_action()
|
|
241
|
-
#TODO
|
|
242
|
-
lambda {|creature, target| }
|
|
243
|
-
end
|
|
244
|
-
#Create an action that eats the target.
|
|
245
|
-
def create_eat_action()
|
|
246
|
-
lambda {|creature, target| @environment.objects.delete(target)}
|
|
247
|
-
end
|
|
248
|
-
#Create an action that applies a tag to the target.
|
|
249
|
-
def create_tag_action()
|
|
250
|
-
tag = create_tag()
|
|
251
|
-
lambda {|creature, target| target.tags << tag unless target.tags.include?(tag)}
|
|
252
|
-
end
|
|
253
|
-
#Generate a number between the given minimum and maximum, based on the current system time.
|
|
254
|
-
def generate_number(minimum, maximum)
|
|
255
|
-
(Time.new.to_f % (maximum - minimum)) + minimum
|
|
256
|
-
end
|
|
257
|
-
#Generate a random number between the given minimum and maximum.
|
|
258
|
-
def generate_random_number(minimum, maximum)
|
|
259
|
-
value = rand * (maximum - minimum) + minimum
|
|
260
|
-
end
|
|
261
|
-
end
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
#Keeps all objects within a set of walls.
|
|
266
|
-
class EncloseBehavior < Behavior
|
|
267
|
-
|
|
268
|
-
#Positions of walls.
|
|
269
|
-
attr_accessor :left, :top, :right, :bottom
|
|
270
|
-
|
|
271
|
-
def initialize
|
|
272
|
-
super
|
|
273
|
-
@left, @top, @right, @bottom = 0, 0, 0, 0
|
|
274
|
-
@actions << lambda do |boundary, object|
|
|
275
|
-
#If object is beyond a boundary, set its position equal to the boundary and reflect it.
|
|
276
|
-
if (object.location.x < @left) then
|
|
277
|
-
object.location.x = @left
|
|
278
|
-
object.vector.pitch = Utility.find_reflection_angle(90, object.vector.pitch)
|
|
279
|
-
elsif (object.location.x > @right) then
|
|
280
|
-
object.location.x = @right
|
|
281
|
-
object.vector.pitch = Utility.find_reflection_angle(270, object.vector.pitch)
|
|
282
|
-
end
|
|
283
|
-
if (object.location.y < @top) then
|
|
284
|
-
object.location.y = @top
|
|
285
|
-
object.vector.pitch = Utility.find_reflection_angle(0, object.vector.pitch)
|
|
286
|
-
elsif (object.location.y > @bottom) then
|
|
287
|
-
object.location.y = @bottom
|
|
288
|
-
object.vector.pitch = Utility.find_reflection_angle(180, object.vector.pitch)
|
|
289
|
-
end
|
|
290
|
-
end
|
|
291
|
-
end
|
|
292
|
-
|
|
293
|
-
end
|
|
294
|
-
|
|
295
|
-
|
|
296
37
|
|
|
297
38
|
class Application
|
|
298
39
|
|
|
@@ -334,15 +75,12 @@ class Application
|
|
|
334
75
|
|
|
335
76
|
|
|
336
77
|
#Keep all objects within a boundary.
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
@environment.environmental_factors <<
|
|
343
|
-
|
|
344
|
-
#Create a creature generator.
|
|
345
|
-
@generator = Generator.new(@environment, 0, 0, @width, @height)
|
|
78
|
+
enclosure = Enclosure.new
|
|
79
|
+
enclosure.left = 0
|
|
80
|
+
enclosure.bottom = 0
|
|
81
|
+
enclosure.top = @height
|
|
82
|
+
enclosure.right = @width
|
|
83
|
+
@environment.environmental_factors << enclosure
|
|
346
84
|
|
|
347
85
|
#Create thread to update environment.
|
|
348
86
|
thread = Thread.new do
|
|
@@ -350,9 +88,7 @@ class Application
|
|
|
350
88
|
begin
|
|
351
89
|
|
|
352
90
|
drawing_clock = Clock.new
|
|
353
|
-
birth_clock = Clock.new
|
|
354
91
|
time_per_frame = 1.0 / @fps
|
|
355
|
-
time_since_birth = 0
|
|
356
92
|
|
|
357
93
|
loop do
|
|
358
94
|
|
|
@@ -411,90 +147,30 @@ class Application
|
|
|
411
147
|
Utility.find_angle(@press_location, @release_location) #Move in direction of drag.
|
|
412
148
|
),
|
|
413
149
|
0,
|
|
150
|
+
1,
|
|
414
151
|
@tags_box.text.split(/,\s*/)
|
|
415
152
|
)
|
|
416
153
|
behavior = Behavior.new
|
|
417
154
|
condition_tags = @tag_condition_box.text
|
|
418
155
|
condition_tags.split(/,\s*/).each do |tag|
|
|
419
|
-
behavior.conditions <<
|
|
420
|
-
target.tags.include?(tag)
|
|
421
|
-
end
|
|
156
|
+
behavior.conditions << TagCondition.new(tag)
|
|
422
157
|
end
|
|
423
158
|
proximity = @proximity_condition_slider.value
|
|
424
|
-
if proximity > 0
|
|
425
|
-
behavior.conditions << lambda do |creature, target|
|
|
426
|
-
Utility.find_distance(creature.location, target.location) < proximity
|
|
427
|
-
end
|
|
428
|
-
end
|
|
159
|
+
behavior.conditions << ProximityCondition.new(proximity) if proximity > 0
|
|
429
160
|
age = @age_condition_slider.value
|
|
430
|
-
if age > 0
|
|
431
|
-
behavior.conditions << lambda do |creature, target|
|
|
432
|
-
target.age > age
|
|
433
|
-
end
|
|
434
|
-
end
|
|
161
|
+
behavior.conditions << AgeCondition.new(age) if age > 0
|
|
435
162
|
acceleration = @acceleration_slider.value
|
|
436
|
-
if acceleration != 0
|
|
437
|
-
behavior.actions << lambda do |creature, target|
|
|
438
|
-
creature.vector.speed += acceleration
|
|
439
|
-
creature.vector.speed = 0 if creature.vector.speed < 0
|
|
440
|
-
end
|
|
441
|
-
end
|
|
163
|
+
behavior.actions << AccelerateAction.new(acceleration) if acceleration != 0
|
|
442
164
|
turn = @turn_slider.value
|
|
443
|
-
if turn != 0
|
|
444
|
-
behavior.actions << lambda do |creature, target|
|
|
445
|
-
creature.vector.pitch += turn
|
|
446
|
-
end
|
|
447
|
-
end
|
|
165
|
+
behavior.actions << TurnAction.new(turn) if turn != 0
|
|
448
166
|
approach_angle = @approach_slider.value
|
|
449
|
-
if approach_angle > 0
|
|
450
|
-
heading = creature.vector.clone
|
|
451
|
-
behavior.actions << lambda do |creature, target|
|
|
452
|
-
#Find the difference between the current heading and the angle to the target.
|
|
453
|
-
turn_angle = Utility.find_angle(creature.location, target.location) - heading.pitch
|
|
454
|
-
#If the angle is the long way around from the current heading, change it to the smaller angle.
|
|
455
|
-
if turn_angle > 180 then
|
|
456
|
-
turn_angle -= 360.0
|
|
457
|
-
elsif turn_angle < -180 then
|
|
458
|
-
turn_angle += 360.0
|
|
459
|
-
end
|
|
460
|
-
#If turn angle is greater than allowed turn speed, reduce it.
|
|
461
|
-
turn_angle = Utility.constrain_value(turn_angle, approach_angle)
|
|
462
|
-
#Turn the appropriate amount.
|
|
463
|
-
heading.pitch += turn_angle
|
|
464
|
-
#Apply the heading to the creature's movement vector.
|
|
465
|
-
creature.vector += heading
|
|
466
|
-
end
|
|
467
|
-
end
|
|
167
|
+
behavior.actions << ApproachAction.new(Vector.new(1, creature.vector.pitch), approach_angle) if approach_angle > 0
|
|
468
168
|
flee_angle = @flee_slider.value
|
|
469
|
-
if flee_angle > 0
|
|
470
|
-
|
|
471
|
-
behavior.actions << lambda do |creature, target|
|
|
472
|
-
#Find the difference between the current heading and the angle to the target.
|
|
473
|
-
turn_angle = Utility.find_angle(creature.location, target.location) - heading.pitch + 180
|
|
474
|
-
#If the angle is the long way around from the current heading, change it to the smaller angle.
|
|
475
|
-
if turn_angle > 180 then
|
|
476
|
-
turn_angle -= 360.0
|
|
477
|
-
elsif turn_angle < -180 then
|
|
478
|
-
turn_angle += 360.0
|
|
479
|
-
end
|
|
480
|
-
#If turn angle is greater than allowed turn speed, reduce it.
|
|
481
|
-
turn_angle = Utility.constrain_value(turn_angle, flee_angle)
|
|
482
|
-
#Turn the appropriate amount.
|
|
483
|
-
heading.pitch += turn_angle
|
|
484
|
-
#Apply the heading to the creature's movement vector.
|
|
485
|
-
creature.vector += heading
|
|
486
|
-
end
|
|
487
|
-
end
|
|
488
|
-
if @eat_flag.active?
|
|
489
|
-
behavior.actions << lambda do |creature, target|
|
|
490
|
-
@environment.objects.delete(target)
|
|
491
|
-
end
|
|
492
|
-
end
|
|
169
|
+
behavior.actions << FleeAction.new(Vector.new(5, creature.vector.pitch), flee_angle) if flee_angle > 0
|
|
170
|
+
behavior.actions << EatAction.new(@environment) if @eat_flag.active?
|
|
493
171
|
apply_tags = @tag_action_box.text
|
|
494
172
|
apply_tags.split(/,\s*/).each do |tag|
|
|
495
|
-
behavior.
|
|
496
|
-
target.tags << tag unless target.tags.include?(tag)
|
|
497
|
-
end
|
|
173
|
+
behavior.actions << TagAction.new(tag)
|
|
498
174
|
end
|
|
499
175
|
creature.behaviors << behavior
|
|
500
176
|
@environment.objects << creature
|
data/bin/zyps_demo
CHANGED
|
@@ -20,10 +20,14 @@
|
|
|
20
20
|
|
|
21
21
|
begin
|
|
22
22
|
require 'zyps'
|
|
23
|
+
require 'zyps/actions'
|
|
24
|
+
require 'zyps/conditions'
|
|
23
25
|
require 'zyps/views/trails'
|
|
24
26
|
rescue LoadError
|
|
25
27
|
require 'rubygems'
|
|
26
28
|
require 'zyps'
|
|
29
|
+
require 'zyps/actions'
|
|
30
|
+
require 'zyps/conditions'
|
|
27
31
|
require 'zyps/views/trails'
|
|
28
32
|
end
|
|
29
33
|
|
|
@@ -38,6 +42,8 @@ class Demo
|
|
|
38
42
|
FRAME_COUNT = 80
|
|
39
43
|
#Number of frames per second.
|
|
40
44
|
FRAMES_PER_SECOND = 30
|
|
45
|
+
#Default size of game objects.
|
|
46
|
+
DEFAULT_OBJECT_SIZE = 78.5 #5 units in radius.
|
|
41
47
|
|
|
42
48
|
#Set up a window, a canvas, and an object environment, then run the given block.
|
|
43
49
|
def demo
|
|
@@ -102,10 +108,12 @@ class Demo
|
|
|
102
108
|
count.times do |i|
|
|
103
109
|
multiplier = i / count.to_f
|
|
104
110
|
environment.objects << Creature.new(
|
|
105
|
-
i,
|
|
111
|
+
i, #Name.
|
|
106
112
|
Location.new(multiplier * @view.width, multiplier * @view.height),
|
|
107
113
|
Color.new(multiplier, 1 - multiplier, multiplier / 2 + 0.5),
|
|
108
|
-
Vector.new(100 * multiplier, multiplier * 360)
|
|
114
|
+
Vector.new(100 * multiplier, multiplier * 360),
|
|
115
|
+
0, #Age.
|
|
116
|
+
DEFAULT_OBJECT_SIZE #Size.
|
|
109
117
|
)
|
|
110
118
|
end
|
|
111
119
|
end
|
|
@@ -125,7 +133,9 @@ class Demo
|
|
|
125
133
|
say("The things that populate an environment are called GameObjects. Each object has:")
|
|
126
134
|
object = GameObject.new
|
|
127
135
|
say("...a name")
|
|
128
|
-
object.name = "
|
|
136
|
+
object.name = "Huey"
|
|
137
|
+
say("...a size")
|
|
138
|
+
object.size = DEFAULT_OBJECT_SIZE
|
|
129
139
|
say("...a Location with x and y coordiates")
|
|
130
140
|
object.location = Location.new(@view.width/2, @view.height/2)
|
|
131
141
|
say("...a Color with red, green and blue components ranging from 0 to 1")
|
|
@@ -136,14 +146,28 @@ class Demo
|
|
|
136
146
|
say("Once your object is ready, add it to the environment.")
|
|
137
147
|
@environment.objects << object
|
|
138
148
|
|
|
139
|
-
say("
|
|
149
|
+
say("Add a view as an observer of an Environment, and it will draw the objects.")
|
|
140
150
|
say("Call an environment's interact() method to have the objects in it move around.")
|
|
141
|
-
say("Our demo's animate() method does
|
|
151
|
+
say("Our demo's animate() method does this for us.")
|
|
142
152
|
animate(FRAME_COUNT)
|
|
143
153
|
|
|
144
154
|
say("Let's add a couple more objects with different colors and vectors.")
|
|
145
|
-
@environment.objects << GameObject.new(
|
|
146
|
-
|
|
155
|
+
@environment.objects << GameObject.new(
|
|
156
|
+
"Duey", #Name.
|
|
157
|
+
Location.new(@view.width/2, @view.height/2),
|
|
158
|
+
Color.new(0, 1, 0),
|
|
159
|
+
Vector.new(20, 135),
|
|
160
|
+
0, #Age.
|
|
161
|
+
DEFAULT_OBJECT_SIZE * 2 #Size.
|
|
162
|
+
)
|
|
163
|
+
@environment.objects << GameObject.new(
|
|
164
|
+
"Louie", #Name.
|
|
165
|
+
Location.new(@view.width/2, @view.height/2),
|
|
166
|
+
Color.new(0, 0, 1),
|
|
167
|
+
Vector.new(30, 225),
|
|
168
|
+
0, #Age.
|
|
169
|
+
DEFAULT_OBJECT_SIZE * 3 #Size.
|
|
170
|
+
)
|
|
147
171
|
animate(FRAME_COUNT)
|
|
148
172
|
|
|
149
173
|
say("The viewing area can be resized at any time via its width and height attributes.")
|
|
@@ -151,16 +175,22 @@ class Demo
|
|
|
151
175
|
@view.height += 100
|
|
152
176
|
animate(FRAME_COUNT)
|
|
153
177
|
|
|
154
|
-
say("TrailsView lets you set the
|
|
155
|
-
@view.
|
|
156
|
-
@view.trail_length = 10
|
|
178
|
+
say("TrailsView lets you set the length of the trails as well.")
|
|
179
|
+
@view.trail_length = 50
|
|
157
180
|
animate(FRAME_COUNT)
|
|
158
181
|
|
|
159
182
|
end
|
|
160
|
-
|
|
183
|
+
|
|
161
184
|
end
|
|
162
185
|
|
|
163
186
|
|
|
187
|
+
class Gravity < EnvironmentalFactor
|
|
188
|
+
#Accelerate object toward the 'ground'.
|
|
189
|
+
def act(target)
|
|
190
|
+
target.vector.y += 9.8
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
164
194
|
#Demonstrates environmental factors by adding gravity to the environment.
|
|
165
195
|
def test_environmental_factors
|
|
166
196
|
|
|
@@ -172,26 +202,19 @@ class Demo
|
|
|
172
202
|
animate(FRAME_COUNT)
|
|
173
203
|
|
|
174
204
|
say("Let's add a new EnvironmentalFactor to simulate gravity.")
|
|
175
|
-
gravity =
|
|
205
|
+
gravity = Gravity.new
|
|
176
206
|
|
|
177
|
-
say("We
|
|
178
|
-
accelerate = Behavior.new
|
|
179
|
-
say("The behavior will have a single action: to accelerate objects toward the 'ground' at 9.8 meters/second.")
|
|
180
|
-
accelerate.actions << lambda {|gravity, target| target.vector.y += 9.8}
|
|
181
|
-
say("We add the behavior to the EnvironmentalFactor.")
|
|
182
|
-
gravity.behaviors << accelerate
|
|
183
|
-
say("Then we add the EnvironmentalFactor to the Environment.")
|
|
207
|
+
say("We add gravity to the Environment.")
|
|
184
208
|
@environment.environmental_factors << gravity
|
|
185
209
|
|
|
186
210
|
say("Everything immediately drops.")
|
|
187
211
|
animate(FRAME_COUNT)
|
|
188
212
|
|
|
189
213
|
end
|
|
190
|
-
|
|
214
|
+
|
|
191
215
|
end
|
|
192
216
|
|
|
193
217
|
|
|
194
|
-
|
|
195
218
|
#Demonstrates creature behaviors.
|
|
196
219
|
def test_behaviors
|
|
197
220
|
|
|
@@ -199,17 +222,17 @@ class Demo
|
|
|
199
222
|
|
|
200
223
|
thread = Thread.new do
|
|
201
224
|
|
|
202
|
-
say("Let's add a
|
|
225
|
+
say("Let's add a Behavior to our creatures.")
|
|
203
226
|
chase = Behavior.new
|
|
204
227
|
|
|
205
|
-
say("
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
creature.vector.pitch = angle_to_target
|
|
209
|
-
end
|
|
228
|
+
say("A Behavior has one or more Action objects that define an action to take on the current target.")
|
|
229
|
+
say("We'll add an Action that makes the creatures head straight toward their target.")
|
|
230
|
+
chase.actions << FaceAction.new
|
|
210
231
|
|
|
232
|
+
say("A Behavior also has one or more Condition objects.")
|
|
233
|
+
say("Unless every Condition is true, the action(s) won't be carried out.")
|
|
211
234
|
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'.")
|
|
212
|
-
chase.conditions <<
|
|
235
|
+
chase.conditions << TagCondition.new("food")
|
|
213
236
|
|
|
214
237
|
say("We'll apply this behavior to all creatures currently in the environment.")
|
|
215
238
|
@environment.objects.each {|creature| creature.behaviors << chase}
|
|
@@ -217,11 +240,12 @@ class Demo
|
|
|
217
240
|
|
|
218
241
|
say("Then we'll toss a piece of food (a GameObject with the label 'food') into the environment.")
|
|
219
242
|
@environment.objects << GameObject.new(
|
|
220
|
-
"target",
|
|
243
|
+
"target", #Name.
|
|
221
244
|
Location.new(@view.width / 2, @view.height / 2),
|
|
222
245
|
Color.new(1, 1, 1),
|
|
223
246
|
Vector.new(50, 315),
|
|
224
247
|
0, #Age.
|
|
248
|
+
DEFAULT_OBJECT_SIZE * 2, #Size.
|
|
225
249
|
["food"] #Tags.
|
|
226
250
|
)
|
|
227
251
|
|
|
@@ -235,17 +259,14 @@ class Demo
|
|
|
235
259
|
|
|
236
260
|
#A Creature that changes the colors of other objects.
|
|
237
261
|
class Morpher < Creature
|
|
262
|
+
#Changes an object's color.
|
|
238
263
|
def initialize(*arguments)
|
|
239
264
|
super
|
|
240
265
|
morph = Behavior.new
|
|
241
266
|
#Shift the target's color to match the creature's.
|
|
242
|
-
morph.actions <<
|
|
243
|
-
target.color.red += 0.1 if target.color.red < creature.color.red
|
|
244
|
-
target.color.green += 0.1 if target.color.green < creature.color.green
|
|
245
|
-
target.color.blue += 0.1 if target.color.blue < creature.color.blue
|
|
246
|
-
end
|
|
267
|
+
morph.actions << BlendAction.new(self.color)
|
|
247
268
|
#Act only on nearby targets.
|
|
248
|
-
morph.conditions <<
|
|
269
|
+
morph.conditions << ProximityCondition.new(50)
|
|
249
270
|
@behaviors << morph
|
|
250
271
|
end
|
|
251
272
|
end
|
|
@@ -260,15 +281,15 @@ class Demo
|
|
|
260
281
|
say("Morphers are created with a single behavior, which shifts the color of any nearby target to match the Morpher's color.")
|
|
261
282
|
|
|
262
283
|
say("Let's place a red Morpher...")
|
|
263
|
-
@environment.objects << Morpher.new(nil, Location.new(0, 100), Color.new(1, 0, 0), Vector.new(100, 0))
|
|
284
|
+
@environment.objects << Morpher.new(nil, Location.new(0, 100), Color.new(1, 0, 0), Vector.new(100, 0), 0, DEFAULT_OBJECT_SIZE)
|
|
264
285
|
say("a green one...")
|
|
265
|
-
@environment.objects << Morpher.new(nil, Location.new(0, 150), Color.new(0, 1, 0), Vector.new(200, 0))
|
|
286
|
+
@environment.objects << Morpher.new(nil, Location.new(0, 150), Color.new(0, 1, 0), Vector.new(200, 0), 0, DEFAULT_OBJECT_SIZE)
|
|
266
287
|
say("and a blue one...")
|
|
267
|
-
@environment.objects << Morpher.new(nil, Location.new(0, 200), Color.new(0, 0, 1), Vector.new(300, 0))
|
|
288
|
+
@environment.objects << Morpher.new(nil, Location.new(0, 200), Color.new(0, 0, 1), Vector.new(300, 0), 0, DEFAULT_OBJECT_SIZE)
|
|
268
289
|
|
|
269
290
|
say("And see what they do.")
|
|
270
291
|
thread = Thread.new {animate(FRAME_COUNT)}
|
|
271
|
-
|
|
292
|
+
|
|
272
293
|
end
|
|
273
294
|
|
|
274
295
|
|
|
@@ -280,30 +301,17 @@ class Demo
|
|
|
280
301
|
thread = Thread.new do
|
|
281
302
|
|
|
282
303
|
|
|
283
|
-
say("Many actions need to happen smoothly over time, such as accelerating at a given rate.")
|
|
284
|
-
|
|
285
304
|
say("Here are some Creatures, just plodding along.")
|
|
286
305
|
animate(FRAME_COUNT / 4)
|
|
287
306
|
say("We're going to have them pick up the pace.")
|
|
288
307
|
|
|
289
|
-
say("
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
say("It will multiply that time by a given rate, say 100 meters/second.")
|
|
295
|
-
say("Let's say it's been 0.1 seconds since this creature last accelerated.")
|
|
296
|
-
say("100 times 0.1 is 10.")
|
|
297
|
-
say("So we should add 10 meters/second to the creature's speed.")
|
|
298
|
-
accelerate = Behavior.new
|
|
299
|
-
accelerate.actions << lambda do |creature, target|
|
|
300
|
-
#Accelerate the appropriate amount for the elapsed time.
|
|
301
|
-
creature.vector.speed += 100 * clocks[creature].elapsed_time
|
|
308
|
+
say("We add a Behavior with an AccelerateAction to all the creatures, and specify they should increase their speed by 100 units/second...")
|
|
309
|
+
@environment.objects.each do |creature|
|
|
310
|
+
accelerate = Behavior.new
|
|
311
|
+
accelerate.actions << AccelerateAction.new(100)
|
|
312
|
+
creature.behaviors << accelerate
|
|
302
313
|
end
|
|
303
314
|
|
|
304
|
-
say("We add acceleration to all the creatures...")
|
|
305
|
-
@environment.objects.each {|creature| creature.behaviors << accelerate}
|
|
306
|
-
|
|
307
315
|
say("And watch them rocket away.")
|
|
308
316
|
animate(FRAME_COUNT)
|
|
309
317
|
|
|
@@ -319,24 +327,16 @@ class Demo
|
|
|
319
327
|
|
|
320
328
|
thread = Thread.new do
|
|
321
329
|
|
|
322
|
-
say("
|
|
330
|
+
say("This time we'll use the TurnAction class.")
|
|
323
331
|
animate(FRAME_COUNT / 2)
|
|
324
332
|
|
|
325
|
-
say("
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
say("We add the result to the Vector angle.")
|
|
331
|
-
turn = Behavior.new
|
|
332
|
-
turn.actions << lambda do |creature, target|
|
|
333
|
-
#Turn the appropriate amount for the elapsed time.
|
|
334
|
-
creature.vector.pitch += 100 * clocks[creature].elapsed_time
|
|
333
|
+
say("We tell each creature it should turn by 90 degrees/second...")
|
|
334
|
+
@environment.objects.each do |creature|
|
|
335
|
+
turn = Behavior.new
|
|
336
|
+
turn.actions << TurnAction.new(90)
|
|
337
|
+
creature.behaviors << turn
|
|
335
338
|
end
|
|
336
339
|
|
|
337
|
-
say("We add the behavior to each Creature...")
|
|
338
|
-
@environment.objects.each {|creature| creature.behaviors << turn}
|
|
339
|
-
|
|
340
340
|
say("And watch things spiral out of control.")
|
|
341
341
|
animate(FRAME_COUNT)
|
|
342
342
|
|
|
@@ -351,55 +351,25 @@ class Demo
|
|
|
351
351
|
populate(@environment, 50)
|
|
352
352
|
|
|
353
353
|
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.")
|
|
354
|
-
say("
|
|
355
|
-
|
|
356
|
-
say("We
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
say("We create a Behavior which adds the Vector the creature WANTS to follow to the Vector it's ACTUALLY following.")
|
|
363
|
-
approach = Behavior.new
|
|
364
|
-
approach.actions << lambda do |creature, target|
|
|
365
|
-
|
|
366
|
-
#Find the difference between the current heading and the angle to the target.
|
|
367
|
-
turn_angle = Utility.find_angle(creature.location, target.location) - headings[creature].pitch
|
|
368
|
-
|
|
369
|
-
#If the angle is the long way around from the current heading, change it to the smaller angle.
|
|
370
|
-
if turn_angle > 180 then
|
|
371
|
-
turn_angle -= 360.0
|
|
372
|
-
elsif turn_angle < -180 then
|
|
373
|
-
turn_angle += 360.0
|
|
374
|
-
end
|
|
375
|
-
|
|
376
|
-
#If turn angle is greater than allowed turn speed, reduce it.
|
|
377
|
-
turn_angle = Utility.constrain_value(turn_angle, max_turn_angle)
|
|
378
|
-
|
|
379
|
-
#Turn the appropriate amount.
|
|
380
|
-
headings[creature].pitch += turn_angle
|
|
381
|
-
|
|
382
|
-
#Apply the heading to the creature's movement vector.
|
|
383
|
-
creature.vector += headings[creature]
|
|
384
|
-
|
|
385
|
-
end
|
|
386
|
-
|
|
387
|
-
say("We add a condition that it should only target its prey.")
|
|
388
|
-
approach.conditions << lambda do |creature, target|
|
|
389
|
-
target.tags.include?('prey')
|
|
354
|
+
say("Our ApproachAction adds the vector the creature WANTS to follow to the vector it's ACTUALLY following.")
|
|
355
|
+
say("We add a behavior with an ApproachAction to all creatures...")
|
|
356
|
+
say("We also add a condition that it should only target food.")
|
|
357
|
+
@environment.objects.each do |creature|
|
|
358
|
+
approach = Behavior.new
|
|
359
|
+
approach.actions << ApproachAction.new(creature.vector)
|
|
360
|
+
approach.conditions << TagCondition.new("food")
|
|
361
|
+
creature.behaviors << approach
|
|
390
362
|
end
|
|
391
363
|
|
|
392
|
-
say("We add the behavior to all creatures...")
|
|
393
|
-
@environment.objects.each {|creature| creature.behaviors << approach}
|
|
394
|
-
|
|
395
364
|
say("Add a target...")
|
|
396
365
|
@environment.objects << Creature.new(
|
|
397
366
|
"target",
|
|
398
|
-
Location.new(@view.width / 2, @view.height /
|
|
367
|
+
Location.new(@view.width / 2, @view.height / 3),
|
|
399
368
|
Color.new(1, 1, 1),
|
|
400
369
|
Vector.new(3, 0),
|
|
401
370
|
0, #Age.
|
|
402
|
-
|
|
371
|
+
DEFAULT_OBJECT_SIZE, #Size.
|
|
372
|
+
["food"] #Tags.
|
|
403
373
|
)
|
|
404
374
|
|
|
405
375
|
say("And watch them all TRY to catch it.")
|
|
@@ -408,58 +378,27 @@ class Demo
|
|
|
408
378
|
end
|
|
409
379
|
|
|
410
380
|
|
|
411
|
-
|
|
381
|
+
|
|
382
|
+
#Demonstrates adding vectors.
|
|
412
383
|
def test_flee
|
|
413
384
|
|
|
414
|
-
populate(@environment,
|
|
415
|
-
|
|
416
|
-
say("Fleeing from something is just like approaching it, but we head in the OPPOSITE direction.")
|
|
417
|
-
say("Just get the angle toward the object, then add 180 degrees.")
|
|
418
|
-
|
|
419
|
-
#Keep a separate heading for each object.
|
|
420
|
-
headings = Hash.new {|h, k| h[k] = Vector.new(k.vector.speed, k.vector.pitch)}
|
|
421
|
-
|
|
422
|
-
#Create a behavior.
|
|
423
|
-
max_turn_angle = 20
|
|
424
|
-
flee = Behavior.new
|
|
425
|
-
flee.actions << lambda do |creature, target|
|
|
426
|
-
|
|
427
|
-
#Find the difference between the current heading and the angle AWAY from the target.
|
|
428
|
-
turn_angle = Utility.find_angle(creature.location, target.location) - headings[creature].pitch + 180
|
|
429
|
-
|
|
430
|
-
#If the angle is the long way around from the current heading, change it to the smaller angle.
|
|
431
|
-
if turn_angle > 180 then
|
|
432
|
-
turn_angle -= 360.0
|
|
433
|
-
elsif turn_angle < -180 then
|
|
434
|
-
turn_angle += 360.0
|
|
435
|
-
end
|
|
436
|
-
|
|
437
|
-
#If turn angle is greater than allowed turn speed, reduce it.
|
|
438
|
-
turn_angle = Utility.constrain_value(turn_angle, max_turn_angle)
|
|
439
|
-
|
|
440
|
-
#Turn the appropriate amount for the elapsed time.
|
|
441
|
-
headings[creature].pitch += turn_angle
|
|
442
|
-
|
|
443
|
-
#Apply the heading to the creature's movement vector.
|
|
444
|
-
creature.vector += headings[creature]
|
|
445
|
-
|
|
446
|
-
end
|
|
385
|
+
populate(@environment, 50)
|
|
447
386
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
387
|
+
say("A FleeAction is just like an ApproachAction, but we head in the OPPOSITE direction.")
|
|
388
|
+
@environment.objects.each do |creature|
|
|
389
|
+
flee = Behavior.new
|
|
390
|
+
flee.actions << FleeAction.new(creature.vector)
|
|
391
|
+
flee.conditions << TagCondition.new("predator")
|
|
392
|
+
creature.behaviors << flee
|
|
451
393
|
end
|
|
452
394
|
|
|
453
|
-
#Add behavior to creatures.
|
|
454
|
-
@environment.objects.each {|creature| creature.behaviors << flee}
|
|
455
|
-
|
|
456
|
-
#Add a target.
|
|
457
395
|
@environment.objects << Creature.new(
|
|
458
|
-
"
|
|
396
|
+
"target",
|
|
459
397
|
Location.new(@view.width / 2, @view.height / 2),
|
|
460
398
|
Color.new(1, 1, 1),
|
|
461
399
|
Vector.new(3, 0),
|
|
462
400
|
0, #Age.
|
|
401
|
+
DEFAULT_OBJECT_SIZE, #Size.
|
|
463
402
|
["predator"] #Tags.
|
|
464
403
|
)
|
|
465
404
|
|
|
@@ -468,47 +407,32 @@ class Demo
|
|
|
468
407
|
end
|
|
469
408
|
|
|
470
409
|
|
|
471
|
-
|
|
472
|
-
class Destroy < Behavior
|
|
473
|
-
#Environment from which targets will be removed.
|
|
474
|
-
attr_accessor :environment
|
|
475
|
-
def initialize(actions = [], conditions = [], environment = Environment.new)
|
|
476
|
-
super(actions, conditions)
|
|
477
|
-
@environment = environment
|
|
478
|
-
#"Kill" target.
|
|
479
|
-
self.actions << lambda do |creature, target|
|
|
480
|
-
@environment.objects.delete(target)
|
|
481
|
-
end
|
|
482
|
-
#Act only if target is close.
|
|
483
|
-
self.conditions << lambda do |creature, target|
|
|
484
|
-
Utility.find_distance(creature.location, target.location) < 25
|
|
485
|
-
end
|
|
486
|
-
end
|
|
487
|
-
end
|
|
488
|
-
|
|
489
|
-
|
|
410
|
+
|
|
490
411
|
#Demonstrates keeping a reference to an Environment so a Creature can alter it.
|
|
491
|
-
def
|
|
412
|
+
def test_eat
|
|
492
413
|
|
|
493
414
|
populate(@environment)
|
|
494
415
|
|
|
495
416
|
say("Most games are all about destruction, but there hasn't been much so far.")
|
|
496
417
|
say("Let's create a creature that causes some havoc.")
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
say("
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
say("
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
418
|
+
predator = Creature.new(nil, Location.new(0, 150), Color.new(0, 1, 0), Vector.new(200, 0), 0, DEFAULT_OBJECT_SIZE * 2)
|
|
419
|
+
|
|
420
|
+
say("The EatAction eats targets by removing them from their environment.")
|
|
421
|
+
say("Creatures and their Actions normally know nothing about the Environment they belong to, so EatAction takes an Environment in its constructor.")
|
|
422
|
+
say("EatAction finds the target in Environment.objects and removes it.")
|
|
423
|
+
action = EatAction.new(@environment)
|
|
424
|
+
|
|
425
|
+
say("Create a behavior...")
|
|
426
|
+
behavior = Behavior.new
|
|
427
|
+
say("Add the action to the behavior...")
|
|
428
|
+
behavior.actions << action
|
|
429
|
+
say("Add a condition that they must collide first...")
|
|
430
|
+
behavior.conditions << CollisionCondition.new
|
|
431
|
+
say("Add the behavior to the creature...")
|
|
432
|
+
predator.behaviors << behavior
|
|
509
433
|
|
|
510
434
|
say("Drop the creature into the actual environment...")
|
|
511
|
-
@environment.objects <<
|
|
435
|
+
@environment.objects << predator
|
|
512
436
|
|
|
513
437
|
say("And - chomp!")
|
|
514
438
|
thread = Thread.new {animate(FRAME_COUNT)}
|
|
@@ -518,6 +442,7 @@ class Demo
|
|
|
518
442
|
|
|
519
443
|
#Run all the demos.
|
|
520
444
|
def main
|
|
445
|
+
say "This is a demonstration of the Zyps library."
|
|
521
446
|
say "After each demo, close the window to proceed."
|
|
522
447
|
say("-" * 30)
|
|
523
448
|
demo {test_render}
|
|
@@ -528,7 +453,10 @@ class Demo
|
|
|
528
453
|
demo {test_turn}
|
|
529
454
|
demo {test_approach}
|
|
530
455
|
demo {test_flee}
|
|
531
|
-
demo {
|
|
456
|
+
demo {test_eat}
|
|
457
|
+
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."
|
|
458
|
+
say "And if you want to code your own Actions, Conditions, EnvironmentalFactors, or Views, see the distribution's 'lib' folder for examples."
|
|
459
|
+
say "Thanks for watching!"
|
|
532
460
|
end
|
|
533
461
|
|
|
534
462
|
|