gosling 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2e286ba691604561ac6676e60e49699cd3167587
4
- data.tar.gz: 6e2083451057aa524bed3f13012134e829a55f80
3
+ metadata.gz: ea892a020a95cbff0d56b2410eed22dcdffa0816
4
+ data.tar.gz: 9ad565fa00e58440ad245ec0ceae7479ab6c3900
5
5
  SHA512:
6
- metadata.gz: 6232f177ad08bc4869af947c3c6748c004a052d47ca92247a8d0c54910117a6c8984aa5c5d7d35edb109e31ca5281536fc52c5013928b43bdd958e5edb1c6c44
7
- data.tar.gz: 35fe442a079c785663f73640b006171c57872fe0c189bf55c9aa1146fd88c336f4cdabf52db410f3a84361fa862081dff505391c563e9f1f80e16729f1514a5f
6
+ metadata.gz: c45e93330e44318c58d2a76456d836366d7a9dc77ecd2c70ab08c1762ac6d92ca5cd20f257c367212759c03703e0387d7809ba08e88f48a3e3f7ecf8fa0ad500
7
+ data.tar.gz: 4711c9d648c83e8d26b5dfdf7b2bd7266db076500ad21c85ad8b1669fe26785efaf7294a48f6865609ee2f5d4f6b93e8256f7ac926686990cfdde2db41d308ea
data/lib/gosling/actor.rb CHANGED
@@ -3,10 +3,70 @@ require_relative 'transform.rb'
3
3
  require 'gosu'
4
4
 
5
5
  module Gosling
6
+ ##
7
+ # Actors are fundamental elements of a rendering and worldspace hierarchy. They represent the things that exist
8
+ # inside of the game world or parts of our application's user interface.
9
+ #
10
+ # A key difference between an Actor and any of its subclasses - Circle, Polygon, Sprite, and the like - is that an
11
+ # Actor is inherently intangible. By itself, it has no shape or appearance and takes up no space. If it's something you
12
+ # can see or interact with, it should probably be an instance of one of Actor's subclasses.
13
+ #
14
+ # The inheritance model is what makes an Actor by itself useful. Actors can have one or more children, which can be
15
+ # any type of Actor. Those Actors can in turn have any number of child Actors, and so on, creating a sort of tree
16
+ # structure. A parent Actor's transform is inherited by its children, so moving or rotating a parent Actor moves or
17
+ # rotates all of its children relative to its parent. And when a parent is drawn, all of its children are drawn as well
18
+ # (see #draw for exceptions).
19
+ #
20
+ # One common application of this is to use a plain Actor as a root object to which all other elements visible in the
21
+ # game world are added. As the player moves through the game world, rather than move the position of each game
22
+ # element across the screen to simulate travel, you need only move the root Actor and all other Actors will be moved
23
+ # similarly. This root actor then acts like a "stage" or "camera". For this reason, one could think of a plain Actor as
24
+ # sort of a "container" for other Actors, a way to keep them all organized and related.
25
+ #
26
+ # The behavior of inheritance can modified by setting various properties. Read on for more details.
27
+ #
6
28
  class Actor
7
29
  attr_reader :transform, :parent, :children, :window
8
- attr_accessor :is_visible, :is_tangible, :are_children_visible, :are_children_tangible, :is_mask, :color
9
30
 
