Envision, Create, Share

Welcome to HBGames, a leading amateur game development forum and Discord server. All are welcome, and amongst our ranks you will find experts in their field from all aspects of video game design and development.

Tilemap optimization

arev

Sponsor

I managed to run my game in 800x600 resolution (whole map), but Seph's Tilemap rewrite lags like hell :/ When only moving, I get around 20 fps on a 45x38 map, on a Dual Athlon 4200+ with 1GB of RAM. What I'd need is to optimize the script, or leave just the functions that are necessary to make the layer bitmap bigger (if that's even possible). Any help appreciated :)

Here's the script, since Seph didn't repost it yet:
Code:
#==============================================================================
# ** Game_Map
#==============================================================================

class Game_Map
  #--------------------------------------------------------------------------
  # * Public Instance Variables
  #--------------------------------------------------------------------------
  attr_reader :map
  attr_accessor :tilemap_tone
  attr_accessor :tilemap_plane
  attr_accessor :tilemap_zoom_x
  attr_accessor :tilemap_zoom_y
  attr_accessor :tilemap_tile_width
  attr_accessor :tilemap_tile_height
  #--------------------------------------------------------------------------
  # * Alias Listings
  #--------------------------------------------------------------------------
  alias seph_tilemap_gmap_init initialize
  #--------------------------------------------------------------------------
  # * Object Initialization
  #--------------------------------------------------------------------------
  def initialize
    # Original Initialization
    seph_tilemap_gmap_init
    # Sets Special Tilemap Properties
    @tilemap_tone        = nil
    @tilemap_plane       = false
    @tilemap_zoom_x      = 1.0
    @tilemap_zoom_y      = 1.0
    @tilemap_tile_width  = 32
    @tilemap_tile_height = 32
  end
end

#==============================================================================
# ** Tilemap
#==============================================================================

class Tilemap
  #--------------------------------------------------------------------------
  # * Animated Autotiles Frames Reset
  #--------------------------------------------------------------------------
  Animated_Autotiles_Frames = 15
  #--------------------------------------------------------------------------
  # * Auto-Tiles
  #
  #   Auto-Tile 48 : First Auto-Tile, Constructed of tiles 27, 28, 33, 34
  #--------------------------------------------------------------------------
  Autotiles = [
    [ [27, 28, 33, 34], [ 5, 28, 33, 34], [27,  6, 33, 34], [ 5,  6, 33, 34],
      [27, 28, 33, 12], [ 5, 28, 33, 12], [27,  6, 33, 12], [ 5,  6, 33, 12] ],
    [ [27, 28, 11, 34], [ 5, 28, 11, 34], [27,  6, 11, 34], [ 5,  6, 11, 34],
      [27, 28, 11, 12], [ 5, 28, 11, 12], [27,  6, 11, 12], [ 5,  6, 11, 12] ],
    [ [25, 26, 31, 32], [25,  6, 31, 32], [25, 26, 31, 12], [25,  6, 31, 12],
      [15, 16, 21, 22], [15, 16, 21, 12], [15, 16, 11, 22], [15, 16, 11, 12] ],
    [ [29, 30, 35, 36], [29, 30, 11, 36], [ 5, 30, 35, 36], [ 5, 30, 11, 36],
      [39, 40, 45, 46], [ 5, 40, 45, 46], [39,  6, 45, 46], [ 5,  6, 45, 46] ],
    [ [25, 30, 31, 36], [15, 16, 45, 46], [13, 14, 19, 20], [13, 14, 19, 12],
      [17, 18, 23, 24], [17, 18, 11, 24], [41, 42, 47, 48], [ 5, 42, 47, 48] ],
    [ [37, 38, 43, 44], [37,  6, 43, 44], [13, 18, 19, 24], [13, 14, 43, 44],
      [37, 42, 43, 48], [17, 18, 47, 48], [13, 18, 43, 48], [ 1,  2,  7,  8] ]
  ]
  #--------------------------------------------------------------------------
  # * Public Instance Variables
  #--------------------------------------------------------------------------
  attr_reader :layers
  attr_accessor :tileset
  attr_accessor :autotiles
  attr_accessor :map_data
  attr_accessor :flash_data
  attr_accessor :priorities
  attr_accessor :visible
  attr_accessor :ox
  attr_accessor :oy
  #--------------------------------------------------------------------------
  # * Object Initialization
  #--------------------------------------------------------------------------
  def initialize(viewport, map = $game_map.map)
    # Creates layers
    @layers = []
    for l in 0...3
      layer = ($game_map.tilemap_plane ?
               Plane.new(viewport) : Sprite.new(viewport))
      layer.bitmap = Bitmap.new(map.width * 32, map.height * 32)
      layer.z = l * 150
      layer.zoom_x = $game_map.tilemap_zoom_x
      layer.zoom_y = $game_map.tilemap_zoom_y
      if (tone = $game_map.tilemap_tone).is_a?(Tone)
        layer.tone = tone
      end
      @layers << layer
    end
    # Sets Tileset Data
    @tileset    = nil  # Refers to Map Tileset Name
    @autotiles  = []   # Refers to Tileset Auto-Tiles (Actual Auto-Tiles)
    @map_data   = nil  # Refers to 3D Array Of Tile Settings
    @flash_data = nil  # Refers to 3D Array of Tile Flashdata
    @priorities = nil  # Refers to Tileset Priorities
    @visible    = true # Refers to Tilest Visibleness
    @ox         = 0    # Bitmap Offsets          
    @oy         = 0    # bitmap Offsets
    @data       = nil  # Acts As Refresh Flag
    # Sets Specials Tile Properties
    @map         = map
    @tone        = $game_map.tilemap_tone
    @plane       = $game_map.tilemap_plane
    @zoom_x      = $game_map.tilemap_zoom_x
    @zoom_y      = $game_map.tilemap_zoom_y
    @tile_width  = $game_map.tilemap_tile_width
    @tile_height = $game_map.tilemap_tile_height
  end
  #--------------------------------------------------------------------------
  # * Dispose
  #--------------------------------------------------------------------------
  def dispose
    # Dispose Layers (Sprites)
    for layer in @layers
      layer.dispose
    end
  end
  #--------------------------------------------------------------------------
  # * Frame Update
  #--------------------------------------------------------------------------
  def update
    # If Data Changes
    unless @data == @map_data &&
           @tile_width == $game_map.tilemap_tile_width &&
           @tile_height == $game_map.tilemap_tile_height
      refresh
    end
    # Tone Change
    unless @tone == $game_map.tilemap_tone
      @tone = $game_map.tilemap_tone
      @tone = Tone.new(0, 0, 0, 0) if @tone.nil?
      for layer in @layers
        layer.tone = @tone
        layer.tone = @tone
      end
    end
    # Zoom Change
    unless @zoom_x == $game_map.tilemap_zoom_x
      @zoom_x = $game_map.tilemap_zoom_x
      for layer in @layers
        layer.zoom_x = @zoom_x
        layer.zoom_x = @zoom_x
      end
    end
    unless @zoom_y == $game_map.tilemap_zoom_y
      @zoom_y = $game_map.tilemap_zoom_y
      for layer in @layers
        layer.zoom_y = @zoom_y
        layer.zoom_y = @zoom_y
      end
    end
    # Update layer Position offsets
    for layer in @layers
      layer.ox = @ox
      layer.oy = @oy
    end
    # Animated Autotiles
    if Graphics.frame_count % Animated_Autotiles_Frames == 0
      # Refresh Autotiles
      refresh_autotiles
    end
  end
  #--------------------------------------------------------------------------
  # * Refresh
  #--------------------------------------------------------------------------
  def refresh
    # Saves Map Data
    @data = @map_data
    # Passes Through All Priorities
    for p in 0..5
      # Passes Through Layers
      for z in 0...@map_data.zsize
        # Passes Through X Coordinates
        for x in 0...@map_data.xsize
          # Passes Through Z Coordinates
          for y in 0...@map_data.ysize
            # Collects Tile ID
            id = @map_data[x, y, z]
            # Skip if 0 tile
            next if id == 0
            # Skip If Priority Doesn't Match
            next unless p == @priorities[id]
            # Cap Priority to Layer 3
            p = 2 if p > 2
            # Draw Tile
            id < 384 ? draw_autotile(x, y, p, id) : draw_tile(x, y, p, id)
          end
        end
      end
    end
  end
  #--------------------------------------------------------------------------
  # * Refresh Auto-Tiles
  #--------------------------------------------------------------------------
  def refresh_autotiles
    # Auto-Tile Locations
    autotile_locations = Table.new(@map_data.xsize, @map_data.ysize,
      @map_data.zsize)
    # Passes Through All Priorities
    for p in 0..5
      # Passes Through Layers
      for z in 0...@map_data.zsize
        # Passes Through X Coordinates
        for x in 0...@map_data.xsize
          # Passes Through Z Coordinates
          for y in 0...@map_data.ysize
            # Collects Tile ID
            id = @map_data[x, y, z]
            # Skip if 0 tile
            next if id == 0
            # Skip If Priority Doesn't Match
            next unless p == @priorities[id]
            # Skip If Non-Animated Tile
            next unless autotile = @autotiles[id / 48 - 1].width / 96 > 1
            # Cap Priority to Layer 3
            p = 2 if p > 2
            # If Autotile
            if id < 384
              # Draw Auto-Tile
              draw_autotile(x, y, p, id)
              # Save Autotile Location
              autotile_locations[x, y, z] = 1
            # If Normal Tile
            else
              # If Autotile Drawn
              if autotile_locations[x, y, z] == 1
                # Redraw Normal Tile
                draw_tile(x, y, p, id)
              end
            end
          end
        end
      end
    end
  end
  #--------------------------------------------------------------------------
  # * Draw Tile
  #--------------------------------------------------------------------------
  def draw_tile(x, y, z, id)
    # Figures Tile Rect
    rect = Rect.new((id - 384) % 8 * 32, (id - 384) / 8 * 32, 32, 32)
    # Calculates Tile Coordinates
    x *= @tile_width
    y *= @tile_height
    # If Normal Tile
    if @tile_width == 32 && @tile_height == 32
      @layers[z].bitmap.blt(x, y, @tileset, rect)
    # If Altered Dimensions
    else
      dest_rect = Rect.new(x, y, @tile_width, @tile_height)
      @layers[z].bitmap.stretch_blt(dest_rect, @tileset, rect)
    end
  end
  #--------------------------------------------------------------------------
  # * Draw Auto-Tile
  #--------------------------------------------------------------------------
  def draw_autotile(x, y, z, tile_id)
    # Gets Auto-Tile
    autotile = @autotiles[tile_id / 48 - 1]
    # Reconfigure Tile ID
    tile_id %= 48
    # Creates Bitmap
    bitmap = Bitmap.new(32, 32)
    # Collects Auto-Tile Tile Layout
    tiles = Autotiles[tile_id / 8][tile_id % 8]
    # Animated Tiles
    frames = autotile.width / 96
    # Configures Animation Offset
    anim = (Graphics.frame_count / Animated_Autotiles_Frames) % frames * 96
    # Draws Auto-Tile Rects
    for i in 0...4
      tile_position = tiles[i] - 1
      src_rect = Rect.new(tile_position % 6 * 16 + anim, tile_position / 6 * 16, 16, 16)
      bitmap.blt(i % 2 * 16, i / 2 * 16, autotile, src_rect)
    end
    # Calculates Tile Coordinates
    x *= @tile_width
    y *= @tile_height
    # If Normal Tile
    if @tile_width == 32 && @tile_height == 32
      @layers[z].bitmap.blt(x, y, bitmap, Rect.new(0, 0, 32, 32))
    # If Altered Dimensions
    else
      dest_rect = Rect.new(x, y, @tile_width, @tile_height)
      @layers[z].bitmap.stretch_blt(dest_rect, bitmap, Rect.new(0, 0, 32, 32))
    end
  end
  #--------------------------------------------------------------------------
  # * Collect Bitmap
  #--------------------------------------------------------------------------
  def bitmap
    # Creates New Blank Bitmap
    bitmap = Bitmap.new(@layers[0].bitmap.width, @layers[0].bitmap.height)
    # Passes Through All Layers
    for layer in @layers
      bitmap.blt(0, 0, layer.bitmap,
        Rect.new(0, 0, bitmap.width, bitmap.height))
    end
    # Return Bitmap
    return bitmap
  end
end

p.s. If someone with powers of moving things thinks this should be in requests, please move it :)
 
unfortunately there's not much any way to optimize the script. It runs correctly with the default class because it's written in C not in ruby.

I am currently (well, on hold for now) working on rewriting the Tilemap class in dll that could be used with RMXP. It's far from finished though. And since I have very basic knowledge of C, it's not going to be ready soon.
 
The only other method I am thinking of for the tilemap class would optomize the auto-tiles.

Basically, create a new sprite for every frame of every auto-tile.

This should speed up everything a bit, as the only problem I can notice is the autotile handeling.
 

arev

Sponsor

That wouldn't really help in my case, becasue I'm not using any autotiles. To tell you the truth, I even turned off drawing them on map :] Thanks for the interest.
 

Thank you for viewing

HBGames is a leading amateur video game development forum and Discord server open to all ability levels. Feel free to have a nosey around!

Discord

Join our growing and active Discord server to discuss all aspects of game making in a relaxed environment. Join Us

Content

  • Our Games
  • Games in Development
  • Emoji by Twemoji.
    Top