Class: Zif::CompoundSprite

Inherits:
Sprite
  • Object
show all
Defined in:
lib/zif/compound_sprite.rb

Overview

A CompoundSprite is a collection of sprites which can be positioned as a group, and are drawn using #draw_override

This class acts like a (inherits from) spriteSprite but can itself accept a list of #sprites and #labels, like $gtk.args.outputs. Sprites and labels added to these arrays will be drawn using the #draw_override method, which is checked by DragonRuby GTK during the draw cycle.

You can use CompoundSprite to draw several sprites which need to move together or relative to each other. You can move the entire collection by changing the CompoundSprite‘s x and y values, and you can move the component sprites relative to each other individually. This is because this object itself is not drawn directly, per se (+@path+ is ignored), but has x, y, w, h, source_x, source_y, source_w, source_h values which act as modifiers to the contents of #sprites it is drawing.

A sprite which has been added to the #sprites array will be drawn in the following way:

  • The CompoundSprite‘s x, y, w, h act as a viewable rectangle on the main screen and are absolute values compared to the game resolution. Sprites which would be drawn completely outside of this rect will be ignored. **Important!** This is unlike Render Targets or regular sprites, which cut off the image cleanly at these boundaries. The CompoundSprite is a virtual effect which can’t slice a sprite in half. Therefore, the entire sprite is rendered if even a portion is visible in the viewable rect.

  • The CompoundSprite‘s source_x, source_y, source_w, source_h act like these attributes would if displaying a normal image instead of a collection of sprites. They are relative values of the #sprites it is drawing.

    • source_x, source_y reposition the origin of the viewport into the #sprites array. E.g. If you have a sprite @ 0x/0y with 10w/10h it will not be drawn if the CompoundSprite‘s source_x and source_y exceeds 10/10

    • source_w, source_h describe the extent of the viewport into the #sprites array. E.g. If the CompoundSprite has 0x, 0y, 20w, 20h, and 0 source_x, 0 source_y, 10 source_w, 10 source_h, the example 0x, 0y, 10w, 10h sprite will be displayed twice as large as normal.

    • **Important!** As above, unlike a normal sprite, changing the source_x, source_y, source_w, source_h will not cause sprites drawn this way to be sliced in any way. It will simply zoom and pan the complete sprites, and possibly ignore them if they exceed the extent of the viewable rectangle or the source viewport.

This class is the basis for Layers::ActiveLayer and many of the UI elements (UI::TwoStageButton, UI::NinePanel, etc).

Examples:

The CompoundSprite position causes translation on the sprites it contains

alduin = Zif::Sprite.new.tap do |s|
  s.x = 0
  s.y = 100
  s.w = 82
  s.h = 66
  s.path = "sprites/dragon_1.png"
end
bahamut = Zif::Sprite.new.tap do |s|
  s.x = 200
  s.y = 0
  s.w = 82
  s.h = 66
  s.flip_horizontally = true
  s.path = "sprites/dragon_1.png"
end

# Now we have 2 dragons facing each other, but we are not adding these to args.outputs.sprites individually.
# They are on a battlefield and can be moved in unison!

battlefield = Zif::CompoundSprite.new.tap do |cs|
  cs.sprites = [alduin, bahamut]
  cs.x = 130 # This causes bahamut to appear at x == 330 on screen
  cs.y = 20  # This causes alduin to appear at y == 120 on screen
  cs.w = 300 # To show everything, should be at least as wide as the farthest x value + width (200+82)
  cs.h = 200 # To show everything, should be at least as high as the largest y value + height (100+66)
  # No path is defined, CompoundSprite is for organization only and does not display directly.
end

# Add the battlefield to outputs.
$gtk.args.outputs.sprites << battlefield

See Also:

Constant Summary

Constants inherited from Sprite

Sprite::BLENDMODE

Instance Attribute Summary collapse

Attributes inherited from Sprite

#a, #angle, #b, #g, #h, #logical_x, #logical_y, #name, #path, #r, #render_target, #source_h, #source_w, #source_x, #source_y, #w, #x, #y, #z_index

Attributes included from Clickable

#on_mouse_changed, #on_mouse_down, #on_mouse_up

Attributes included from Actions::Animatable

#animation_sequences, #cur_animation

Attributes included from Actions::Actionable

#actions, #dirty

1. Public Interface collapse

2. Private-ish methods collapse

Methods inherited from Sprite

#blend, #blend=, #center, #center_x, #center_y, #clicked?, #color, #color=, #dup_and_assign, #exclude_from_serialize, #hide, #rect, rect_array_to_hash, rect_array_to_source_hash, #rect_hash, rect_hash_to_source_hash, #show, #source_as_rect_hash, #source_center, #source_is_set?, #source_rect_hash, #source_wh, #source_xy, #to_h, #view_actual_size!, #wh, #xy, #zoom_factor

Methods included from Clickable

#absorb_click?, #clicked?

Methods included from Actions::Animatable

#new_basic_animation, #new_tiled_animation, #register_animation_sequence, #run_animation_sequence, #stop_animating

Methods included from Actions::Actionable