31
+ ##
32
+ # If set to true, this Actor will be drawn to screen. If false, it will be skipped. The default is true.
33
+ #
34
+ attr_accessor :is_visible
35
+
36
+ ##
37
+ # If set to true, this Actor will respond to "point-in-shape" tests. If false, such tests will skip this Actor. The default
38
+ # is true.
39
+ #
40
+ attr_accessor :is_tangible
41
+
42
+ ##
43
+ # If set to true, all of this Actor's children will be drawn to screen. If false, they and their descendants will be
44
+ # skipped. The default is true.
45
+ #
46
+ attr_accessor :are_children_visible
47
+
48
+ ##
49
+ # If set to true, this Actor's children will respond to "point-in-shape" tests. If false, such tests will skip them and
50
+ # their descendants. The default is true.
51
+ #
52
+ attr_accessor :are_children_tangible
53
+
54
+ ##
55
+ # If set to true, this Actor will be treated as a "mask" for its parent regarding "point-in-shape" tests. If the point is
56
+ # in this Actor's bounds, it will act as though the point is in its parent's bounds instead of its own. The default is
57
+ # false.
58
+ #
59
+ attr_accessor :is_mask
60
+
61
+ ##
62
+ # The Gosu::Color to use when rendering this Actor.
63
+ #
64
+ attr_accessor :color
65
+
66
+ ##
67
+ # Creates a new Actor, setting all inheritance properties to their defaults and assigning a random color. Requires
68
+ # a Gosu::Window to be used when rendering.
69
+ #
10
70
  def initialize(window)
11
71
  @window = window
12
72
  @transform = Transform.new
@@ -24,17 +84,16 @@ module Gosling
24
84
  "#<#{self.class}:#{self.object_id}>"
25
85
  end
26
86
 
27
- def parent=(parent)
28
- return if parent == @parent
29
- unless parent
30
- raise Gosling::InheritanceError.new("You should use Actor.remove_child() instead of setting the parent directly.") if @parent.has_child?(self)
31
- end
32
- @parent = parent
33
- if @parent
34
- raise Gosling::InheritanceError.new("You should use Actor.add_child() instead of setting the parent directly.") unless @parent.has_child?(self)
35
- end
36
- end
37
-
87
+ ##
88
+ # Establishes a parent/child relationship between this actor and the one passed, respectively. The child Actor will
89
+ # appear relative to its parent, move as the parent moves, and draw when the parent draws.
90
+ #
91
+ # An Actor cannot be made a child of itself. Similarly, a child cannot be added to a parent if doing so would create
92
+ # a circular reference (e.g. a.add_child(b) followed by b.add_child(a)).
93
+ #
94
+ # If the child Actor already had a parent, the Actor is disassociated from its former parent before becoming
95
+ # associated with this one. An Actor can have only one parent at a time.
96
+ #
38
97
  def add_child(child)
39
98
  return if @children.include?(child)
40
99
  raise Gosling::InheritanceError.new("An Actor cannot be made a child of itself.") if child == self
@@ -49,6 +108,10 @@ module Gosling
49
108
  child.parent = self
50
109
  end
51
110
 
111
+ ##
112
+ # If the given Actor is a child of this Actor, it is disassociated from this Actor. In any case, the child Actor is
113
+ # immediately orphaned.
114
+ #
52
115
  def remove_child(child)
53
116
  return unless @children.include?(child)
54
117
 
@@ -56,94 +119,137 @@ module Gosling
56
119
  child.parent = nil
57
120
  end
58
121
 
122
+ ##
123
+ # Returns true if this Actor has the given Actor as a child.
124
+ #
59
125
  def has_child?(child)
60
126
  @children.include?(child)
61
127
  end
62
128
 
129
+ ##
130
+ # Wrapper method. Returns this Actor's x position in relative space. See Transform#translation.
131
+ #
63
132
  def x
64
- @transform.translation[0]
133
+ @transform.translation.x
65
134
  end
66
135
 
136
+ ##
137
+ # Wrapper method. Sets this Actor's x position in relative space. See Transform#translation.
138
+ #
67
139
  def x=(val)
68
- array = @transform.translation.to_a
69
- array[0] = val
70
- @transform.set_translation(Vector.elements(array))
140
+ @transform.translation = val, @transform.translation.y
71
141
  end
72
142
 
143
+ ##
144
+ # Wrapper method. Returns this Actor's y position in relative space. See Transform#translation.
145
+ #
73
146
  def y
74
- @transform.translation[1]
147
+ @transform.translation.y
75
148
  end
76
149
 
150
+ ##
151
+ # Wrapper method. Sets this Actor's y position in relative space. See Transform#translation.
152
+ #
77
153
  def y=(val)
78
- array = @transform.translation.to_a
79
- array[1] = val
80
- @transform.set_translation(Vector.elements(array))
154
+ @transform.translation = @transform.translation.x, val
81
155
  end
