gosling 2.3.0 → 2.3.2
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 +5 -5
- data/lib/gosling.rb +4 -4
- data/lib/gosling/actor.rb +328 -328
- data/lib/gosling/circle.rb +65 -65
- data/lib/gosling/collision.rb +499 -499
- data/lib/gosling/image_library.rb +24 -24
- data/lib/gosling/inheritance_error.rb +4 -4
- data/lib/gosling/matrix_cache.rb +23 -21
- data/lib/gosling/object_cache.rb +48 -48
- data/lib/gosling/patches.rb +42 -42
- data/lib/gosling/polygon.rb +122 -122
- data/lib/gosling/rect.rb +41 -41
- data/lib/gosling/sprite.rb +50 -50
- data/lib/gosling/transformable.rb +413 -413
- data/lib/gosling/utils.rb +20 -20
- data/lib/gosling/vector_cache.rb +21 -21
- data/lib/gosling/version.rb +7 -7
- data/spec/actor_spec.rb +627 -627
- data/spec/circle_spec.rb +46 -46
- data/spec/collision_spec.rb +1755 -1755
- data/spec/image_library_spec.rb +19 -19
- data/spec/matrix_cache_spec.rb +25 -25
- data/spec/object_cache_spec.rb +22 -22
- data/spec/polygon_spec.rb +284 -284
- data/spec/rect_spec.rb +86 -86
- data/spec/spec_helper.rb +3 -3
- data/spec/sprite_spec.rb +45 -45
- data/spec/transformable_spec.rb +479 -479
- data/spec/vector_cache_spec.rb +80 -80
- metadata +3 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ac651ebce37fb5da3aacc1ced63789b6d9651c5ce8c0c112e9380e6d1ecdafd3
|
4
|
+
data.tar.gz: f3dada919c44fe16a49811bbb8e823257713e6042b858727737220f5d59f647e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d31bf801d211beef278199b322efeda3286cebb3951cc1f23f64e063b0b87367f82bd345d1fe6bb4aaca5415afc4b315eb39d89b706261cd8cf49a42c7032283
|
7
|
+
data.tar.gz: fe40452705018052c180a3c9dd1f0b2a961347d83361ee83c0fa9c8c173043b747c632f89d12f152b10e97b28c5e155ef87ac832685477c39bc823ffe1eb7abc
|
data/lib/gosling.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Dir.glob(File.join(File.dirname(__FILE__), 'gosling/*.rb')).each { |file| require_relative file }
|
2
|
-
|
3
|
-
module Gosling
|
4
|
-
end
|
1
|
+
Dir.glob(File.join(File.dirname(__FILE__), 'gosling/*.rb')).each { |file| require_relative file }
|
2
|
+
|
3
|
+
module Gosling
|
4
|
+
end
|
data/lib/gosling/actor.rb
CHANGED
@@ -1,328 +1,328 @@
|
|
1
|
-
require_relative 'transformable.rb'
|
2
|
-
|
3
|
-
require 'gosu'
|
4
|
-
|
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
|
-
#
|
28
|
-
class Actor
|
29
|
-
include Transformable
|
30
|
-
|
31
|
-
attr_reader :parent, :children, :window
|
32
|
-
|
33
|
-
##
|
34
|
-
# If set to true, this Actor will be drawn to screen. If false, it will be skipped. The default is true.
|
35
|
-
#
|
36
|
-
attr_accessor :is_visible
|
37
|
-
|
38
|
-
##
|
39
|
-
# If set to true, this Actor will respond to "point-in-shape" tests. If false, such tests will skip this Actor. The default
|
40
|
-
# is true.
|
41
|
-
#
|
42
|
-
attr_accessor :is_tangible
|
43
|
-
|
44
|
-
##
|
45
|
-
# If set to true, all of this Actor's children will be drawn to screen. If false, they and their descendants will be
|
46
|
-
# skipped. The default is true.
|
47
|
-
#
|
48
|
-
attr_accessor :are_children_visible
|
49
|
-
|
50
|
-
##
|
51
|
-
# If set to true, this Actor's children will respond to "point-in-shape" tests. If false, such tests will skip them and
|
52
|
-
# their descendants. The default is true.
|
53
|
-
#
|
54
|
-
attr_accessor :are_children_tangible
|
55
|
-
|
56
|
-
##
|
57
|
-
# If set to true, this Actor will be treated as a "mask" for its parent regarding "point-in-shape" tests. If the point is
|
58
|
-
# 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
|
59
|
-
# false.
|
60
|
-
#
|
61
|
-
attr_accessor :is_mask
|
62
|
-
|
63
|
-
##
|
64
|
-
# The Gosu::Color to use when rendering this Actor.
|
65
|
-
#
|
66
|
-
attr_accessor :color
|
67
|
-
|
68
|
-
##
|
69
|
-
# Creates a new Actor, setting all inheritance properties to their defaults and assigning a random color. Requires
|
70
|
-
# a Gosu::Window to be used when rendering.
|
71
|
-
#
|
72
|
-
def initialize(window)
|
73
|
-
super()
|
74
|
-
@window = window
|
75
|
-
@parent = nil
|
76
|
-
@children = []
|
77
|
-
@is_visible = true
|
78
|
-
@is_tangible = true
|
79
|
-
@are_children_visible = true
|
80
|
-
@are_children_tangible = true
|
81
|
-
@is_mask = false
|
82
|
-
@color = Gosu::Color.from_hsv(rand(360), rand(), rand())
|
83
|
-
end
|
84
|
-
|
85
|
-
def inspect
|
86
|
-
"#<#{self.class}:#{self.object_id}>"
|
87
|
-
end
|
88
|
-
|
89
|
-
##
|
90
|
-
# Establishes a parent/child relationship between this actor and the one passed, respectively. The child Actor will
|
91
|
-
# appear relative to its parent, move as the parent moves, and draw when the parent draws.
|
92
|
-
#
|
93
|
-
# An Actor cannot be made a child of itself. Similarly, a child cannot be added to a parent if doing so would create
|
94
|
-
# a circular reference (e.g. a.add_child(b) followed by b.add_child(a)).
|
95
|
-
#
|
96
|
-
# If the child Actor already had a parent, the Actor is disassociated from its former parent before becoming
|
97
|
-
# associated with this one. An Actor can have only one parent at a time.
|
98
|
-
#
|
99
|
-
def add_child(child)
|
100
|
-
return if @children.include?(child)
|
101
|
-
raise Gosling::InheritanceError.new("An Actor cannot be made a child of itself.") if child == self
|
102
|
-
ancestor = parent
|
103
|
-
until ancestor.nil?
|
104
|
-
raise Gosling::InheritanceError.new("Adding a child's ancestor as a child would create a circular reference.") if child == ancestor
|
105
|
-
ancestor = ancestor.parent
|
106
|
-
end
|
107
|
-
|
108
|
-
child.parent.remove_child(child) if child.parent
|
109
|
-
@children.push(child)
|
110
|
-
child.parent = self
|
111
|
-
end
|
112
|
-
|
113
|
-
##
|
114
|
-
# If the given Actor is a child of this Actor, it is disassociated from this Actor. In any case, the child Actor is
|
115
|
-
# immediately orphaned.
|
116
|
-
#
|
117
|
-
def remove_child(child)
|
118
|
-
return unless @children.include?(child)
|
119
|
-
|
120
|
-
@children.delete(child)
|
121
|
-
child.parent = nil
|
122
|
-
end
|
123
|
-
|
124
|
-
##
|
125
|
-
# Returns true if this Actor has the given Actor as a child.
|
126
|
-
#
|
127
|
-
def has_child?(child)
|
128
|
-
@children.include?(child)
|
129
|
-
end
|
130
|
-
|
131
|
-
##
|
132
|
-
# Calls #render on this Actor, drawing it to the screen if #is_visible is set to true (the default).
|
133
|
-
#
|
134
|
-
# The Actor's transforms, if any, will be applied prior to rendering. If an optional Snow::Mat3 matrix transform is
|
135
|
-
# given, the Actor will be transformed by a combination of that matrix transform and its own.
|
136
|
-
#
|
137
|
-
# If the #are_children_visible flag is set to true (the default), then this method will recursively call draw on each
|
138
|
-
# of the Actor's children, passing them the combined matrix used to render the parent. Otherwise, children will
|
139
|
-
# be skipped and not drawn.
|
140
|
-
#
|
141
|
-
def draw(matrix = nil)
|
142
|
-
transform = MatrixCache.instance.get
|
143
|
-
if matrix
|
144
|
-
to_matrix.multiply(matrix, transform)
|
145
|
-
else
|
146
|
-
transform.set(to_matrix)
|
147
|
-
end
|
148
|
-
|
149
|
-
render(transform) if @is_visible
|
150
|
-
if @are_children_visible
|
151
|
-
@children.each { |child| child.draw(transform) }
|
152
|
-
end
|
153
|
-
ensure
|
154
|
-
MatrixCache.instance.recycle(transform)
|
155
|
-
end
|
156
|
-
|
157
|
-
##
|
158
|
-
# Returns false. Actors have no shape, and so no point is in their bounds. Subclasses override this method with
|
159
|
-
# shape-specific behavior.
|
160
|
-
#
|
161
|
-
def is_point_in_bounds(point)
|
162
|
-
false
|
163
|
-
end
|
164
|
-
|
165
|
-
##
|
166
|
-
# Given a point in global space, tests this Actor and each of its children, returning the first Actor for whom this
|
167
|
-
# point is inside its shape. Respects each Actor's transforms as well as any it may inherit from its ancestors.
|
168
|
-
# Useful for determining which Actor the user may have clicked on.
|
169
|
-
#
|
170
|
-
# If the #is_tangible flag is set to false, this Actor will not be tested. The default is true.
|
171
|
-
#
|
172
|
-
# If the #are_children_tangible flag is set to false, this Actor's children will not be tested. The default is true.
|
173
|
-
#
|
174
|
-
# If the #is_mask flag is set to true, a positive test from this Actor instead returns its parent Actor, if any. The
|
175
|
-
# default is false.
|
176
|
-
#
|
177
|
-
# If the point is not inside this Actor or any of its children (excluding any skipped Actors), nil is returned.
|
178
|
-
#
|
179
|
-
def get_actor_at(point)
|
180
|
-
hit = nil
|
181
|
-
if @are_children_tangible
|
182
|
-
@children.reverse_each do |child|
|
183
|
-
hit = child.get_actor_at(point)
|
184
|
-
if hit
|
185
|
-
break if @is_mask
|
186
|
-
return hit
|
187
|
-
end
|
188
|
-
end
|
189
|
-
end
|
190
|
-
hit = self if hit == nil && @is_tangible && is_point_in_bounds(point)
|
191
|
-
hit = @parent if @is_mask && hit == self
|
192
|
-
hit
|
193
|
-
end
|
194
|
-
|
195
|
-
##
|
196
|
-
# Functions similarly to #get_actor_at, but returns a list of +all+ Actors for whom the point is inside their shape.
|
197
|
-
#
|
198
|
-
def get_actors_at(point)
|
199
|
-
actors = []
|
200
|
-
if @are_children_tangible
|
201
|
-
@children.reverse_each do |child|
|
202
|
-
actors |= child.get_actors_at(point)
|
203
|
-
end
|
204
|
-
end
|
205
|
-
actors.push(self) if @is_tangible && is_point_in_bounds(point)
|
206
|
-
actors.uniq!
|
207
|
-
if @is_mask
|
208
|
-
actors.map! { |actor| (actor == self) ? @parent : actor }
|
209
|
-
end
|
210
|
-
actors
|
211
|
-
end
|
212
|
-
|
213
|
-
##
|
214
|
-
# Returns a Snow::Mat3 transformation matrix combining this Actor's transforms as well as all of its ancestors.
|
215
|
-
# This matrix can be used to transform a point in this Actor's local space to its global equivalent (the geometric
|
216
|
-
# space of its root ancestor).
|
217
|
-
#
|
218
|
-
def get_global_transform(out = nil)
|
219
|
-
out ||= Snow::Mat3.new
|
220
|
-
if parent
|
221
|
-
to_matrix.multiply(parent.get_global_transform, out)
|
222
|
-
else
|
223
|
-
out.set(to_matrix)
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
##
|
228
|
-
# Returns the global x/y position of this actor (where it is relative to its root ancestor). This value is calculated
|
229
|
-
# using the Actor's center (see Transformable#center).
|
230
|
-
#
|
231
|
-
def get_global_position(out = nil)
|
232
|
-
tf = MatrixCache.instance.get
|
233
|
-
get_global_transform(tf)
|
234
|
-
out ||= Snow::Vec3.new
|
235
|
-
Transformable.transform_point(tf, center, out)
|
236
|
-
ensure
|
237
|
-
MatrixCache.instance.recycle(tf)
|
238
|
-
end
|
239
|
-
|
240
|
-
##
|
241
|
-
# Wrapper method. Returns this Actor's alpha value (0-255).
|
242
|
-
#
|
243
|
-
def alpha
|
244
|
-
@color.alpha
|
245
|
-
end
|
246
|
-
|
247
|
-
##
|
248
|
-
# Wrapper method. Sets this Actor's alpha value (0-255).
|
249
|
-
#
|
250
|
-
def alpha=(val)
|
251
|
-
@color.alpha = val
|
252
|
-
end
|
253
|
-
|
254
|
-
##
|
255
|
-
# Wrapper method. Returns this Actor's red value (0-255).
|
256
|
-
#
|
257
|
-
def red
|
258
|
-
@color.red
|
259
|
-
end
|
260
|
-
|
261
|
-
##
|
262
|
-
# Wrapper method. Sets this Actor's red value (0-255).
|
263
|
-
#
|
264
|
-
def red=(val)
|
265
|
-
@color.red = val
|
266
|
-
end
|
267
|
-
|
268
|
-
##
|
269
|
-
# Wrapper method. Returns this Actor's green value (0-255).
|
270
|
-
#
|
271
|
-
def green
|
272
|
-
@color.green
|
273
|
-
end
|
274
|
-
|
275
|
-
##
|
276
|
-
# Wrapper method. Sets this Actor's green value (0-255).
|
277
|
-
#
|
278
|
-
def green=(val)
|
279
|
-
@color.green = val
|
280
|
-
end
|
281
|
-
|
282
|
-
##
|
283
|
-
# Wrapper method. Returns this Actor's blue value (0-255).
|
284
|
-
#
|
285
|
-
def blue
|
286
|
-
@color.blue
|
287
|
-
end
|
288
|
-
|
289
|
-
##
|
290
|
-
# Wrapper method. Sets this Actor's blue value (0-255).
|
291
|
-
#
|
292
|
-
def blue=(val)
|
293
|
-
@color.blue = val
|
294
|
-
end
|
295
|
-
|
296
|
-
protected
|
297
|
-
|
298
|
-
def render(matrix)
|
299
|
-
end
|
300
|
-
|
301
|
-
def fill_polygon(vertices)
|
302
|
-
(2...vertices.length).each do |i|
|
303
|
-
v0 = vertices[0]
|
304
|
-
v1 = vertices[i - 1]
|
305
|
-
v2 = vertices[i]
|
306
|
-
@window.draw_triangle(
|
307
|
-
v0[0].to_f, v0[1].to_f, @color,
|
308
|
-
v1[0].to_f, v1[1].to_f, @color,
|
309
|
-
v2[0].to_f, v2[1].to_f, @color,
|
310
|
-
)
|
311
|
-
end
|
312
|
-
end
|
313
|
-
|
314
|
-
##
|
315
|
-
# Internal use only. See #add_child and #remove_child.
|
316
|
-
#
|
317
|
-
def parent=(parent)
|
318
|
-
return if parent == @parent
|
319
|
-
unless parent
|
320
|
-
raise Gosling::InheritanceError.new("You should use Actor.remove_child() instead of setting the parent directly.") if @parent.has_child?(self)
|
321
|
-
end
|
322
|
-
@parent = parent
|
323
|
-
if @parent
|
324
|
-
raise Gosling::InheritanceError.new("You should use Actor.add_child() instead of setting the parent directly.") unless @parent.has_child?(self)
|
325
|
-
end
|
326
|
-
end
|
327
|
-
end
|
328
|
-
end
|
1
|
+
require_relative 'transformable.rb'
|
2
|
+
|
3
|
+
require 'gosu'
|
4
|
+
|
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
|
+
#
|
28
|
+
class Actor
|
29
|
+
include Transformable
|
30
|
+
|
31
|
+
attr_reader :parent, :children, :window
|
32
|
+
|
33
|
+
##
|
34
|
+
# If set to true, this Actor will be drawn to screen. If false, it will be skipped. The default is true.
|
35
|
+
#
|
36
|
+
attr_accessor :is_visible
|
37
|
+
|
38
|
+
##
|
39
|
+
# If set to true, this Actor will respond to "point-in-shape" tests. If false, such tests will skip this Actor. The default
|
40
|
+
# is true.
|
41
|
+
#
|
42
|
+
attr_accessor :is_tangible
|
43
|
+
|
44
|
+
##
|
45
|
+
# If set to true, all of this Actor's children will be drawn to screen. If false, they and their descendants will be
|
46
|
+
# skipped. The default is true.
|
47
|
+
#
|
48
|
+
attr_accessor :are_children_visible
|
49
|
+
|
50
|
+
##
|
51
|
+
# If set to true, this Actor's children will respond to "point-in-shape" tests. If false, such tests will skip them and
|
52
|
+
# their descendants. The default is true.
|
53
|
+
#
|
54
|
+
attr_accessor :are_children_tangible
|
55
|
+
|
56
|
+
##
|
57
|
+
# If set to true, this Actor will be treated as a "mask" for its parent regarding "point-in-shape" tests. If the point is
|
58
|
+
# 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
|
59
|
+
# false.
|
60
|
+
#
|
61
|
+
attr_accessor :is_mask
|
62
|
+
|
63
|
+
##
|
64
|
+
# The Gosu::Color to use when rendering this Actor.
|
65
|
+
#
|
66
|
+
attr_accessor :color
|
67
|
+
|
68
|
+
##
|
69
|
+
# Creates a new Actor, setting all inheritance properties to their defaults and assigning a random color. Requires
|
70
|
+
# a Gosu::Window to be used when rendering.
|
71
|
+
#
|
72
|
+
def initialize(window)
|
73
|
+
super()
|
74
|
+
@window = window
|
75
|
+
@parent = nil
|
76
|
+
@children = []
|
77
|
+
@is_visible = true
|
78
|
+
@is_tangible = true
|
79
|
+
@are_children_visible = true
|
80
|
+
@are_children_tangible = true
|
81
|
+
@is_mask = false
|
82
|
+
@color = Gosu::Color.from_hsv(rand(360), rand(), rand())
|
83
|
+
end
|
84
|
+
|
85
|
+
def inspect
|
86
|
+
"#<#{self.class}:#{self.object_id}>"
|
87
|
+
end
|
88
|
+
|
89
|
+
##
|
90
|
+
# Establishes a parent/child relationship between this actor and the one passed, respectively. The child Actor will
|
91
|
+
# appear relative to its parent, move as the parent moves, and draw when the parent draws.
|
92
|
+
#
|
93
|
+
# An Actor cannot be made a child of itself. Similarly, a child cannot be added to a parent if doing so would create
|
94
|
+
# a circular reference (e.g. a.add_child(b) followed by b.add_child(a)).
|
95
|
+
#
|
96
|
+
# If the child Actor already had a parent, the Actor is disassociated from its former parent before becoming
|
97
|
+
# associated with this one. An Actor can have only one parent at a time.
|
98
|
+
#
|
99
|
+
def add_child(child)
|
100
|
+
return if @children.include?(child)
|
101
|
+
raise Gosling::InheritanceError.new("An Actor cannot be made a child of itself.") if child == self
|
102
|
+
ancestor = parent
|
103
|
+
until ancestor.nil?
|
104
|
+
raise Gosling::InheritanceError.new("Adding a child's ancestor as a child would create a circular reference.") if child == ancestor
|
105
|
+
ancestor = ancestor.parent
|
106
|
+
end
|
107
|
+
|
108
|
+
child.parent.remove_child(child) if child.parent
|
109
|
+
@children.push(child)
|
110
|
+
child.parent = self
|
111
|
+
end
|
112
|
+
|
113
|
+
##
|
114
|
+
# If the given Actor is a child of this Actor, it is disassociated from this Actor. In any case, the child Actor is
|
115
|
+
# immediately orphaned.
|
116
|
+
#
|
117
|
+
def remove_child(child)
|
118
|
+
return unless @children.include?(child)
|
119
|
+
|
120
|
+
@children.delete(child)
|
121
|
+
child.parent = nil
|
122
|
+
end
|
123
|
+
|
124
|
+
##
|
125
|
+
# Returns true if this Actor has the given Actor as a child.
|
126
|
+
#
|
127
|
+
def has_child?(child)
|
128
|
+
@children.include?(child)
|
129
|
+
end
|
130
|
+
|
131
|
+
##
|
132
|
+
# Calls #render on this Actor, drawing it to the screen if #is_visible is set to true (the default).
|
133
|
+
#
|
134
|
+
# The Actor's transforms, if any, will be applied prior to rendering. If an optional Snow::Mat3 matrix transform is
|
135
|
+
# given, the Actor will be transformed by a combination of that matrix transform and its own.
|
136
|
+
#
|
137
|
+
# If the #are_children_visible flag is set to true (the default), then this method will recursively call draw on each
|
138
|
+
# of the Actor's children, passing them the combined matrix used to render the parent. Otherwise, children will
|
139
|
+
# be skipped and not drawn.
|
140
|
+
#
|
141
|
+
def draw(matrix = nil)
|
142
|
+
transform = MatrixCache.instance.get
|
143
|
+
if matrix
|
144
|
+
to_matrix.multiply(matrix, transform)
|
145
|
+
else
|
146
|
+
transform.set(to_matrix)
|
147
|
+
end
|
148
|
+
|
149
|
+
render(transform) if @is_visible
|
150
|
+
if @are_children_visible
|
151
|
+
@children.each { |child| child.draw(transform) }
|
152
|
+
end
|
153
|
+
ensure
|
154
|
+
MatrixCache.instance.recycle(transform)
|
155
|
+
end
|
156
|
+
|
157
|
+
##
|
158
|
+
# Returns false. Actors have no shape, and so no point is in their bounds. Subclasses override this method with
|
159
|
+
# shape-specific behavior.
|
160
|
+
#
|
161
|
+
def is_point_in_bounds(point)
|
162
|
+
false
|
163
|
+
end
|
164
|
+
|
165
|
+
##
|
166
|
+
# Given a point in global space, tests this Actor and each of its children, returning the first Actor for whom this
|
167
|
+
# point is inside its shape. Respects each Actor's transforms as well as any it may inherit from its ancestors.
|
168
|
+
# Useful for determining which Actor the user may have clicked on.
|
169
|
+
#
|
170
|
+
# If the #is_tangible flag is set to false, this Actor will not be tested. The default is true.
|
171
|
+
#
|
172
|
+
# If the #are_children_tangible flag is set to false, this Actor's children will not be tested. The default is true.
|
173
|
+
#
|
174
|
+
# If the #is_mask flag is set to true, a positive test from this Actor instead returns its parent Actor, if any. The
|
175
|
+
# default is false.
|
176
|
+
#
|
177
|
+
# If the point is not inside this Actor or any of its children (excluding any skipped Actors), nil is returned.
|
178
|
+
#
|
179
|
+
def get_actor_at(point)
|
180
|
+
hit = nil
|
181
|
+
if @are_children_tangible
|
182
|
+
@children.reverse_each do |child|
|
183
|
+
hit = child.get_actor_at(point)
|
184
|
+
if hit
|
185
|
+
break if @is_mask
|
186
|
+
return hit
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
hit = self if hit == nil && @is_tangible && is_point_in_bounds(point)
|
191
|
+
hit = @parent if @is_mask && hit == self
|
192
|
+
hit
|
193
|
+
end
|
194
|
+
|
195
|
+
##
|
196
|
+
# Functions similarly to #get_actor_at, but returns a list of +all+ Actors for whom the point is inside their shape.
|
197
|
+
#
|
198
|
+
def get_actors_at(point)
|
199
|
+
actors = []
|
200
|
+
if @are_children_tangible
|
201
|
+
@children.reverse_each do |child|
|
202
|
+
actors |= child.get_actors_at(point)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
actors.push(self) if @is_tangible && is_point_in_bounds(point)
|
206
|
+
actors.uniq!
|
207
|
+
if @is_mask
|
208
|
+
actors.map! { |actor| (actor == self) ? @parent : actor }
|
209
|
+
end
|
210
|
+
actors
|
211
|
+
end
|
212
|
+
|
213
|
+
##
|
214
|
+
# Returns a Snow::Mat3 transformation matrix combining this Actor's transforms as well as all of its ancestors.
|
215
|
+
# This matrix can be used to transform a point in this Actor's local space to its global equivalent (the geometric
|
216
|
+
# space of its root ancestor).
|
217
|
+
#
|
218
|
+
def get_global_transform(out = nil)
|
219
|
+
out ||= Snow::Mat3.new
|
220
|
+
if parent
|
221
|
+
to_matrix.multiply(parent.get_global_transform, out)
|
222
|
+
else
|
223
|
+
out.set(to_matrix)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
##
|
228
|
+
# Returns the global x/y position of this actor (where it is relative to its root ancestor). This value is calculated
|
229
|
+
# using the Actor's center (see Transformable#center).
|
230
|
+
#
|
231
|
+
def get_global_position(out = nil)
|
232
|
+
tf = MatrixCache.instance.get
|
233
|
+
get_global_transform(tf)
|
234
|
+
out ||= Snow::Vec3.new
|
235
|
+
Transformable.transform_point(tf, center, out)
|
236
|
+
ensure
|
237
|
+
MatrixCache.instance.recycle(tf)
|
238
|
+
end
|
239
|
+
|
240
|
+
##
|
241
|
+
# Wrapper method. Returns this Actor's alpha value (0-255).
|
242
|
+
#
|
243
|
+
def alpha
|
244
|
+
@color.alpha
|
245
|
+
end
|
246
|
+
|
247
|
+
##
|
248
|
+
# Wrapper method. Sets this Actor's alpha value (0-255).
|
249
|
+
#
|
250
|
+
def alpha=(val)
|
251
|
+
@color.alpha = val
|
252
|
+
end
|
253
|
+
|
254
|
+
##
|
255
|
+
# Wrapper method. Returns this Actor's red value (0-255).
|
256
|
+
#
|
257
|
+
def red
|
258
|
+
@color.red
|
259
|
+
end
|
260
|
+
|
261
|
+
##
|
262
|
+
# Wrapper method. Sets this Actor's red value (0-255).
|
263
|
+
#
|
264
|
+
def red=(val)
|
265
|
+
@color.red = val
|
266
|
+
end
|
267
|
+
|
268
|
+
##
|
269
|
+
# Wrapper method. Returns this Actor's green value (0-255).
|
270
|
+
#
|
271
|
+
def green
|
272
|
+
@color.green
|
273
|
+
end
|
274
|
+
|
275
|
+
##
|
276
|
+
# Wrapper method. Sets this Actor's green value (0-255).
|
277
|
+
#
|
278
|
+
def green=(val)
|
279
|
+
@color.green = val
|
280
|
+
end
|
281
|
+
|
282
|
+
##
|
283
|
+
# Wrapper method. Returns this Actor's blue value (0-255).
|
284
|
+
#
|
285
|
+
def blue
|
286
|
+
@color.blue
|
287
|
+
end
|
288
|
+
|
289
|
+
##
|
290
|
+
# Wrapper method. Sets this Actor's blue value (0-255).
|
291
|
+
#
|
292
|
+
def blue=(val)
|
293
|
+
@color.blue = val
|
294
|
+
end
|
295
|
+
|
296
|
+
protected
|
297
|
+
|
298
|
+
def render(matrix)
|
299
|
+
end
|
300
|
+
|
301
|
+
def fill_polygon(vertices)
|
302
|
+
(2...vertices.length).each do |i|
|
303
|
+
v0 = vertices[0]
|
304
|
+
v1 = vertices[i - 1]
|
305
|
+
v2 = vertices[i]
|
306
|
+
@window.draw_triangle(
|
307
|
+
v0[0].to_f, v0[1].to_f, @color,
|
308
|
+
v1[0].to_f, v1[1].to_f, @color,
|
309
|
+
v2[0].to_f, v2[1].to_f, @color,
|
310
|
+
)
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
##
|
315
|
+
# Internal use only. See #add_child and #remove_child.
|
316
|
+
#
|
317
|
+
def parent=(parent)
|
318
|
+
return if parent == @parent
|
319
|
+
unless parent
|
320
|
+
raise Gosling::InheritanceError.new("You should use Actor.remove_child() instead of setting the parent directly.") if @parent.has_child?(self)
|
321
|
+
end
|
322
|
+
@parent = parent
|
323
|
+
if @parent
|
324
|
+
raise Gosling::InheritanceError.new("You should use Actor.add_child() instead of setting the parent directly.") unless @parent.has_child?(self)
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|