• Our software update is now concluded. You will need to reset your password to log in. In order to do this, you will have to click "Log in" in the top right corner and then "Forgot your password?".
  • Welcome to PokéCommunity! Register now and join one of the best fan communities on the 'net to talk Pokémon and more! We are not affiliated with The Pokémon Company or Nintendo.

Nuri Yuri's Tilemap

MysteriousUser94

Guest
0
Posts
Hi everyone !
Today I decided to finish the tilemap script I started to rewrite. This script objective was to reduce the Autotile lag there was with the previous script. This script is designed to work with the RGSS 3 but to display RMXP like maps.

Code:
# Header: psdk.pokemonworkshop.com/index.php/ScriptHeader
# Author: Nuri Yuri
# Date: 2017
# Update: 2017-09-08
# ScriptNorm: No
# Description: Affichage des tiles sur la map
class Tilemap
	attr_accessor :tileset, :autotiles, :map_data, :priorities, :ox, :oy
  attr_reader :viewport, :disposed
  
  Autotile_Frame_Count = 15
  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] ]
  ]
  SRC = Rect.new(0, 0, 16, 16)
  #> Nombre de sprites pour les positions x et positions y
  NX = 22
  NY = 17
  #> De cache (pour des optimisations de transition)
  @@autotile_bmp = Array.new(384)
  @@autotiles_copy = Array.new(7, -1)
  @@autotile_db = Hash.new
  
  def initialize(viewport)
    @viewport = viewport
    @autotiles = Array.new(7)
    @autotiles_counter = Array.new(8, 0)
    @autotiles_copy = @@autotiles_copy
    @autotiles_bmp = @@autotile_bmp
    make_sprites(viewport)
    check_copy(@autotiles_copy)
    @last_ox = @last_oy = nil #> Prévenir d'un déplacement inutile
    @disposed = false
  end
  
  # ox / 32 = position du premier tile visible, oy / 32 pareil
  def update
    return if @disposed
    ox = @ox
    oy = @oy
    #> S'il y a une variation dans les autotiles
    if @autotiles != @autotiles_copy
      remake_autotiles
      draw_all(@last_x = ox / 32 - 1, @last_y = oy / 32 - 1, ox % 32, oy % 32)
    #> Si le compteur tombe sur le moment de mise à jour des autotiles
    elsif (Graphics.frame_count % Autotile_Frame_Count) == 0
      x = ox / 32 - 1
      y = oy / 32 - 1
      #> Si la position a changée il faut remettre les bitmaps où il faut
      if(x != @last_x or y != @last_y)
        draw_all(@last_x = x, @last_y = y, ox % 32, oy % 32)
      else
        draw_autotiles(@last_x = x, @last_y = y, ox % 32, oy % 32)
      end
    #> Si la map a bougée
    elsif ox != @last_ox or oy != @last_oy
      x = ox / 32 - 1
      y = oy / 32 - 1
      #> Si la position a changée il faut remettre les bitmaps où il faut
      if(x != @last_x or y != @last_y)
        draw_all(@last_x = x, @last_y = y, ox % 32, oy % 32)
      else
        update_positions(@last_x = x, @last_y = y, ox % 32, oy % 32)
      end
    end
    @last_ox = ox
    @last_oy = oy
  end
  
  #===
  #> Fonction de dessin des autotiles
  #  Cette fonction ajuste les compteur d'autorile et réactualise les src_rect
  #===
  def draw_autotiles(x, y, ox, oy)
    map_data = @map_data
    autotiles_counter = @autotiles_counter
    autotiles_bmp = @autotiles_bmp
    1.upto(7) do |index|
      counter = autotiles_counter[index]
      counter += 32
      counter = 0 if(autotiles_bmp[index * 48].height <= counter)
      autotiles_counter[index] = counter
    end
    @sprites.each_with_index do |sprite_table, pz|
      sprite_table.each_with_index do |sprite_col, px|
        sprite_col.each_with_index do |sprite, py|
          sprite.ox = ox
          sprite.oy = oy
          tile_id = map_data[x + px, y + py, pz]
          if(tile_id and tile_id > 0 and tile_id < 384) #Autotile
            sprite.src_rect.set(0, autotiles_counter[tile_id / 48], 32, 32)
          end
        end
      end
    end
  end
  #===
  #> Fonction de dessin de tous les sprites
  #  Cette fonction ajuste le bitmap du sprite ainsi que son src_rect, elle recalcule aussi la position z
  #  Formule simplifiée du z : sprite.y + priority * 32 + 32 ou 0 si priority == 0
  #  Supprimer add_z pour avoir une priorité plus haute des tiles
  #===
  def draw_all(x, y, ox, oy)
    priorities = @priorities
    map_data = @map_data
    autotiles_counter = @autotiles_counter
    autotiles_bmp = @autotiles_bmp
    tileset = @tileset
    add_z = oy / 2
    @sprites.each_with_index do |sprite_table, pz|
      sprite_table.each_with_index do |sprite_col, px|
        sprite_col.each_with_index do |sprite, py|
          sprite.ox = ox
          sprite.oy = oy
          tile_id = map_data[x + px, y + py, pz]
          if(!tile_id or tile_id <= 0)
            next(sprite.bitmap = nil)
          elsif(tile_id < 384) #Autotile
            sprite.bitmap = autotiles_bmp[tile_id]
            sprite.src_rect.set(0, autotiles_counter[tile_id / 48], 32, 32)
          else #Tile
            tid = tile_id - 384
            sprite.bitmap = tileset
            sprite.src_rect.set(tid % 8 * 32, tid / 8 * 32, 32, 32)
          end
          priority = priorities[tile_id]
          next(sprite.z = 0) if !priority or priority == 0
          sprite.z = (py + priority) * 32 - add_z
        end
      end
    end
    
  end
  
  #===
  #> Fonction de mise à jour des positions
  #  Cette fonction actualise la position ox/oy des sprites + Petite opti pour les bâtiments
  #  La méthode contient ce qui est commenté en temps normal (priorité plus haute des tiles)
  #===
  def update_positions(x, y, ox, oy)
    priorities = @priorities
    map_data = @map_data
    add_z = oy / 2
    @sprites.each_with_index do |sprite_table, pz|
      sprite_table.each_with_index do |sprite_col, px|
        sprite_col.each_with_index do |sprite, py|
          sprite.ox = ox
          sprite.oy = oy
          tile_id = map_data[x + px, y + py, pz]
          next if(!tile_id or tile_id <= 0)
          priority = priorities[tile_id]
          next if !priority or priority == 0
          sprite.z = (py + priority) * 32 - add_z
        end
      end
    end