82
156
 
157
+ ##
158
+ # Wrapper method. Returns this Actor's position in relative space as a Snow::Vec3. See Transform#translation.
159
+ #
83
160
  def pos
84
- Vector[x, y, 0]
161
+ @transform.translation
85
162
  end
86
163
 
164
+ ##
165
+ # Wrapper method. Sets this Actor's position in relative space. See Transform#translation.
166
+ #
87
167
  def pos=(val)
88
- array = @transform.translation.to_a
89
- array[0] = val[0]
90
- array[1] = val[1]
91
- @transform.set_translation(Vector.elements(array))
168
+ @transform.translation = val
92
169
  end
93
170
 
171
+ ##
172
+ # Wrapper method. Returns the x component of the centerpoint of this Actor. See Transform#center.
173
+ #
94
174
  def center_x
95
- @transform.center[0]
175
+ @transform.center.x
96
176
  end
97
177
 
178
+ ##
179
+ # Wrapper method. Sets the x component of the centerpoint of this Actor. See Transform#center.
180
+ #
98
181
  def center_x=(val)
99
- array = @transform.center.to_a
100
- array[0] = val
101
- @transform.set_center(Vector.elements(array))
182
+ @transform.center = val, @transform.center.y
102
183
  end
103
184
 
185
+ ##
186
+ # Wrapper method. Returns the y component of the centerpoint of this Actor. See Transform#center.
187
+ #
104
188
  def center_y
105
- @transform.center[1]
189
+ @transform.center.y
106
190
  end
107
191
 
192
+ ##
193
+ # Wrapper method. Sets the y component of the centerpoint of this Actor. See Transform#center.
194
+ #
108
195
  def center_y=(val)
109
- array = @transform.center.to_a
110
- array[1] = val
111
- @transform.set_center(Vector.elements(array))
196
+ @transform.center = @transform.center.x, val
112
197
  end
113
198
 
199
+ ##
200
+ # Wrapper method. Returns the x component of the scaling of this Actor. See Transform#scale.
201
+ #
114
202
  def scale_x
115
- @transform.scale[0]
203
+ @transform.scale.x
116
204
  end
117
205
 
206
+ ##
207
+ # Wrapper method. Sets the x component of the scaling of this Actor. See Transform#scale.
208
+ #
118
209
  def scale_x=(val)
119
- array = @transform.scale.to_a
120
- array[0] = val
121
- @transform.set_scale(Vector.elements(array))
210
+ @transform.scale = val, @transform.scale.y
122
211
  end
123
212
 
213
+ ##
214
+ # Wrapper method. Returns the y component of the scaling of this Actor. See Transform#scale.
215
+ #
124
216
  def scale_y
125
- @transform.scale[1]
217
+ @transform.scale.y
126
218
  end
127
219
 
220
+ ##
221
+ # Wrapper method. Sets the y component of the scaling of this Actor. See Transform#scale.
222
+ #
128
223
  def scale_y=(val)
129
- array = @transform.scale.to_a
130
- array[1] = val
131
- @transform.set_scale(Vector.elements(array))
224
+ @transform.scale = @transform.scale.x, val
132
225
  end
133
226
 
227
+ ##
228
+ # Wrapper method. Returns this Actor's rotation in radians. See Transform#rotation.
229
+ #
134
230
  def rotation
135
231
  @transform.rotation
136
232
  end
137
233
 
234
+ ##
235
+ # Wrapper method. Sets this Actor's rotation in radians. See Transform#rotation.
236
+ #
138
237
  def rotation=(val)
139
- @transform.set_rotation(val)
140
- end
141
-
142
- def render(matrix)
143
- end
144
-
238
+ @transform.rotation = val
239
+ end
240
+
241
+ ##
242
+ # Calls #render on this Actor, drawing it to the screen if #is_visible is set to true (the default).
243
+ #
244
+ # The Actor's transforms, if any, will be applied prior to rendering. If an optional Snow::Mat3 matrix transform is
245
+ # given, the Actor will be transformed by a combination of that matrix transform and its own.
246
+ #
247
+ # If the #are_children_visible flag is set to true (the default), then this method will recursively call draw on each
248
+ # of the Actor's children, passing them the combined matrix used to render the parent. Otherwise, children will
249
+ # be skipped and not drawn.
250
+ #
145
251
  def draw(matrix = nil)
