Module: Zif::Layers::Tileable
- Included in:
- ActiveBitmaskedTiledLayer, ActiveTiledLayer, BitmaskedTiledLayer, TiledLayer
- Defined in:
- lib/zif/layers/tileable.rb
Overview
Functionality shared between TiledLayer & BitmaskedTiledLayer
Modifies the layer to be based around the concept of a “logical” position. This is used to differentiate between the “natural” x, y position on the screen. The “logical” position is instead the natural position divided by the tile size, and is used to index the sprites array.
For performance reasons, the sprites array is still implemented as one-dimensional array, but the idea is that it could have been implemented as a two-dimensional array of rows (logical_x
) and columns (logical_y
).
Add sprites to the layer using #add_positioned_sprite which sets the logical position on the sprite.
Instance Method Summary collapse
-
#add_positioned_sprite(sprite:, logical_x:, logical_y:) ⇒ Object
Overrides SimpleLayer#add_positioned_sprite or ActiveLayer#add_positioned_sprite Adds
sprite
to the @sprites array at the position indicated bylogical_x
andlogical_y
. - #exclude_from_serialize ⇒ Object
-
#intersecting_sprites(left:, bottom:, right:, top:) ⇒ Object
Overrides Layerable#intersecting_sprites A convenience to calling #visible_sprites with boundary values instead of a [x,y,w,h] rect.
-
#reinitialize_sprites ⇒ Object
Overrides SimpleLayer#reinitialize_sprites or ActiveLayer#reinitialize_sprites Clears the @sprites array, based on the logical_height and logical_width of the LayerGroup.
-
#remove_positioned_sprite(sprite) ⇒ Object
Overrides Layerable#remove_positioned_sprite Remove a sprite which has already been added.
-
#remove_tile(logical_x, logical_y) ⇒ Object
Clears the element in the @sprites array indicated by the logical position.
-
#tile(logical_x, logical_y) ⇒ Zif::Sprite
Uses #tile_pos_to_sprite_index and returns the sprite at that position in @sprites.
-
#tile_pos_to_sprite_index(logical_x, logical_y) ⇒ Integer
Convert logical_x and logical_y to the index of the sprite in the @sprites array.
-
#visible_sprites(given_rect = nil) ⇒ Enumerator
Overrides Layerable#visible_sprites This returns an enumerator which can be used to iterate over only the tiles which are visible.
Instance Method Details
#add_positioned_sprite(sprite:, logical_x:, logical_y:) ⇒ Object
Overrides SimpleLayer#add_positioned_sprite or ActiveLayer#add_positioned_sprite Adds sprite
to the @sprites array at the position indicated by logical_x
and logical_y
. Ensures the logical position is saved on the sprite
.
40 41 42 43 44 45 46 47 48 |
# File 'lib/zif/layers/tileable.rb', line 40 def add_positioned_sprite(sprite:, logical_x:, logical_y:) # puts "#{@layer_name}: Tileable#add_positioned_sprite #{logical_x} #{logical_y}" # puts "#{@sprites.class.to_s}" @sprites[tile_pos_to_sprite_index(logical_x, logical_y)] = position_sprite( sprite: sprite, logical_x: logical_x, logical_y: logical_y ) end |
#exclude_from_serialize ⇒ Object
133 134 135 |
# File 'lib/zif/layers/tileable.rb', line 133 def exclude_from_serialize %w[sprites primitives] end |
#intersecting_sprites(left:, bottom:, right:, top:) ⇒ Object
Overrides Layerable#intersecting_sprites A convenience to calling #visible_sprites with boundary values instead of a [x,y,w,h] rect.
129 130 131 |
# File 'lib/zif/layers/tileable.rb', line 129 def intersecting_sprites(left:, bottom:, right:, top:) visible_sprites([left, bottom, right - left, top - bottom]) end |
#reinitialize_sprites ⇒ Object
Overrides SimpleLayer#reinitialize_sprites or ActiveLayer#reinitialize_sprites Clears the @sprites array, based on the logical_height and logical_width of the LayerGroup
28 29 30 31 32 |
# File 'lib/zif/layers/tileable.rb', line 28 def reinitialize_sprites super # puts "#{@layer_name}: Tileable#reinitialize_sprites #{@map.logical_height} #{@map.logical_width}" @sprites = Array.new(@map.logical_height * @map.logical_width) end |
#remove_positioned_sprite(sprite) ⇒ Object
Overrides Layerable#remove_positioned_sprite Remove a sprite which has already been added. Finds the sprite by calculating its position in the @sprites array using #tile_pos_to_sprite_index and the sprite
‘s logical position.
54 55 56 |
# File 'lib/zif/layers/tileable.rb', line 54 def remove_positioned_sprite(sprite) @sprites[tile_pos_to_sprite_index(sprite.logical_x, sprite.logical_y)] = nil end |
#remove_tile(logical_x, logical_y) ⇒ Object
Clears the element in the @sprites array indicated by the logical position.
61 62 63 |
# File 'lib/zif/layers/tileable.rb', line 61 def remove_tile(logical_x, logical_y) @sprites[tile_pos_to_sprite_index(logical_x, logical_y)] = nil end |
#tile(logical_x, logical_y) ⇒ Zif::Sprite
Uses #tile_pos_to_sprite_index and returns the sprite at that position in @sprites
22 23 24 |
# File 'lib/zif/layers/tileable.rb', line 22 def tile(logical_x, logical_y) @sprites[tile_pos_to_sprite_index(logical_x, logical_y)] end |
#tile_pos_to_sprite_index(logical_x, logical_y) ⇒ Integer
Convert logical_x and logical_y to the index of the sprite in the @sprites array.
16 17 18 |
# File 'lib/zif/layers/tileable.rb', line 16 def tile_pos_to_sprite_index(logical_x, logical_y) (logical_y * @map.logical_width) + logical_x end |
#visible_sprites(given_rect = nil) ⇒ Enumerator
Overrides Layerable#visible_sprites This returns an enumerator which can be used to iterate over only the tiles which are visible. Only for layers which have allocated_tiles!
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/zif/layers/tileable.rb', line 70 def visible_sprites(given_rect=nil) # puts "Tileable#visible_sprites: #{@layer_name} '#{given_rect}'" if given_rect.nil? containing_sprite.view_actual_size! unless containing_sprite.source_is_set? left = containing_sprite.source_x bottom = containing_sprite.source_y w = containing_sprite.source_w h = containing_sprite.source_h else left = given_rect.x bottom = given_rect.y w = given_rect.w h = given_rect.h end logical_x = left.idiv(@map.tile_width) logical_y = bottom.idiv(@map.tile_height) x_range = w.fdiv(@map.tile_width) y_range = h.fdiv(@map.tile_height) max_y = [logical_y + y_range.ceil + 1, @map.logical_height].min max_x = [logical_x + x_range.ceil + 1, @map.logical_width].min # This enumerator is basically the equivalent of: # # @floor_tiles[logical_y..max_y].map do |x_tiles| # x_tiles[logical_x..max_x] # end.flatten.to_enum # # The benefit of doing this instead is that we avoid some extraneous iteration and allocation if we call # #visible_tiles more than once per tick. This definitely feels faster, but I haven't benchmarked. starting_a = [logical_x, 0].max starting_b = [logical_y, 0].max a = starting_a b = starting_b # puts " -> #{logical_x} #{logical_y} #{x_range} #{y_range} #{max_y} #{max_x} #{starting_a} #{starting_b} " Enumerator.new do |yielder| loop do next_tile = tile(a, b) yielder << next_tile if next_tile r, a = (a + 1).divmod(max_x) if r.positive? a = starting_a b += r end break if b > max_y end end end |