=begin
    @sprites.each do |sprite_table|
      sprite_table.each do |sprite_col|
        sprite_col.each do |sprite|
          sprite.ox = ox
          sprite.oy = oy
        end
      end
    end
=end
  end
  
  def dispose
    return if @disposed
    @sprites.each { |sprite_array| sprite_array.each { |sprite_col| sprite_col.each { |sprite| sprite.dispose } } }
    @disposed = true
  end
  alias disposed? disposed
  
  def make_sprites(viewport, tile_size = 32, zoom = 1)
    sprite = nil
    @sprites = Array.new(3) do
      Array.new(NX) do |x|
        Array.new(NY) do |y|
          sprite = Sprite.new(viewport)
          sprite.x = (x - 1) * tile_size
          sprite.y = (y - 1) * tile_size
          sprite.zoom_x = sprite.zoom_y = zoom
          next(sprite)
        end
      end
    end
  end
  
  def remake_autotiles
    autotiles = @autotiles
    autotiles_copy = @autotiles_copy
    7.times do |j|
      if autotiles_copy[j] != autotiles[j]
        autotiles_copy[j] = autotiles[j]
        load_autotile(j, (j + 1) * 48, autotiles)
      end
    end
  end
  
  def check_copy(copy)
    7.times do |i|
      if copy[i] and copy[i] != -1
        if copy[i].disposed?
          @@autotiles_copy = @autotiles_copy = Array.new(7, -1)
        end
        break
      end
    end
  end
  
  def load_autotile(j, base_id, autotiles)
    autotile_name = $game_map.autotile_names[j]
    autotiles_bmp = @autotiles_bmp
    if(autotile_data = @@autotile_db[autotile_name])
      unless autotile_data.first.disposed?
        autotile_data.each_with_index do |autotile, i|
          autotiles_bmp[base_id + i] = autotile
        end
        return
      end
    end
    autotile_data = []
    base_id.upto(base_id + 47) do |i|
      autotile_data << (autotiles_bmp[i] = generate_autotile_bmp(i, autotiles))
    end
    @@autotile_db[autotile_name] = autotile_data
  end
  
  def generate_autotile_bmp(id, autotiles)
    autotile = autotiles[id / 48 - 1]
    return Bitmap.new(32, 32) if !autotile or autotile.width < 96
    src = SRC
    id %= 48
    tiles = Autotiles[id>>3][id&7]
    frames = autotile.width / 96
    bmp = Bitmap.new(32, frames * 32)
    frames.times do |x|
      anim = x * 96
      4.times do |i|
        tile_position = tiles[i] - 1
        src.set(tile_position % 6 * 16 + anim, tile_position / 6 * 16, 16, 16)
        bmp.blt(i % 2 * 16, i / 2 * 16 + x * 32, autotile, src)
      end
    end
    return bmp
  end
end

class Yuri_Tilemap < Tilemap
  def make_sprites(viewport)
    super(viewport, 16, 0.5)
  end
end
There's two classes in this script
- Tilemap : to display 32x32 tiles (2x2 looking with low quality tiles)
- Yuri_Tilemap : to display 16x16 tiles from a 32x32 tileset (zoom = 1/2)

I optimised this tilemap by counting the time spend inside the update function for 180 frames. I couldn't do better than the poccil's tilemap for some points but my objective (no more Autotile LAG) is done :)
NY Tilemap
0.014 = pas de mouvements
0.18 / 0.2 = mouvements

Avec autotiles (full)
0.014 = pas de mouvements
0.155 = mouvements

Poccil's Tilemap (an outdated one i guess)
0.0 = pas de mouvements
0.17 = mouvements

Avec Autotiles (full)
0.85 = pas de mouvements
1.01 = mouvements

___
NY tilemap : Phase d'optimisation
0.011 ~ 0.016 (pas de mouvements)
0.009 ~ 0.011 (pas de mouvements => passage de certains tableaux en variable locale)
0.159 ~ 0.169 (mouvements)
0.008 ~ 0.0095 (pas de mouvements => usage de bitmap = nil à la place de visible = false)
0.132 ~ 0.141 (mouvements)

Important note : There's no flash_data in this tilemap (didn't see any use in my scripts ^^').

Feel free to use it if you want :)
 
Last edited:
Back
Top