146
- matrix ||= Matrix.identity(3)
252
+ matrix ||= Snow::Mat3.new
147
253
  transform = matrix * @transform.to_matrix
148
254
  render(transform) if @is_visible
149
255
  if @are_children_visible
@@ -151,10 +257,28 @@ module Gosling
151
257
  end
152
258
  end
153
259
 
260
+ ##
261
+ # Returns false. Actors have no shape, and so no point is in their bounds. Subclasses override this method with
262
+ # shape-specific behavior.
263
+ #
154
264
  def is_point_in_bounds(point)
155
265
  false
156
266
  end
157
267
 
268
+ ##
269
+ # Given a point in global space, tests this Actor and each of its children, returning the first Actor for whom this
270
+ # point is inside its shape. Respects each Actor's transforms as well as any it may inherit from its ancestors.
271
+ # Useful for determining which Actor the user may have clicked on.
272
+ #
273
+ # If the #is_tangible flag is set to false, this Actor will not be tested. The default is true.
274
+ #
275
+ # If the #are_children_tangible flag is set to false, this Actor's children will not be tested. The default is true.
276
+ #
277
+ # If the #is_mask flag is set to true, a positive test from this Actor instead returns its parent Actor, if any. The
278
+ # default is false.
279
+ #
280
+ # If the point is not inside this Actor or any of its children (excluding any skipped Actors), nil is returned.
281
+ #
158
282
  def get_actor_at(point)
159
283
  hit = nil
160
284
  if @are_children_tangible
@@ -171,6 +295,9 @@ module Gosling
171
295
  hit
172
296
  end
173
297
 
298
+ ##
299
+ # Functions similarly to #get_actor_at, but returns a list of +all+ Actors for whom the point is inside their shape.
300
+ #
174
301
  def get_actors_at(point)
175
302
  actors = []
176
303
  if @are_children_tangible
@@ -186,50 +313,103 @@ module Gosling
186
313
  actors
187
314
  end
188
315
 
189
- def get_global_transform
190
- tf = if parent
191
- parent.get_global_transform * @transform.to_matrix
316
+ ##
317
+ # Returns a Snow::Mat3 transformation matrix combining this Actor's transforms as well as all of its ancestors.
318
+ # This matrix can be used to transform a point in this Actor's local space to its global equivalent (the geometric
319
+ # space of its root ancestor).
320
+ #
321
+ def get_global_transform(out = nil)
322
+ if parent
323
+ out ||= Snow::Mat3.new
324
+ @transform.to_matrix.multiply(parent.get_global_transform, out)
325
+ out
192
326
  else
193
327
  @transform.to_matrix
194
328
  end
195
- return tf
196
329
  end
197
330
 
331
+ ##
332
+ # Returns the global x/y position of this actor (where it is relative to its root ancestor). This value is calculated
333
+ # using the Actor's center (see Transform#center).
334
+ #
198
335
  def get_global_position
199
336
  tf = get_global_transform
200
- Transform.transform_point(tf, Vector[@transform.center[0], @transform.center[1], 0])
337
+ Transform.transform_point(tf, @transform.center)
201
338
  end
202
339
 
340
+ ##
341
+ # Wrapper method. Returns this Actor's alpha value (0-255).
342
+ #
203
343
  def alpha
204
344
  @color.alpha
205
345
  end
206
346
 
347
+ ##
348
+ # Wrapper method. Sets this Actor's alpha value (0-255).
349
+ #
207
350
  def alpha=(val)
208
351
  @color.alpha = val
209
352
  end
210
353
 
354
+ ##
355
+ # Wrapper method. Returns this Actor's red value (0-255).
356
+ #
211
357
  def red
212
358
  @color.red
213
359
  end
214
360
 
