O TEMA DO FÓRUM ESTÁ EM MANUTENÇÃO. FEEDBACKS AQUI: ACESSAR

Script 3D

Iniciado por Avenger_B7, 15/11/2013 às 11:23

15/11/2013 às 11:23 Última edição: 20/01/2017 às 10:03 por King Gerar
[box class=catbg]Introdução:[/box]
[box class=randomquote]
Eu estou navegando pelo youtube à procura de tutoriais e encontro esse maravilhoso script em 3D.   
[/box]


[box class=catbg]Características:[/box]
[box class=randomquote]- Script para criar uma plataforma 3D.
[/box]

[box class=catbg]Como usar:[/box]
[box class=randomquote]- Cole acima do Main[/box]

[box class=catbg]Script:[/box]
[box class=randomquote]
Código: ruby
=begin
add the following commands to the map name
[m7]  -  Use m7 on this Map. If omitted, standard tilemap will be used
[#XX] -  XX = Value between 89 and 0. Sets the angle of slant
[-X]  -  X = 1 or 0     if X = 1, hide vertical walls if the backside would
                        be visible
if [#XX] or [-X] are omitted, the last setting will be used

by Shining Advances
=end
class Game_System
  alias initialize_m7 initialize
  
  attr_reader :factor
  attr_reader :correct
  
  attr_reader :scroll_y
  attr_reader :distance
  attr_reader :angle
  attr_reader :height
  attr_reader :columns
  attr_reader :filter
  
  attr_accessor :hidewalls
  attr_accessor :hide
  attr_accessor :new_angle
  attr_accessor :need_refresh
  def initialize
    initialize_m7
    
    @scroll_y = 256#distance of the camera to the player
    @height = 1  #the height of the ground sprites
    #increasing this value increases the performance slightly
    #however values > 2 will let the ground look unneatly in the distance
    @columns = 16 #the amount of sprites for 1 vertical wall
    #set to 8 or 16
    #8 will increase the performance greatly, but at cost of the quality
    @filter = 2*32#the filter skips ~every 3 vertical frame within
    #the given range. setting @filter to zero will deactivate the filter
    @hidewalls = 1
    # 1 -> hides vertical walls if the backside would be visible
    # 0 -> show the vertical walls
    @distance = 480 #the focus
    #higher values will let the vertical walls be more parallel
    @hide = 90#if distance of a wall's and the player's y-coord is between
    #1 and @hide, the wall will become transparent
    self.angle = 45 #take a guess which angle is meant ._.
    #each of these values can be changed with an call script:
    #$game_system.*attribute* = value
    #example:
    #$game_system.height = 2
    
    
    @new_angle = false#internal use. do not change
    @need_refresh = false
  end
  
  #central projection formulas based on MGCaladtogel's Neo Mode07 Script
  
  def screen2m7_y(y)
    #calcs old screen_y to new screen_y
    return @scroll_y + (@cd * y) / (@distance - y * @sinus)
  end
  
  def screen2map_y(y)
    #calcs new screen_y to map_y (y*32)
    return @distance * (@scroll_y - y) /
      (@dif - y * @sinus) + @scroll_y
  end
  
  def screen2zoom(y)
    return (y * @factor + @correct)
  end
  
  def angle=(n)
    @angle = n
    @cosinus = Math.cos(Math::PI * (@angle / 180.0))
    @sinus = Math.sin(Math::PI * (@angle / 180.0))
    @cd = @cosinus * @distance
    @ys = @scroll_y * @sinus
    @dif = @ys - @cd
    
    z0 = @distance / (@distance + @scroll_y * @sinus)
    h0 = (-@distance * @scroll_y * @cosinus) /
      (@distance + @scroll_y * @sinus) + @scroll_y
    @factor = (1.0 - z0) / (@scroll_y - h0)
    @correct = 1.0 - @scroll_y * @factor
    @new_angle = true
  end
  
  def distance=(n)
    @distance = n
    self.angle = @angle
  end
  
  def height=(n)
    @height = n
    @need_refresh = true
  end
  
  def columns=(n)
    @columns = n
    @need_refresh = true
  end
end

$data_maps = load_data("Data/MapInfos.rxdata")

class M7Tilemap
  attr_reader   :autotiles
  attr_accessor :tileset
  attr_accessor :priorities
  
  def initialize(vp)
    @viewport = vp
    @horizontal = {}  #hash that stores horizontal wall sprites
    @vertical = {}    #hash that stores vertical wall sprites
    @tileset = nil
    @map_data = nil
    @priorities = nil
    @bitmap = Bitmap.new(1,1) #bitmap that represents the map
    @sprites = []     #array that stores the ground sprites
    @autotiles = []
    refresh
  end
  
  def refresh
    #set tilemapsettings to globalsettings
    @height = $game_system.height
    @columns = $game_system.columns
    @scroll_y = $game_system.scroll_y
    @filter = $game_system.filter
    #set ox and oy to unnormal values to force refresh of sprite coordinates
    #see methods ox= oy=
    @ox = -1
    @oy = -1
    #dispose old sprites
    w = nil
    @sprites.each{ |w|
      w.dispose}
    @sprites = []
    #create new sprites
    for i in 0...(@scroll_y / @height)
      @sprites[i] = Sprite.new(@viewport)
      @sprites[i].y = i * @height
    end
    #skip every 2. sprite beyond @scroll_y to increase performance
    #it looks still the same because zoom > 1
    for i in (@scroll_y / @height)...(((480-@scroll_y) / 2 + @scroll_y) /
                                                                    @height)
      @sprites[i] = Sprite.new(@viewport)
      @sprites[i].y = i * @height * 2 - @scroll_y
    end
    @sprites.each {|w|
      w.zoom_x = $game_system.screen2zoom(w.y+1)
      if w.zoom_x > 1 #zoom < 1 could make a sprite with 1 pixel height disappear
        w.zoom_y = w.zoom_x
      end
      w.x = 320
    }
    unless @map_data.nil?
      #if there is no map_data (that means refresh is called for the first time)
      #-> create bitmap and sprites
      refresh_bitmap
    end
  end
  
  def terrain=(n)
    @terrain = n
  end
  
  def tileset=(bitmap)
    @tileset = bitmap
  end
  
  def ox=(n)
    return if @ox == n  #if ox didn't change, there is no need to render
    @ox = n
    dif = (@oy + @scroll_y) #calc difference once to increase performance
    ox = n + 320  #calc ox of the screen center once to increase performance
    #define local variables before loops to increase performance
    w = nil #sprites
    i = nil #index, key and y coord
    a = nil #ary of sprites
    z = nil #zoom
    erase = nil
    
    @sprites.each{ |w|
      w.ox = ox}  #scroll ground sprites to ox
      
    @horizontal.each{ |i, a|
      #calc zoom for all horizontal sprites on this y-achsis
      new_y = $game_system.screen2m7_y(i - dif)
      z = $game_system.screen2zoom(new_y)#a[0].y)
      #do this sprites need to be set on transparent?
      erase = (a[0].y - 256).between?(1,$game_system.hide)
      a.each{ |w|
        w.x = 320 + z * (w.map_x - ox)  #calc x coord
        if erase and 28 >= (ox - w.map_x).abs
          #if player is behind wall, make it transparent
          w.opacity = 100
        else
          w.opacity = 255
        end
      }
    }
    
    @vertical.each{ |i, a|
      #calc y-coord of sprites in ary a
      new_y = $game_system.screen2m7_y(i - dif)
      #calc z-coord of sprites in ary a
      z = $game_system.screen2zoom(new_y)
      #these sprites can be skipped if they are in filter range
      erase = (a[0].map_y % 6 != 0)
      a.each{ |w|
        #if sprites are in filter range, skip them
        if erase and (w.map_x - ox).abs < @filter
          w.jump = true     #mark sprite as skipped
          w.visible = false #make them invisible
          next
        end
        w.jump = false      #mark sprite as not skipped
        if w.visible
          #can sprite be skipped due to hidewalls setting?
          if w.visible = (ox*w.side >= w.map_x*w.side)
            w.x = 320 + z * (w.map_x - ox)
          end
        elsif w.visible = (ox*w.side >= w.map_x*w.side)
          #if sprites were invisible, they were skipped and have to be
          #fully new rendered -> set y-achsis too
          w.y = new_y
          w.x = 320 + z * (w.map_x - ox)
          w.zoom_y = z
        end
      }
    }
  end
  
  def oy=(n)
    return if @oy == n
    @oy = n
    ox320 = @ox + 320
    dif = (n + @scroll_y)
    w = nil #sprites
    i = nil #index, key and y coord
    a = nil #ary of sprites
    z = nil #zoom
    new_y = nil
    erase = nil
    
    @sprites.each{ |w|
      #which row of the ground bitmap does the sprite represent?
      w.src_rect.y = $game_system.screen2map_y(w.y+1).round + @oy
    }
    
    @horizontal.each{ |i, a|
      #same as in ox=
      new_y = $game_system.screen2m7_y(i - dif)
      z = $game_system.screen2zoom(new_y)
      erase = (a[0].y - 256).between?(1,$game_system.hide)
      a.each{ |w|
        w.y = new_y
        w.x = 320 + (z * (w.map_x - ox320))
        w.zoom_x = (w.zoom_y = z + 0.04)
        if erase and 28 >= (ox320 - w.map_x).abs
          w.opacity = 100
        else
          w.opacity = 255
        end
      }
    }
    
    @vertical.each{ |i, a| 
    new_y = $game_system.screen2m7_y(i - dif)
    z = $game_system.screen2zoom(new_y)
    a.each { |w|
      if w.visible
        w.y = new_y
        w.x = 320 + z * (w.map_x - ox320)
        w.zoom_y = z
      end
      }
    }
  end
  
  def map_data=(data)
    @map_data = data
    refresh_bitmap
  end
  
  def refresh_bitmap
    @terrain = $game_map.terrain_tags if @terrain.nil?
    #dispose old wall sprites
    @horizontal.each{ |i, c|
      c.each{ |w|
        w.dispose}}
    @vertical.each{ |i, c|
      c.each{ |w|
        w.dispose}}
    @horizontal.clear
    @vertical.clear
    
    @bitmap.dispose
    @bitmap = Bitmap.new(@map_data.xsize*32,@map_data.ysize*32)
    
    rect = Rect.new(0,0,32,32)
    source = Rect.new(0,0,32,32)
    i = 0
    x = 0
    y = 0
    z = 0
    data = nil
    wall = nil
    #create new ground bitmap/texture
    for x in 0...@map_data.xsize
      for y in 0...@map_data.ysize
        rect.x = x*32
        rect.y = y*32
        source.x = ((@map_data[x,y,0] - 384) % 8) * 32
        source.y = ((@map_data[x,y,0] - 384) / 8) * 32
        @bitmap.stretch_blt(rect,@tileset,source)
        #look for vertical and horizontal walls
        for z in 0..2
          data = @map_data[x,y,z]
          if @terrain[data] == 2  #if vertical wall
            if @terrain[@map_data[[x+1,@map_data.xsize-1].min,y,z].to_i] != 2
              #if next tile is ground -> need to display vertical wall
              #these are walls on the left side of the room
              for i in 0...@columns
                #split vertical wall into @columns sprites
                wall = SWall.new(@viewport,@columns)
                wall.map_x = x * 32 + 32
                wall.map_y = y * 32 + (@columns-i) * 32 / @columns
                wall.bitmap = @tileset
                wall.z = wall.map_y
                wall.side = 1 * $game_system.hidewalls
                wall.set_src(@terrain, data, i)
                wall.ox = 32 / @columns / 2 - 1
                #save walls with same y-coord into same array to
                #calc screen y coord for all these sprites at once
                #-> increases performance
                if @vertical.key?(wall.map_y)
                  @vertical[wall.map_y].push(wall)
                else
                  @vertical[wall.map_y] = [wall]
                end
              end
            end
            if @terrain[@map_data[[x-1,0].max,y,z].to_i] != 2
              #for comments see above
              #these are walls on the right side of the room
              for i in 0...@columns
                wall = SWall.new(@viewport,@columns)
                wall.map_x = x * 32
                wall.map_y = y * 32 + (@columns-i) * 32 / @columns
                wall.bitmap = @tileset
                wall.mirror = true
                wall.set_src(@terrain, data, i)
                wall.z = wall.map_y
                wall.side = -1 * $game_system.hidewalls
                wall.ox = 32 / @columns / 2
                if @vertical.key?(wall.map_y)
                  @vertical[wall.map_y].push(wall)
                else
                  @vertical[wall.map_y] = [wall]
                end
              end
            end
          end
          if @terrain[data] == 1 and #if horizontal wall
            (y+1 == @map_data.ysize or
              @map_data[x,y+1,z] != data + 8) #and next tile is no wall
            wall = Wall.new(@viewport,1,@map_data)
            wall.map_x = x * 32 + 16
            wall.map_y = y * 32 + 32 + 1
            wall.real_y = y
            wall.bitmap = @tileset
            wall.set_src(@terrain, data)
            wall.ox = 15
            wall.z = wall.map_y
            if @horizontal.key?(wall.map_y)
              @horizontal[wall.map_y].push(wall)
            else
              @horizontal[wall.map_y] = [wall]
            end
          end
        end
      end
    end
    #set scr_rect and ground bitmap/texture of the ground sprites
    for i in 0...@sprites.size
      @sprites[i].bitmap = @bitmap
      @sprites[i].src_rect.set(0,i,@bitmap.width,@height)
      if i >= @scroll_y / @height
        @sprites[i].src_rect.height *= 2
      end
    end
  end
  
  def update
    if $game_system.need_refresh
      $game_system.new_angle = false
      $game_system.need_refresh = false
      refresh
      return
    end
    if $game_system.new_angle
      #applies new zoom to ground sprites
      @sprites.each {|w|
      w.zoom_x = $game_system.screen2zoom(w.y+1)
        if w.zoom_x > 1
          w.zoom_y = w.zoom_x
        end
        w.x = 320
      }
      #changes ox/oy to force new rendering of walls
      x = @ox
      y = @oy
      @ox += 1
      @oy += 1
      self.ox = x
      self.oy = y
      $game_system.new_angle = false
    end
  end
  
  def dispose
    @horizontal.each{ |i, c|
      c.each{ |w|
        w.dispose}}
    @vertical.each{ |i, c|
      c.each{ |w|
        w.dispose}}
    @sprites.each{ |w|
        w.dispose}
    @bitmap.dispose
  end
end

class Wall < Sprite
  attr_accessor :map_x
  attr_accessor :map_y
  attr_accessor :real_y
  attr_accessor :side
  attr_accessor :jump
  attr_accessor :height
  def initialize(vp,spalten,data=nil)
    super(vp)
    @data = data
    @spalten = spalten
    @jump = false
    @real_y = 0
    @map_x = 0
    @map_y = 0
    @side = 0
    self.x = 320
    self.z = 100
    @blick = true
  end
  
  def set_src(terrain,tile,i=0)
    height = 1
    #calc height of the wall
    while terrain[tile - height * 8].to_i == 1
      height += 1
    end
    self.src_rect.set(
            ((tile % 8) * 32) + 32 / @spalten * i,
            ((tile - 384) / 8 - height + 1) * 32,
            32 / @spalten,
            32 * height)
    self.oy = height * 32 - 1
    @height = height
  end
end

class SWall < Wall
  def set_src(terrain,tile,i)
    super
    self.src_rect.height -= 32
    self.oy -= 32
  end
end

class Game_Map
  attr_reader :m7
  
  alias scroll_down_m7 scroll_down
  alias scroll_left_m7 scroll_left
  alias scroll_right_m7 scroll_right
  alias scroll_up_m7 scroll_up
  alias setup_m7 setup
  
  #don NOT stop scrolling anymore when end of map is reached
  def scroll_down(distance)
    if $game_map.m7
      @display_y += distance
    else
      scroll_down_m7(distance)
    end
  end
  
  def scroll_left(distance)
    if $game_map.m7
      @display_x -= distance
    else
      scroll_left_m7(distance)
    end
  end
  
  def scroll_right(distance)
    if $game_map.m7
      @display_x += distance
    else
      scroll_right_m7(distance)
    end
  end
  
  def scroll_up(distance)
    if $game_map.m7
      @display_y -= distance
    else
      scroll_up_m7(distance)
    end
  end
  
  def name
    return $data_maps[@map_id].name
  end
  
  def setup(id)
    setup_m7(id)
    @m7 = false
    for part in self.name.split("[")
      case part
      when /#(.*)\]/
        $game_system.angle = $1.to_i
      when "m7]"
        @m7 = true
      when /-(.*)\]/
        $game_system.hidewalls = $1.to_i
      end
    end
  end
end

class Game_Character
  alias screen_z_m7 screen_z
  def screen_z(height = 0)
    if $game_map.m7
      if @always_on_top
        return $game_map.height * 32 + 10
      end
      return @real_y / 4 + 33
    else
      screen_z_m7(height)
    end
  end
end

class Game_Player
  alias center_m7 center
  def center(x, y)
    if $game_map.m7
      $game_map.display_x = x * 128 - CENTER_X
      $game_map.display_y = y * 128 - CENTER_Y
    else
      center_m7(x, y)
    end
  end
end

class Sprite_Character
  #set event screen coords
  alias update_m7 update
  def update
    update_m7
    return unless $game_map.m7
    self.y = $game_system.screen2m7_y(self.y - $game_system.scroll_y)
    self.zoom_x = self.zoom_y = $game_system.screen2zoom(self.y)
    self.x = 320 + (self.zoom_x * (self.x - 320))
  end
end

class Spriteset_Map
  def initialize
    # Make viewports
    @viewport1 = Viewport.new(0, 0, 640, 480)
    @viewport2 = Viewport.new(0, 0, 640, 480)
    @viewport3 = Viewport.new(0, 0, 640, 480)
    @viewport2.z = 200
    @viewport3.z = 5000
    # Make tilemap
    if $game_map.m7
      @tilemap = M7Tilemap.new(@viewport1)
      @tilemap.terrain = $game_map.terrain_tags
    else
      @tilemap = Tilemap.new(@viewport1)
    end
    @tilemap.tileset = RPG::Cache.tileset($game_map.tileset_name)
    for i in 0..6
      autotile_name = $game_map.autotile_names[i]
      @tilemap.autotiles[i] = RPG::Cache.autotile(autotile_name)
    end
    @tilemap.map_data = $game_map.data
    @tilemap.priorities = $game_map.priorities
    # Make panorama plane
    @panorama = Plane.new(@viewport1)
    @panorama.z = -1000
    # Make fog plane
    @fog = Plane.new(@viewport1)
    @fog.z = 3000
    # Make character sprites
    @character_sprites = []
    for i in $game_map.events.keys.sort
      sprite = Sprite_Character.new(@viewport1, $game_map.events[i])
      @character_sprites.push(sprite)
    end
    @character_sprites.push(Sprite_Character.new(@viewport1, $game_player))
    # Make weather
    @weather = RPG::Weather.new(@viewport1)
    # Make picture sprites
    @picture_sprites = []
    for i in 1..50
      @picture_sprites.push(Sprite_Picture.new(@viewport2,
        $game_screen.pictures[i]))
    end
    # Make timer sprite
    @timer_sprite = Sprite_Timer.new
    # Frame update
    update
  end
end
[/box]

[box class=catbg]Multimídia:[/box]
[box class=randomquote]

[/box]

[box class=catbg]Download:[/box]
[box class=randomquote]Baixe a demo aqui
[/box]

[box class=catbg]Créditos:[/box]
[box class=randomquote]A Shining Advances pela criação do script.
[/box]
Unique Destiny | um novo conceito de RPG Maker 2000!

Já vi este script,é muito bom.
O único problema é que é muito dificil de usar,mesmo com o video guia que fizeram  :=|:

Entendo... Eu não sei modificá-lo nem pagando... Mas, relaxa, vou fazer um melhor e mais fácil. Aí você usa. (y)
Unique Destiny | um novo conceito de RPG Maker 2000!

Como eu disse nesse tópico, acho a ideia de um RPG Maker em 3D muito interessante apesar de reconhecer que deve dar bastante trabalho. Aproveitando que o DFTW está em curso, acho que seria bem legal se alguém usasse esse script para fazer um dungeon crawl. Com um pouco de habilidade deve dar um jogo e tanto. Enfim, tô enrolando de mais, valeu por divulgar Avenger!

Viva a lenda!




Olha só, esse eu não conhecia!

Já tinha visto um outro que não lembro o nome, mas aquele era meio ruim porque as paredes ficavam muito quadriculadas e tal, esse tem um angulo diferente e a parte legal é que as paredes ficam transparentes se estiverem sobrepostas ao personagem.

Deve dar um trabalho imenso, mas pra jogos curtos provavelmente da pra se usar com bons resultados.

é um sistema muito bom. embora eu não use mais o XP  eu baixei para dar uma olhada
ficaria legal com graficos  isométricos como o amigo ali de de cima, citou, isso me remete
muito ao MODE7 tambem que e um otimo sistema 3D otimo pra quem quer criar um jogo
com uma visão mais Ampla. Obrigado Por Compartilhar

Bem legal, vou tentar no meu novo jogo !