#bounce_forever_around, #delayed_action, #fade_in, #fade_out, #fade_out_and_in_forever, #new_action, #perform_actions, #run_action, #running_actions?, #stop_action

Methods included from Serializable

#exclude_from_serialize, #inspect, #serialize, #to_s

Methods included from Assignable

#assign

Constructor Details

#initialize(name = Zif.unique_name('compound_sprite')) ⇒ CompoundSprite

Returns a new instance of CompoundSprite.

Parameters:

  • name (String) (defaults to: Zif.unique_name('compound_sprite'))

    The name of this compound sprite, mostly used for debugging purposes



81
82
83
84
85
# File 'lib/zif/compound_sprite.rb', line 81

def initialize(name=Zif.unique_name('compound_sprite'))
  super(name)
  @sprites = []
  @labels  = []
end

Instance Attribute Details

#labelsArray<Zif::UI::Label>

Returns The list of labels this CompoundSprite is rendering.

Returns:

  • (Array<Zif::UI::Label>)

    The list of labels this CompoundSprite is rendering.



75
76
77
# File 'lib/zif/compound_sprite.rb', line 75

def labels
  @labels
end

#spritesArray<Zif::Sprite>

Returns The list of sprites this CompoundSprite is rendering.

Returns:

  • (Array<Zif::Sprite>)

    The list of sprites this CompoundSprite is rendering.



72
73
74
# File 'lib/zif/compound_sprite.rb', line 72

def sprites
  @sprites
end

Instance Method Details

#draw_override(ffi_draw) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This class defines #draw_override, which is used by DragonRuby GTK internals. This method contains the logic for grouping the #sprites and #labels together.

You should not need to call this directly. DRGTK docs on #draw_override: docs.dragonruby.org/#—-performance—static-sprites-as-classes-with-custom-drawing—main.rb



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/zif/compound_sprite.rb', line 106

def draw_override(ffi_draw)
  # $services&.named(:tracer)&.mark("CompoundSprite(#{@name})#draw_override: begin")
  # Treat an alpha setting of 0 as an indication that it should be hidden, to match Sprite behavior
  return if @a.zero?

  view_actual_size! unless source_is_set?

  x_zoom, y_zoom = zoom_factor
  cur_source_right = @source_x + @source_w
  cur_source_top   = @source_y + @source_h

  # Since this "sprite" itself won't actually be drawn, we can use the positioning attributes to control the
  # contained sprites.
  # x/y: linear offset
  # w/h: used for #zoom_factor, derived with comparison to source_w/h (Sprite method)
  # source_x/y: position of visible window
  # source_w/h: extent of visible window.  Unfortunately we can't clip sprites in half using this method.
  #             Therefore, anything even *partially* visible will be *fully* drawn.

  # $services&.named(:tracer)&.mark("CompoundSprite(#{@name})#draw_override: Sprite drawing begin")
  # puts "CompoundSprite(#{@name})#draw_override: Sprite drawing begin"

  # Throwback to the days before Enumerable, for performance reasons
  cur_sprite_idx = 0
  total_sprite_length = sprites.count
  while cur_sprite_idx < total_sprite_length
    sprite = @sprites[cur_sprite_idx]
    cur_sprite_idx += 1
    next if sprite.nil?

    x = sprite.x
    y = sprite.y
    w = sprite.w
    h = sprite.h

    # This performs a little better than calling intersect_rect?
    next if
      (x     > cur_source_right) ||
      (y     > cur_source_top)   ||
      (x + w < @source_x)        ||
      (y + h < @source_y)

    ffi_draw.draw_sprite_3(
      (x - @source_x) * x_zoom + @x,
      (y - @source_y) * y_zoom + @y,
      w * x_zoom,
      h * y_zoom,
      sprite.path.s_or_default,
      sprite.angle,
      sprite.a,
      sprite.r,
      sprite.g,
      sprite.b,
      nil, nil, nil, nil, # Don't use tile_*
      sprite.flip_horizontally,
      sprite.flip_vertically,
      sprite.angle_anchor_x,
      sprite.angle_anchor_y,
      sprite.source_x,
      sprite.source_y,
      sprite.source_w,
      sprite.source_h
    )
  end
  # $services&.named(:tracer)&.mark("CompoundSprite(#{@name})#draw_override: Sprite drawing complete")
  # puts "CompoundSprite(#{@name})#draw_override: Sprite drawing complete"

  labels.each do |label|
    # TODO: Skip if not in visible window
    ffi_draw.draw_label(
      ((label.x - @source_x) * x_zoom) + @x,
      ((label.y - @source_y) * y_zoom) + @y,
      label.text.s_or_default,
      label.size_enum,
      label.alignment_enum,
      label.r,
      label.g,
      label.b,
      label.a,
      label.font.s_or_default(nil)
    )
  end
  # $services&.named(:tracer)&.mark("CompoundSprite(#{@name})#draw_override: Label drawing complete")
end

#source_rectArray<Numeric>

Calls Sprite#source_rect after ensuring the source_x etc attrs are set to something.



91
92
93
94
# File 'lib/zif/compound_sprite.rb', line 91

def source_rect
  view_actual_size! unless source_is_set?
  super
end