361
+ ##
362
+ # Wrapper method. Sets this Actor's red value (0-255).
363
+ #
215
364
  def red=(val)
216
365
  @color.red = val
217
366
  end
218
367
 
368
+ ##
369
+ # Wrapper method. Returns this Actor's green value (0-255).
370
+ #
219
371
  def green
220
372
  @color.green
221
373
  end
222
374
 
375
+ ##
376
+ # Wrapper method. Sets this Actor's green value (0-255).
377
+ #
223
378
  def green=(val)
224
379
  @color.green = val
225
380
  end
226
381
 
382
+ ##
383
+ # Wrapper method. Returns this Actor's blue value (0-255).
384
+ #
227
385
  def blue
228
386
  @color.blue
229
387
  end
230
388
 
389
+ ##
390
+ # Wrapper method. Sets this Actor's blue value (0-255).
391
+ #
231
392
  def blue=(val)
232
393
  @color.blue = val
233
394
  end
395
+
396
+ protected
397
+
398
+ def render(matrix)
399
+ end
400
+
401
+ ##
402
+ # Internal use only. See #add_child and #remove_child.
403
+ #
404
+ def parent=(parent)
405
+ return if parent == @parent
406
+ unless parent
407
+ raise Gosling::InheritanceError.new("You should use Actor.remove_child() instead of setting the parent directly.") if @parent.has_child?(self)
408
+ end
409
+ @parent = parent
410
+ if @parent
411
+ raise Gosling::InheritanceError.new("You should use Actor.add_child() instead of setting the parent directly.") unless @parent.has_child?(self)
412
+ end
413
+ end
234
414
  end
235
- end
415
+ end
@@ -2,26 +2,52 @@ require_relative 'actor.rb'
2
2
  require_relative 'collision.rb'
3
3
 
4
4
  module Gosling
5
+ ##
6
+ # Represents an Actor with a circular shape, defined by a mutable radius. The circle is rendered relative to the
7
+ # Circle's center (see Transform#center).
8
+ #
5
9
  class Circle < Actor
10
+ ##
11
+ # How many vertices to use when rendering circles. More vertices means more accurate rendering at the cost of
12
+ # performance.
13
+ #
6
14
  RENDER_VERTEX_COUNT = 16
7
15
 
8
16
  attr_reader :radius
9
17
 
18
+ ##
19
+ # Creates a new Circle with initial radius of zero.
20
+ #
10
21
  def initialize(window)
11
22
  super(window)
12
23
  @radius = 0
13
24
  end
14
25
 
26
+ ##
27
+ # Sets this circle's radius. Radius must be a positive integer.
28
+ #
15
29
  def radius=(val)
16
30
  raise ArgumentError.new("Circle.radius cannot be negative") if val < 0
17
31
  @radius = val
18
32
  end
19
33
 
34
+ ##
35
+ # Returns the angle's corresponding unit vector times this circle's radius.
36
+ #
20
37
  def get_point_at_angle(radians)
21
38
  raise ArgumentError.new("Expected Numeric, but received #{radians.inspect}!") unless radians.is_a?(Numeric)
22
- Vector[Math.cos(radians) * @radius, Math.sin(radians) * @radius, 0]
39
+ Snow::Vec3[Math.cos(radians) * @radius, Math.sin(radians) * @radius, 0]
23
40
  end
24
41
 
42
+ ##
43
+ # Returns true if the point is inside the Circle, false otherwise.
44
+ #
45
+ def is_point_in_bounds(point)
46
+ Collision.is_point_in_shape?(point, self)
47
+ end
48
+
49
+ private
50
+
25
51
  def render(matrix)
26
52
  local_vertices = (0...RENDER_VERTEX_COUNT).map do |i|
27
53
  get_point_at_angle(Math::PI * 2 * i / RENDER_VERTEX_COUNT)
@@ -40,9 +66,5 @@ module Gosling
40
66
  i += 1
41
67
  end
42
68
  end
43
-
44
- def is_point_in_bounds(point)
45
- Collision.is_point_in_shape?(point, self)
46
- end
47
69
  end
48
70
  end