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 +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
|