Class: Gosling::Actor

Inherits:
Object show all
Includes:
Transformable
Defined in:
lib/gosling/actor.rb

Overview

Actors are fundamental elements of a rendering and worldspace hierarchy. They represent the things that exist inside of the game world or parts of our application’s user interface.

A key difference between an Actor and any of its subclasses - Circle, Polygon, Sprite, and the like - is that an Actor is inherently intangible. By itself, it has no shape or appearance and takes up no space. If it’s something you can see or interact with, it should probably be an instance of one of Actor’s subclasses.

The inheritance model is what makes an Actor by itself useful. Actors can have one or more children, which can be any type of Actor. Those Actors can in turn have any number of child Actors, and so on, creating a sort of tree structure. A parent Actor’s transform is inherited by its children, so moving or rotating a parent Actor moves or rotates all of its children relative to its parent. And when a parent is drawn, all of its children are drawn as well (see #draw for exceptions).

One common application of this is to use a plain Actor as a root object to which all other elements visible in the game world are added. As the player moves through the game world, rather than move the position of each game element across the screen to simulate travel, you need only move the root Actor and all other Actors will be moved similarly. This root actor then acts like a “stage” or “camera”. For this reason, one could think of a plain Actor as sort of a “container” for other Actors, a way to keep them all organized and related.

The behavior of inheritance can modified by setting various properties. Read on for more details.

Direct Known Subclasses

Circle, Polygon

Instance Attribute Summary collapse

Attributes included from Transformable

#rotation

Instance Method Summary collapse

Methods included from Transformable

#center, #center=, #center_x, #center_x=, #center_y, #center_y=, #reset, #scale, #scale=, #scale_x, #scale_x=, #scale_y, #scale_y=, #to_matrix, transform_point, #transform_point, #translation, #translation=, untransform_point, #untransform_point, #x, #x=, #y, #y=

Constructor Details

#initialize(window) ⇒ Actor

Creates a new Actor, setting all inheritance properties to their defaults and assigning a random color. Requires a Gosu::Window to be used when rendering.



72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/gosling/actor.rb', line 72

def initialize(window)
  super()
  @window = window
  @parent = nil
  @children = []
  @is_visible = true
  @is_tangible = true
  @are_children_visible = true
  @are_children_tangible = true
  @is_mask = false
  @color = Gosu::Color.from_hsv(rand(360), rand(), rand())
end

Instance Attribute Details

#are_children_tangibleObject

If set to true, this Actor’s children will respond to “point-in-shape” tests. If false, such tests will skip them and their descendants. The default is true.



54
55
56
# File 'lib/gosling/actor.rb', line 54

def are_children_tangible
  @are_children_tangible
end

#are_children_visibleObject

If set to true, all of this Actor’s children will be drawn to screen. If false, they and their descendants will be skipped. The default is true.



48
49
50
# File 'lib/gosling/actor.rb', line 48

def are_children_visible
  @are_children_visible
end

#childrenObject (readonly)

Returns the value of attribute children.



31
32
33
# File 'lib/gosling/actor.rb', line 31

def children
  @children
end

#colorObject

The Gosu::Color to use when rendering this Actor.



66
67
68
# File 'lib/gosling/actor.rb', line 66

def color
  @color
end

#is_maskObject

If set to true, this Actor will be treated as a “mask” for its parent regarding “point-in-shape” tests. If the point is 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 false.



61
62
63
# File 'lib/gosling/actor.rb', line 61

def is_mask
  @is_mask
end

#is_tangibleObject

If set to true, this Actor will respond to “point-in-shape” tests. If false, such tests will skip this Actor. The default is true.



42
43
44
# File 'lib/gosling/actor.rb', line 42

def is_tangible
  @is_tangible
end

#is_visibleObject

If set to true, this Actor will be drawn to screen. If false, it will be skipped. The default is true.



36
37
38
# File 'lib/gosling/actor.rb', line 36

def is_visible
  @is_visible
end

#parentObject

Returns the value of attribute parent.



31
32
33
# File 'lib/gosling/actor.rb', line 31

def parent
  @parent
end

#windowObject (readonly)

Returns the value of attribute window.



31
32
33
# File 'lib/gosling/actor.rb', line 31

def window
  @window
end

Instance Method Details

#add_child(child) ⇒ Object

Establishes a parent/child relationship between this actor and the one passed, respectively. The child Actor will appear relative to its parent, move as the parent moves, and draw when the parent draws.

An Actor cannot be made a child of itself. Similarly, a child cannot be added to a parent if doing so would create a circular reference (e.g. a.add_child(b) followed by b.add_child(a)).

If the child Actor already had a parent, the Actor is disassociated from its former parent before becoming associated with this one. An Actor can have only one parent at a time.



99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/gosling/actor.rb', line 99

def add_child(child)
  return if @children.include?(child)
  raise Gosling::InheritanceError.new("An Actor cannot be made a child of itself.") if child == self
  ancestor = parent
  until ancestor.nil?
    raise Gosling::InheritanceError.new("Adding a child's ancestor as a child would create a circular reference.") if child == ancestor
    ancestor = ancestor.parent
  end

  child.parent.remove_child(child) if child.parent
  @children.push(child)
  child.parent = self
end

#alphaObject

Wrapper method. Returns this Actor’s alpha value (0-255).



243
244
245
# File 'lib/gosling/actor.rb', line 243

def alpha
  @color.alpha
end

#alpha=(val) ⇒ Object

Wrapper method. Sets this Actor’s alpha value (0-255).



250
251
252
# File 'lib/gosling/actor.rb', line 250

def alpha=(val)
  @color.alpha = val
end

#blueObject

Wrapper method. Returns this Actor’s blue value (0-255).



285
286
287
# File 'lib/gosling/actor.rb', line 285

def blue
  @color.blue
end

#blue=(val) ⇒ Object

Wrapper method. Sets this Actor’s blue value (0-255).



292
293
294
# File 'lib/gosling/actor.rb', line 292

def blue=(val)
  @color.blue = val
end

#draw(matrix = nil) ⇒ Object

Calls #render on this Actor, drawing it to the screen if #is_visible is set to true (the default).

The Actor’s transforms, if any, will be applied prior to rendering. If an optional Snow::Mat3 matrix transform is given, the Actor will be transformed by a combination of that matrix transform and its own.

If the #are_children_visible flag is set to true (the default), then this method will recursively call draw on each of the Actor’s children, passing them the combined matrix used to render the parent. Otherwise, children will be skipped and not drawn.



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/gosling/actor.rb', line 141

def draw(matrix = nil)
  transform = MatrixCache.instance.get
  if matrix
    to_matrix.multiply(matrix, transform)
  else
    transform.set(to_matrix)
  end

  render(transform) if @is_visible
  if @are_children_visible
    @children.each { |child| child.draw(transform) }
  end
ensure
  MatrixCache.instance.recycle(transform)
end

#get_actor_at(point) ⇒ Object

Given a point in global space, tests this Actor and each of its children, returning the first Actor for whom this point is inside its shape. Respects each Actor’s transforms as well as any it may inherit from its ancestors. Useful for determining which Actor the user may have clicked on.

If the #is_tangible flag is set to false, this Actor will not be tested. The default is true.

If the #are_children_tangible flag is set to false, this Actor’s children will not be tested. The default is true.

If the #is_mask flag is set to true, a positive test from this Actor instead returns its parent Actor, if any. The default is false.

If the point is not inside this Actor or any of its children (excluding any skipped Actors), nil is returned.



179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/gosling/actor.rb', line 179

def get_actor_at(point)
  hit = nil
  if @are_children_tangible
    @children.reverse_each do |child|
      hit = child.get_actor_at(point)
      if hit
        break if @is_mask
        return hit
      end
    end
  end
  hit = self if hit == nil && @is_tangible && is_point_in_bounds(point)
  hit = @parent if @is_mask && hit == self
  hit
end

#get_actors_at(point) ⇒ Object

Functions similarly to #get_actor_at, but returns a list of all Actors for whom the point is inside their shape.



198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/gosling/actor.rb', line 198

def get_actors_at(point)
  actors = []
  if @are_children_tangible
    @children.reverse_each do |child|
      actors |= child.get_actors_at(point)
    end
  end
  actors.push(self) if @is_tangible && is_point_in_bounds(point)
  actors.uniq!
  if @is_mask
    actors.map! { |actor| (actor == self) ? @parent : actor }
  end
  actors
end

#get_global_position(out = nil) ⇒ Object

Returns the global x/y position of this actor (where it is relative to its root ancestor). This value is calculated using the Actor’s center (see Transformable#center).



231
232
233
234
235
236
237
238
# File 'lib/gosling/actor.rb', line 231

def get_global_position(out = nil)
  tf = MatrixCache.instance.get
  get_global_transform(tf)
  out ||= Snow::Vec3.new
  Transformable.transform_point(tf, center, out)
ensure
  MatrixCache.instance.recycle(tf)
end

#get_global_transform(out = nil) ⇒ Object

Returns a Snow::Mat3 transformation matrix combining this Actor’s transforms as well as all of its ancestors. This matrix can be used to transform a point in this Actor’s local space to its global equivalent (the geometric space of its root ancestor).



218
219
220
221
222
223
224
225
# File 'lib/gosling/actor.rb', line 218

def get_global_transform(out = nil)
  out ||= Snow::Mat3.new
  if parent
    to_matrix.multiply(parent.get_global_transform, out)
  else
    out.set(to_matrix)
  end
end

#greenObject

Wrapper method. Returns this Actor’s green value (0-255).



271
272
273
# File 'lib/gosling/actor.rb', line 271

def green
  @color.green
end

#green=(val) ⇒ Object

Wrapper method. Sets this Actor’s green value (0-255).



278
279
280
# File 'lib/gosling/actor.rb', line 278

def green=(val)
  @color.green = val
end

#has_child?(child) ⇒ Boolean

Returns true if this Actor has the given Actor as a child.

Returns:

  • (Boolean)


127
128
129
# File 'lib/gosling/actor.rb', line 127

def has_child?(child)
  @children.include?(child)
end

#inspectObject



85
86
87
# File 'lib/gosling/actor.rb', line 85

def inspect
  "#<#{self.class}:#{self.object_id}>"
end

#is_point_in_bounds(point) ⇒ Object

Returns false. Actors have no shape, and so no point is in their bounds. Subclasses override this method with shape-specific behavior.



161
162
163
# File 'lib/gosling/actor.rb', line 161

def is_point_in_bounds(point)
  false
end

#redObject

Wrapper method. Returns this Actor’s red value (0-255).



257
258
259
# File 'lib/gosling/actor.rb', line 257

def red
  @color.red
end

#red=(val) ⇒ Object

Wrapper method. Sets this Actor’s red value (0-255).



264
265
266
# File 'lib/gosling/actor.rb', line 264

def red=(val)
  @color.red = val
end

#remove_child(child) ⇒ Object

If the given Actor is a child of this Actor, it is disassociated from this Actor. In any case, the child Actor is immediately orphaned.



117
118
119
120
121
122
# File 'lib/gosling/actor.rb', line 117

def remove_child(child)
  return unless @children.include?(child)

  @children.delete(child)
  child.parent = nil
end