gosling 1.0.0 → 2.0.0
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.
- checksums.yaml +4 -4
- data/lib/gosling/actor.rb +234 -54
- data/lib/gosling/circle.rb +27 -5
- data/lib/gosling/collision.rb +55 -20
- data/lib/gosling/image_library.rb +7 -0
- data/lib/gosling/patches.rb +42 -0
- data/lib/gosling/polygon.rb +39 -11
- data/lib/gosling/rect.rb +13 -4
- data/lib/gosling/sprite.rb +14 -0
- data/lib/gosling/transform.rb +264 -163
- data/lib/gosling/utils.rb +20 -0
- data/lib/gosling/version.rb +5 -1
- data/spec/actor_spec.rb +47 -44
- data/spec/circle_spec.rb +2 -3
- data/spec/collision_spec.rb +207 -206
- data/spec/polygon_spec.rb +36 -36
- data/spec/rect_spec.rb +12 -12
- data/spec/transform_spec.rb +138 -149
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ea892a020a95cbff0d56b2410eed22dcdffa0816
|
4
|
+
data.tar.gz: 9ad565fa00e58440ad245ec0ceae7479ab6c3900
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
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
|
-
|
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
|
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
|
-
|
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
|
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
|
-
|
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.
|
140
|
-
end
|
141
|
-
|
142
|
-
|
143
|
-
|
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 ||=
|
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
|
-
|
190
|
-
|
191
|
-
|
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,
|
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
|
data/lib/gosling/circle.rb
CHANGED
@@ -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
|
-
|
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
|