• 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