Guest User

MBS - Isometric

a guest
Jun 30th, 2015
376
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 22.89 KB | None | 0 0
  1. #==============================================================================
  2. # MBS - Isometric
  3. #------------------------------------------------------------------------------
  4. # por Masked
  5. #==============================================================================
  6. #==============================================================================
  7. # Instruções
  8. #------------------------------------------------------------------------------
  9. # 1. Tileset
  10. #
  11. # O script usa um tileset com cubos isométricos, a grade do tileset deve ter
  12. # 64 pixels, o tileset deve ter 8 colunas e no máximo 16 linhas.
  13. # O primeiro tile do tileset será sempre transparente, então você pode por o
  14. # que quiser nele (um template pros blocos, por exemplo).
  15. # Depois é só salvar o tileset na pasta do jogo e configurar o caminho do
  16. # arquivo.
  17. # Os tilesets isométricos devem ter o nome dos tilesets no database (Ex.:
  18. # O tileset 'Mundo' no database carrega o tileset isométrico 'Mundo.png' na
  19. # pasta escolhida)
  20. #
  21. # 2. Configuração no database
  22. #
  23. # O tileset no database deve ter só os tiles A5 e B-E, qualquer outro tile será
  24. # ignorado.
  25. # Nas abas B-E, todos os tiles que tiverem uma continuação vertical (por
  26. # exemplo uma árvore) devem ser macados com terrenos, o terreno (0-7) determina
  27. # a altura daquele tile (no exemplo da árvore, o tronco deve ser 0 e as folhas
  28. # devem ser 1).
  29. #
  30. # 3. Mapas
  31. #
  32. # Para definir um mapa como isométrico, é só adicionar "[Isometric]"
  33. # (sem aspas) às notas dele.
  34. # O mapeamento é igual ao normal, a única diferença é que é possível definir a
  35. # altura de um tile (para fazer uma parede, por exemplo), a altura máxima é
  36. # definida nas configurações, não é recomendado mudar (além do que ninguém
  37. # deveria precisar de mais de 5 tiles de altura...), mas fique a vontade.
  38. # Para definir a altura do tile, basta marcar ele com uma região (F7) de número
  39. # correspondente à altura.
  40. # Obs.: A altura do tile também influencia na passabilidade, um tile só é
  41. # passável se a diferença de altura entre ele e o char for menor que 2, isso
  42. # impede que o jogador pule sobre uma parede de 2 tiles de altura a menos que
  43. # ele esteja em um tile com 1 de altura ou que ele pule de uma parede de 2
  44. # tiles de altura direto para o chão.
  45. #==============================================================================
  46. ($imported ||= {})[:mbs_isometric] = true
  47. #==============================================================================
  48. module MBS
  49.   module Isometric
  50. #==============================================================================
  51. # Configurações
  52. #==============================================================================
  53.     # Altura máxima de um tile
  54.     MAX_HEIGHT = 5
  55.  
  56.     # Caso queira que as paredes fiquem transparentes quando um char passar por
  57.     # trás dela deixe como true, se não deixe como false
  58.     $view_behind = true
  59.  
  60.     # Pasta onde ficam os tilesets isométricos
  61.     ISO_TILESET = 'Graphics/Iso/'
  62.    
  63.     # Caso queira que o movimento seja em 8 direções, deixe como true, se não,
  64.     # mude para false
  65.     DIR8 = true
  66. #==============================================================================
  67. # Fim das Configurações
  68. #==============================================================================
  69.     ISO_TAG = /[Isometric]/i
  70.   end
  71. end
  72.  
  73. #------------------------------------------------------------------------------
  74. # Ajuste de performance
  75. #------------------------------------------------------------------------------
  76. Win32API.new('kernel32', 'SetPriorityClass', 'pi', 'i').call(-1, 0x080)
  77. Graphics.frame_rate = 40
  78.  
  79. #==============================================================================
  80. # ** Isomap
  81. #------------------------------------------------------------------------------
  82. # Esta classe desenha o mapa isométrico, bem como os chars do mapa
  83. #==============================================================================
  84. class Isomap
  85.  
  86.   #--------------------------------------------------------------------------
  87.   # Inclusão do módulo MBS::Isometric
  88.   #--------------------------------------------------------------------------
  89.   include MBS::Isometric
  90.  
  91.   #--------------------------------------------------------------------------
  92.   # Definição dos atributos
  93.   #--------------------------------------------------------------------------
  94.   attr_accessor :flags, :bitmaps, :characters, :ox, :oy, :viewport
  95.   attr_reader :sprite, :data
  96.  
  97.   #--------------------------------------------------------------------------
  98.   # * Inicialização do objeto
  99.   #     viewport : A camada da tela onde fica o sprite
  100.   #--------------------------------------------------------------------------
  101.   def initialize(viewport)
  102.     @viewport = viewport
  103.     setup
  104.   end
  105.  
  106.   #--------------------------------------------------------------------------
  107.   # * Configuração das variáveis
  108.   #--------------------------------------------------------------------------
  109.   def setup
  110.     @ox = 0
  111.     @oy = 0
  112.     @tileset = nil
  113.     @data = nil
  114.     @todraw = nil
  115.     @flags = []
  116.     @bitmaps = []
  117.     @characters = []
  118.     @sprite = Sprite.new(self.viewport)
  119.     @sprite.z = 200
  120.     @sprite.bitmap = Bitmap.new(Graphics.width, Graphics.height)
  121.   end
  122.  
  123.   #--------------------------------------------------------------------------
  124.   # * Atualização do objeto
  125.   #--------------------------------------------------------------------------
  126.   def update
  127.     @sprite.update
  128.     return unless @tileset
  129.     draw_sprites
  130.   end
  131.  
  132.   #--------------------------------------------------------------------------
  133.   # * Definição do tileset isométrico
  134.   #     name : Nome do arquivo de tileset
  135.   #--------------------------------------------------------------------------
  136.   def data=(table)
  137.     @data = table
  138.     @todraw = Table.new(table.xsize, table.ysize, 7)
  139.   end
  140.  
  141.   #--------------------------------------------------------------------------
  142.   # * Definição do tileset isométrico
  143.   #     name : Nome do arquivo de tileset
  144.   #--------------------------------------------------------------------------
  145.   def tileset=(name)
  146.     @tileset = Bitmap.new(ISO_TILESET + name)
  147.   end
  148.  
  149.   #--------------------------------------------------------------------------
  150.   # * Verificação de se um char está atrás de um bloco na posição XY
  151.   #     x : Coordenada X
  152.   #     y : Coordenada Y
  153.   #     h : Altura do bloco
  154.   #--------------------------------------------------------------------------
  155.   def char_hidden?(x, y, h)
  156.     @characters.each do |spr|
  157.       next unless spr.visible
  158.       char = spr.character
  159.       ch = char.region_id % (MAX_HEIGHT + 1)
  160.       next if ch >= h
  161.       return true if catch(:any) do
  162.         (1...(h - ch)).each do |i|
  163.           throw(:any, true) if (char.x == x && char.y == y - i ||
  164.            char.x == x - i && char.y == y ||
  165.            char.x == x - i && char.y == y - i)
  166.          end
  167.          false
  168.       end
  169.     end
  170.     false
  171.   end
  172.  
  173.   #--------------------------------------------------------------------------
  174.   # * Aquisição do ID de um tile A5
  175.   #--------------------------------------------------------------------------
  176.   def tileA5(id)
  177.     return id - 0x600 # 0x600 = 1536 (número de tiles A1-A4)
  178.   end
  179.  
  180.   #--------------------------------------------------------------------------
  181.   # * Aquisição da região de um tile
  182.   #--------------------------------------------------------------------------
  183.   def region_id(x, y)
  184.     (data[x, y, 3] >> 8) % (MAX_HEIGHT + 1)
  185.   end
  186.  
  187.   #--------------------------------------------------------------------------
  188.   # * Desenho dos sprites na tela
  189.   #--------------------------------------------------------------------------
  190.   def draw_sprites
  191.     return unless @data
  192.     @sprite.bitmap.clear
  193.     return if @data.xsize <= 0 || @data.ysize <= 0
  194.     for y in 0...@data.ysize
  195.       for x in 0...@data.xsize
  196.         catch(:draw) do
  197.           # Desenho do bloco de chão/parede
  198.           tile_id = data[x, y, 0]
  199.           id = tileA5(tile_id)
  200.           if id > 0 && id <= 128
  201.             region = region_id(x, y)
  202.             draw_block(x, y, id, $view_behind ? char_hidden?(x, y, region) : false)
  203.           end
  204.          
  205.           # Desenho dos tiles B-E (Abaixo do personagem)
  206.           tile_id = data[x, y, 2]
  207.           if (tile_id || 0) >= 0 && flags[tile_id] & 0x0010 == 0      
  208.             draw_second_layer(x, y, tile_id)
  209.           end
  210.          
  211.           # Desenho dos chars
  212.           @characters.select do |spr|
  213.             spr.visible && spr.character.real_x.ceil == x &&
  214.             spr.character.real_y.ceil == y
  215.           end.each do |spr|
  216.             draw_character(spr)
  217.           end
  218.          
  219.           # Desenho dos tiles B-E (Acima do personagem)
  220.           if (tile_id || 0) <= 0 || flags[tile_id] & 0x0010 == 0
  221.             next
  222.           else
  223.             draw_second_layer(x, y, tile_id)
  224.           end
  225.         end
  226.       end
  227.     end
  228.   end
  229.  
  230.   #--------------------------------------------------------------------------
  231.   # * Ajuste das coordenadas
  232.   #     x : Coordenada X
  233.   #     y : Coordenada Y
  234.   #--------------------------------------------------------------------------
  235.   def adjust_xy(x, y)
  236.     [x - self.ox - 32, y - self.oy + (MAX_HEIGHT + 1) * 32]
  237.   end
  238.  
  239.   #--------------------------------------------------------------------------
  240.   # * Desenho de um bloco de tile na tela
  241.   #     a          : Coordenada X
  242.   #     y          : Coordenada Y
  243.   #     id         : ID do tile
  244.   #     translucid : Se o tile será semi-transparente ou não
  245.   #--------------------------------------------------------------------------
  246.   def draw_block(a, b, id, translucid=false)
  247.     return if id <= 0
  248.     # Retângulo do bloco no tileset
  249.     rect = Rect.new((id % 8) * 64, (id / 8) * 64, 64, 64)
  250.    
  251.     # Coordenadas
  252.     x = (a - b) * 32
  253.     y = (a + b) * 16
  254.     x, y = *adjust_xy(x, y)
  255.    
  256.     # Altura do bloco
  257.     height = region_id(a, b)
  258.    
  259.     # Interrompe o desenho se estiver fora da tela
  260.     return if x < -64 || y < -64
  261.     if x >= Graphics.width || (y - MAX_HEIGHT * 32 - 32) >= Graphics.height
  262.       throw(:draw)
  263.     end
  264.  
  265.     # Desenho do bloco
  266.     @sprite.bitmap.blt(x, y, @tileset, rect)
  267.     for h in 1..height
  268.       @sprite.bitmap.blt(x, y - h * 32, @tileset, rect, translucid ? 50 : 255)
  269.     end
  270.   end
  271.  
  272.   #--------------------------------------------------------------------------
  273.   # * Desenho de um tile da segunda camada na tela
  274.   #--------------------------------------------------------------------------
  275.   def draw_second_layer(a, b, tile_id)
  276.    
  277.     # Valores do tile
  278.     id = tile_id % 0x100                     # ID do tile
  279.     lt = tile_id / 0x100                     # Tileset (0-4)
  280.     tt = (@flags[tile_id] & 0xf000) / 0x1000 # Tag de terreno do tile (0-7)
  281.     height = (data[a, b + tt, 3] >> 8) % (MAX_HEIGHT + 1) # Altura do tile
  282.    
  283.     # Alistamento do tile para desenho posterior
  284.     if tt > 0 && @todraw[a, b+tt, tt-1] != tile_id
  285.       @todraw[a, b+tt, tt-1] = tile_id
  286.       return
  287.     end
  288.    
  289.     # Desenho dos tiles alistados
  290.     for i in 0...7
  291.       if @todraw[a, b, i] > 0
  292.         draw_second_layer(a, b-i-1, @todraw[a, b, i])
  293.         @todraw[a, b, i] = 0
  294.       end
  295.     end
  296.    
  297.     # Bitmap do tileset
  298.     bmp = @bitmaps[5 + lt]
  299.    
  300.     # Coordenadas
  301.     a -= tt
  302.     x = (a - b) * 32
  303.     y = (a + b) * 16
  304.     x, y = *adjust_xy(x, y)
  305.    
  306.     # Retângulo do tile
  307.     if id < 128
  308.       rect = Rect.new((id % 8) * 32, (id / 8) * 32, 32, 32)
  309.     else
  310.       id -= 128
  311.       rect = Rect.new((id % 8) * 32 + 256, (id / 8) * 32, 32, 32)
  312.     end
  313.    
  314.     # Desenho do tile
  315.     @sprite.bitmap.blt(x + 16, y - 8 - height * 32, bmp, rect)
  316.   end
  317.  
  318.   #--------------------------------------------------------------------------
  319.   # * Desenho de um char na tela
  320.   #--------------------------------------------------------------------------
  321.   def draw_character(sprite)
  322.     return unless sprite.is_a?(Sprite_Character)
  323.     # Coordenadas
  324.     x, y = *adjust_xy(sprite.x - sprite.ox, sprite.y - sprite.oy)
  325.    
  326.     return if x < -64 || y < -64 || x >= Graphics.width || (y - sprite.src_rect.height) >= Graphics.height
  327.    
  328.     # Desenho do char
  329.     @sprite.bitmap.blt(x, y, sprite.bitmap, sprite.src_rect)
  330.   end
  331.  
  332.   #--------------------------------------------------------------------------
  333.   # * Disposição do objeto
  334.   #--------------------------------------------------------------------------
  335.   def dispose
  336.     @sprite.dispose
  337.   end
  338. end
  339.  
  340. #==============================================================================
  341. # * Game_CharacterBase
  342. #------------------------------------------------------------------------------
  343. # Aqui são feitas as modificações nos characters para corrigir a posição na
  344. # tela e ajustar o movimento diagonal
  345. #==============================================================================
  346. class Game_CharacterBase
  347.   #--------------------------------------------------------------------------
  348.   # Alias
  349.   #--------------------------------------------------------------------------
  350.   alias mbsisomovediagonal move_diagonal
  351.   alias mbsisomovestraight move_straight
  352.   alias mbsisomappassable map_passable?
  353.   alias mbsisoscreenx screen_x
  354.   alias mbsisoscreeny screen_y
  355.   alias mbsisoshifty shift_y
  356.   alias mbsisoopacity opacity
  357.  
  358.   #--------------------------------------------------------------------------
  359.   # * Definição de coordenada X na tela
  360.   #--------------------------------------------------------------------------
  361.   def screen_x
  362.     return (@real_x - @real_y + 1) * 32 if $game_map.isometric?
  363.     mbsisoscreenx
  364.   end
  365.   #--------------------------------------------------------------------------
  366.   # * Definição de coordenada Y na tela
  367.   #--------------------------------------------------------------------------
  368.   def screen_y
  369.     if $game_map.isometric?
  370.       return (@real_x + @real_y + 1) * 16 - shift_y - jump_height - region_height
  371.     end
  372.     mbsisoscreeny
  373.   end
  374.  
  375.   #--------------------------------------------------------------------------
  376.   # * Aquisição da altura do char de acordo com a região
  377.   #--------------------------------------------------------------------------
  378.   def region_height
  379.     (region_id % (MBS::Isometric::MAX_HEIGHT + 1)) * 32
  380.   end
  381.  
  382.   #--------------------------------------------------------------------------
  383.   # * Aquisição da mudança de posição sobre tile
  384.   #--------------------------------------------------------------------------
  385.   def shift_y
  386.     return 0 if $game_map.isometric?
  387.     mbsisoshifty
  388.   end
  389.  
  390.   #--------------------------------------------------------------------------
  391.   # * Aquisição da opacidade do char
  392.   #--------------------------------------------------------------------------
  393.   def opacity
  394.     return 0 if $game_map.isometric?
  395.     mbsisoopacity
  396.   end
  397.  
  398.   #--------------------------------------------------------------------------
  399.   # * Movimento na diagonal
  400.   #     horz : Direção horizontal (4 ou 6)
  401.   #     vert : Direção vertical (2 ou 8)
  402.   #--------------------------------------------------------------------------
  403.   def move_diagonal(horz, vert)
  404.     # Ajuste de velocidade
  405.     if $game_map.isometric?
  406.       if (horz == 4 && vert == 2) || (horz == 6 && vert == 8)
  407.         unless @dsa
  408.           @move_speed /= 1.25
  409.           @dsa = true
  410.         end
  411.       elsif @dsa
  412.         @move_speed *= 1.25
  413.         @dsa = false
  414.       end
  415.     end
  416.     mbsisomovediagonal(horz, vert)
  417.   end
  418.  
  419.   #--------------------------------------------------------------------------
  420.   # * Movimento em linha reta
  421.   #--------------------------------------------------------------------------
  422.   def move_straight(*args)
  423.     # Ajuste de velocidade
  424.     if @dsa
  425.       @move_speed *= 1.25
  426.       @dsa = false
  427.     end
  428.     mbsisomovestraight(*args)
  429.   end
  430.  
  431.   #--------------------------------------------------------------------------
  432.   # * Aquisição da diferença entre as regiões do character e do tile XY no
  433.   #   mapa
  434.   #     x : coordenada X
  435.   #     y : coordenada Y
  436.   #--------------------------------------------------------------------------
  437.   def region_difference(x, y)
  438.     mh = MBS::Isometric::MAX_HEIGHT
  439.     (($game_map.region_id(x, y) % (mh + 1)) - (region_id % (mh + 1))).abs
  440.   end
  441.  
  442.   #--------------------------------------------------------------------------
  443.   # * Definição de passagem no mapa
  444.   #     x : coordenada X
  445.   #     y : coordenada Y
  446.   #     d : direção (2,4,6,8)
  447.   #--------------------------------------------------------------------------
  448.   def map_passable?(x, y, d)
  449.     if $game_map.isometric?
  450.       return mbsisomappassable(x, y, d) && region_difference(x, y) < 2
  451.     end
  452.     mbsisomappassable(x, y, d)
  453.   end
  454. end
  455.  
  456. #==============================================================================
  457. # ** Game_Map
  458. #------------------------------------------------------------------------------
  459. # Aqui são feitas as modificações para evitar que a tela mude de posição
  460. #==============================================================================
  461. class Game_Map  
  462.   #--------------------------------------------------------------------------
  463.   # Alias
  464.   #--------------------------------------------------------------------------
  465.   alias mbsisosetdisplaypos set_display_pos
  466.  
  467.   #--------------------------------------------------------------------------
  468.   # * Definir a posição de exibição
  469.   #     x : coordenada X de exibição
  470.   #     y : coordenada Y de exibição
  471.   #--------------------------------------------------------------------------
  472.   def set_display_pos(x, y)
  473.     if isometric?
  474.       @parallax_x = x
  475.       @parallax_y = y
  476.     else
  477.       mbsisosetdisplaypos(x, y)
  478.     end
  479.   end
  480.  
  481.   #--------------------------------------------------------------------------
  482.   # * Verificação de se o mapa é isométrico
  483.   #--------------------------------------------------------------------------
  484.   def isometric?
  485.     !@map.note[MBS::Isometric::ISO_TAG].nil?
  486.   end
  487. end
  488.  
  489. #==============================================================================
  490. # ** Game_Player
  491. #------------------------------------------------------------------------------
  492. # Aqui são feitas as modificações para evitar que a tela mude de posição e para
  493. # o movimento diagonal
  494. #==============================================================================
  495. class Game_Player < Game_Character
  496.   #--------------------------------------------------------------------------
  497.   # Alias
  498.   #--------------------------------------------------------------------------
  499.   alias mbsisoupdatescroll update_scroll
  500.  
  501.   #--------------------------------------------------------------------------
  502.   # * Atualização da rolagem
  503.   #     last_real_x : ultima coordenada X real
  504.   #     last_real_y : ultima coordenada Y real
  505.   #--------------------------------------------------------------------------
  506.   def update_scroll(*args)
  507.     return if $game_map.isometric?
  508.     mbsisoupdatescroll(*args)
  509.   end
  510.  
  511.   #--------------------------------------------------------------------------
  512.   # Movimento diagonal
  513.   #--------------------------------------------------------------------------
  514.   if MBS::Isometric::DIR8
  515.     #------------------------------------------------------------------------
  516.     # * Processamento de movimento através de pressionar tecla
  517.     #------------------------------------------------------------------------
  518.     def move_by_input
  519.       return if !movable? || $game_map.interpreter.running?
  520.       case Input.dir8
  521.       when 1 # Esquerda-cima
  522.         @direction = 4
  523.         move_diagonal(4,2)
  524.       when 2 # Cima
  525.         move_straight(2)
  526.       when 3 # Direita-cima
  527.         @direction = 2
  528.         move_diagonal(6,2)
  529.       when 4 # Esquerda
  530.         move_straight(4)
  531.       when 6 # Direita
  532.         move_straight(6)
  533.       when 7 # Esquerda-baixo
  534.         @direction = 8
  535.         move_diagonal(4,8)
  536.       when 8 # Baixo
  537.         move_straight(8)
  538.       when 9 # Direita-baixo
  539.         @direction = 6
  540.         move_diagonal(6,8)
  541.       end
  542.     end
  543.   end
  544. end
  545.  
  546. #==============================================================================
  547. # ** Spriteset_Map
  548. #------------------------------------------------------------------------------
  549. # Aqui são feitas as modificações nos sprites do mapa para se mostrar o Isomap
  550. # e não o Tilemap
  551. #==============================================================================
  552. class Spriteset_Map
  553.   #--------------------------------------------------------------------------
  554.   # * Alias
  555.   #--------------------------------------------------------------------------
  556.   alias mbsisoinitialize initialize
  557.   alias mbsisoloadtileset load_tileset
  558.   alias mbsisoupdatetilemap update_tilemap
  559.   alias mbsisocreatetilemap create_tilemap
  560.  
  561.   #--------------------------------------------------------------------------
  562.   # * Inicialização do objeto
  563.   #--------------------------------------------------------------------------
  564.   def initialize(*args)
  565.     mbsisoinitialize(*args)
  566.   end
  567.  
  568.   #--------------------------------------------------------------------------
  569.   # * Criação do tilemap
  570.   #--------------------------------------------------------------------------
  571.   def create_tilemap
  572.     mbsisocreatetilemap
  573.     setup_tilemap
  574.   end
  575.  
  576.   #--------------------------------------------------------------------------
  577.   # * Configuração do tilemap
  578.   #--------------------------------------------------------------------------
  579.   def setup_tilemap
  580.     if @tilemap.is_a?(Tilemap) && $game_map.isometric?
  581.       @tilemap = Isomap.new(@viewport1)
  582.       load_tileset
  583.     elsif @tilemap.is_a?(Isomap) && !$game_map.isometric?
  584.       mbsisocreatetilemap
  585.     end
  586.   end
  587.  
  588.   #--------------------------------------------------------------------------
  589.   # * Atualização do tilemap
  590.   #--------------------------------------------------------------------------
  591.   def update_tilemap
  592.     setup_tilemap
  593.     if @tilemap.is_a?(Isomap)
  594.       @tilemap.data = $game_map.data
  595.       @tilemap.characters = @character_sprites
  596.       @tilemap.ox = $game_player.screen_x - Graphics.width / 2 + $game_map.display_x * 32
  597.       @tilemap.oy = $game_player.screen_y - Graphics.height / 2 + (MBS::Isometric::MAX_HEIGHT + 1) * 32 + $game_map.display_y * 16
  598.       @tilemap.update
  599.     else
  600.       mbsisoupdatetilemap
  601.     end
  602.   end
  603.  
  604.   #--------------------------------------------------------------------------
  605.   # * Carregamento dos tilesets
  606.   #--------------------------------------------------------------------------
  607.   def load_tileset
  608.     mbsisoloadtileset
  609.     @tilemap.tileset = @tileset.name if @tilemap.is_a?(Isomap)
  610.   end
  611.  
  612.   #--------------------------------------------------------------------------
  613.   # * Disposição do tilemap
  614.   #--------------------------------------------------------------------------
  615.   def dispose_tilemap
  616.     @tilemap.dispose
  617.   end
  618. end
Advertisement
Add Comment
Please, Sign In to add comment