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

Aulas de Ruby

Iniciado por Sotelie, 24/02/2017 às 02:11

Aula 22 lançada.

14/05/2017 às 11:27 #91 Última edição: 14/05/2017 às 15:22 por Corvo
Ae, agora entendo como funciona esse negócio que vivo cortando do menu. :malvado:

MDS, Alisson, você não sabe o QUANTO me ajuda.
Suas aulas são incríveis, cara!
Quem sabe, algum dia eu migre dos eventos para a terra dos códigos...
~Obrigado por dispor essas belezuras, sensei
^^

É ótimo saber que estão sendo de ajuda :)
E agora que tu sabe esse treco, cê já pode burlar os comandos do menu, Poe e.e

23/05/2017 às 23:39 #94 Última edição: 24/05/2017 às 01:29 por Alisson
Aula 23, com suas duas partes lançadas.
Abaixo estarão alguns códigos de exemplo juntamente do código que usamos na aula.

Código da aula
class Test_Scene < Scene_Base
  
  def start
    super
    @background = Sprite.new
    @background.bitmap = SceneManager.background_bitmap
    @my_select = My_Select.new(0, 0, 300, 200)
  end
  
end

class My_Select < Window_Selectable
  
  def initialize(x, y, width, height)
    make_command_list
    super
    draw_commands
    activate
    select(0)
  end
  
  def make_command_list
    @list = []
    commands = ["Select Me", "I am the chosen one", "Use my protag powers"]
    for i in 0...commands.size
      @list.push(commands[i])
    end
  end
  
  def draw_commands
    for i in 0...@list.size
      rect = item_rect(i)
      self.draw_text(rect, @list[i])
    end
  end
  
  def update
    super
    if Input.trigger?(:C) && self.active
      Sound.play_ok
      p @list[index]
    end
  end
  
  def item_max
    return @list.nil? ? 0 : @list.size
  end
  
end
[close]

Exemplo com ícones
class Test_Scene < Scene_Base
  
  def start
    super
    @background = Sprite.new
    @background.bitmap = SceneManager.background_bitmap
    @my_select = My_Select.new(0, 0, 300, 200)
  end
  
end

class My_Select < Window_Selectable
  
  def initialize(x, y, width, height)
    make_command_list
    super
    draw_commands
    activate
    select(0)
  end
  
  def make_command_list
    @list = []
    @icons = [] # Criando um depósito de ícones apenas como exemplo.
    commands = ["Select Me", "I am the chosen one", "Use my protag powers"]
     # Vamos criar uma array de ícones de exemplo.
    icons = [18, 39, 64] # Vamos usar apenas o index dos ícones no iconset.
    for i in 0...commands.size
      @list.push(commands[i])
      @icons.push(icons[i]) # Vamos adicionar os ícones no depósito de ícones.
    end
  end
  
  def draw_commands
    for i in 0...@list.size
      rect = item_rect(i)
      self.draw_icon(@icons[i], rect.x, rect.y) # Vamos desenhar os ícones.
      rect.x += 24 # Vamos afastar o texto 24 pixels para a direita.
      self.draw_text(rect, @list[i])
    end
  end
  
  def update
    super
    if Input.trigger?(:C) && self.active
      Sound.play_ok
      p @list[index]
    end
  end
  
  def item_max
    return @list.nil? ? 0 : @list.size
  end
  
end
[close]

Exemplo usando apenas ícones
class Test_Scene < Scene_Base
  
  def start
    super
    @background = Sprite.new
    @background.bitmap = SceneManager.background_bitmap
    @my_select = My_Select.new(0, 0, 300, 200)
  end
  
end

class My_Select < Window_Selectable
  
  def initialize(x, y, width, height)
    make_command_list
    super
    draw_commands
    activate
    select(0)
  end
  
  def make_command_list
    @list = []
    @icons = [] # Criando um depósito de ícones apenas como exemplo.
    commands = ["Select Me", "I am the chosen one", "Use my protag powers"]
     # Vamos criar uma array de ícones de exemplo.
    icons = [18, 39, 64] # Vamos usar apenas o index dos ícones no iconset.
    for i in 0...commands.size
      @list.push(commands[i])
      @icons.push(icons[i]) # Vamos adicionar os ícones no depósito de ícones.
    end
  end
  
  def draw_commands # Aqui nós vamos desenhar apenas os ícones.
    for i in 0...@list.size
      rect = item_rect(i)
      self.draw_icon(@icons[i], rect.x, rect.y) # Vamos desenhar os ícones.
    end
  end
  
  def item_width # A largura de uma seleção na janela.
    return 24
  end
  
  def line_height # A altura de uma linha na janela.
    return 24
  end
  
  def spacing # O espaço entre os itens horizontais na janela.
    return 4
  end
  
  def col_max # O número máximo de colunas na janela.
    return 2
  end
  
  def update
    super
    if Input.trigger?(:C) && self.active
      Sound.play_ok
      p @list[index]
    end
  end
  
  def item_max
    return @list.nil? ? 0 : @list.size
  end
  
end
[close]

Opa, mais uma. Só fiquei com uma dúvida tosca aqui. O comando que você usou para o background usa - automaticamente - a windowskin, certo? O que eu faria para incluir uma imagem? Exemplo: em uma árvore de habilidades, a posição de cada ícone está de acordo com a imagem de fundo. Tipo aquele plugin que o [user]King Gerar[/user] fez há*(?) um tempo.

No caso de mostrar cada ícone de acordo com a imagem de fundo, você precisaria determinar explicitamente  as coordenadas que eles apareceriam. Eu recomendaria criar um módulo de configuração, e nele colocar os ícones + as coordenadas, e usar os valores para desenhar cada ícone. Ex:
icons = [ [32, 28, 120], [64, 20, 19] ] # [ [index, x, y], [index, x, y] ]
for i in 0...icons.size
    self.draw_icon(icons[i][0], icons[i][1], icons[i][2])
end

Esse aí foi um exemplo usando arrays, mas eu prefiro usar hash para esse caso. Ex:
icons = [ {:index => 32, :x => 28, :y => 120}, {:index => 64, :x => 20, :y => 19} ]
for i in 0...icons.size
    self.draw_icon(icons[i][:index], icons[i][:x], icons[i][:y])
end


\o/

Aula 24 lançada.

O sprite utilizado na aula pode ser obtido aqui:
Spoiler
[close]

Muito interessante  :sera:
No caso dos charsets normais, é preciso definir quando uma linha de frames termina? Ou isso é automático? Tipo, são três para cada direção - ou não, dependendo do sprite. É preciso definir que a linha de baixo pertence ao mesmo sprite, ou essa separação não faz diferença?

No caso dos charsets, toda vez que você muda de direção, o que muda no src_rect é a posição y, os frames horizontais continuam animando usando o src_rect.
E não seria necessário definir o número de frames na horizontal, basta você pegar a largura e dividir pelo tamanho de 1 frame.
No caso: 32 * 3 = 96 (três frames de 32 na horizontal é 96, o que seria a largura do bitmap).
96 / 32 = 3 (são três frames na horizontal), então usando este tipo de cálculo você faz um negócio automático, haha. É basicamente o que eles fazem com os iconsets.

Aula 25 lançada. Ela é uma aula rápida sobre um conceito que estaremos precisando na próxima aula.

Opa! Pergunta idiota antes de começarmos a usar 'se'troço. As :keys funcionam, basicamente, como um Label dos eventos? Digo, um marcador?

As keys funcionam de forma parecida com as labels, mas elas são usadas como identificadores.
Ao contrário das arrays, as hashes precisam de keys, ou identificadores para guardarem seus valores. E para acessar um conteúdo específico da hash, é necessário indicar a key ou o identificador do conteúdo que você quer.

É como uma biblioteca. Para acessar o conteúdo de um livro seria necessário saber o nome do livro.

Aula 26 lançada com sucesso.
Vocês podem checar o código que utilizamos na aula logo abaixo, com alguns comentários a mais:

#===============================================================================
# Módulo de Configuração
#===============================================================================
module SoundTestConfig

    #---------------------------------------------------------------------------
    # Lista de músicas.
    #---------------------------------------------------------------------------
    Sounds = {
        :battle1 => {
            :name => "Battle1",
            :author => "Enterbrain, i guess...",
            :description => "Just a battle theme.\nFor the lolz."
        },
        :battle2 => {
            :name => "Battle2",
            :author => "Hmm... Enterbrain?",
            :description => "Testing this\nthing."
        }
    }

    #---------------------------------------------------------------------------
    # Controle do volume e tom das músicas.
    #---------------------------------------------------------------------------
    Sound_Volume = 100
    Sound_Pitch = 100

end

#===============================================================================
# Resto do código
#===============================================================================
class Sound_Test < Scene_Base

    #---------------------------------------------------------------------------
    # Inicialização da cena.
    #---------------------------------------------------------------------------
    def start
        super
        @map_bgm = RPG::BGM.last
        RPG::BGM.fade(1000)
        @background = Sprite.new
        @background.bitmap = SceneManager.background_bitmap
        @help_window = Sound_Test_Help.new
        @sound_list_window = Sound_List.new(0, 0, Graphics.width * 0.5, Graphics.height - @help_window.height)
        @description_window = Sound_Test_Description.new(@sound_list_window.x + @sound_list_window.width, 0, Graphics.width * 0.5, Graphics.height - @help_window.height)
        refresh_author
        refresh_description
    end

    #---------------------------------------------------------------------------
    # Atualização do nome do autor.
    #---------------------------------------------------------------------------
    def refresh_author
        return unless @sound_list_window.current_item
        @help_window.contents.clear
        @help_window.draw_text_ex(0, 0, @sound_list_window.current_item[:author])
    end

    #---------------------------------------------------------------------------
    # Atualização da descrição.
    #---------------------------------------------------------------------------
    def refresh_description
        return unless @sound_list_window.current_item
        @description_window.contents.clear
        @description_window.draw_text_ex(0, 0, @sound_list_window.current_item[:description])
    end

    #---------------------------------------------------------------------------
    # Atualização geral da cena (atualização de frames).
    #---------------------------------------------------------------------------
    def update
        cs = @sound_list_window.current_item
        super
        refresh_author if cs != @sound_list_window.current_item
        refresh_description if cs != @sound_list_window.current_item
        if Input.trigger?(:C)
            if @sound_list_window.current_item
                RPG::BGM.new(@sound_list_window.current_item[:name], Sound_Volume, Sound_Pitch).play
            end
        end
        if Input.trigger?(:B)
            SceneManager.return
        end
    end

    #---------------------------------------------------------------------------
    # Finalização da cena.
    #---------------------------------------------------------------------------
    def terminate
        super
        @map_bgm.play(@map_bgm.pos)
    end

end

#===============================================================================
# Eu prefiro usar a Window_Selectable pois tenho mais liberdade e controle
# sobre meus comandos. Posso desenhar ícones, e o que for nela livremente.
# Mas caso você ainda não esteja conseguindo usar a selectable, pode usar
# a Window_Command no lugar (embora eu ainda recomende a selectable).
#===============================================================================
class Sound_List < Window_Selectable
    include SoundTestConfig

    #---------------------------------------------------------------------------
    # Inicialização da janela.
    #---------------------------------------------------------------------------
    def initialize(x, y, width, height)
        @list = []
        make_command_list
        super
        draw_commands
        select(0)
        activate
    end

    #---------------------------------------------------------------------------
    # Criação dos comandos.
    #---------------------------------------------------------------------------
    def make_command_list
        Sound.each_pair do |key, sound|
            @list.push(sound) if $game_system.unlocked_sounds[key]
        end
    end
    
    #---------------------------------------------------------------------------
    # Desenho dos comandos.
    #---------------------------------------------------------------------------
    def draw_commands
        for i in 0...@list.size
            rect = item_rect_for_text(i)
            draw_text(rect.x, rect.y, rect.width, rect.height, @list[i][:name])
        end
    end
    
    #---------------------------------------------------------------------------
    # O item atualmente selecionado.
    #---------------------------------------------------------------------------
    def current_item
        return @list[index]
    end
    
    #---------------------------------------------------------------------------
    # Número máximo de itens da janela.
    #---------------------------------------------------------------------------
    def item_max
        return @list.size
    end

end

class Sound_Test_Help < Window_Base

    #---------------------------------------------------------------------------
    # Inicialização da janela.
    #---------------------------------------------------------------------------
    def initialize(x = 0, y = Graphics.height - fitting_height(2), width = Graphics.width, height = fitting_height(2))
        super
    end

end

class Sound_Test_Description < Window_Base

    #---------------------------------------------------------------------------
    # Inicialização da janela.
    # Como o método é idêntico ao da window_base, sem nenhum parâmetro com
    # valores padrões (veja a Sound_Test_Help acima), você pode até deletar
    # esse initialize que não faz diferença alguma :T Só adicionei pois em
    # minha mente eu ia colocar alguma coisa nele, mas bah'
    #---------------------------------------------------------------------------
    def initialize(x, y, width, height)
        super
    end

end

#===============================================================================
# Aqui é onde nós vamos nos encarregar de adicionar comandos no Game_Interpreter
# (basicamente os comandos de chamar script).
#===============================================================================
class Game_Interpreter

    #---------------------------------------------------------------------------
    # Desbloqueio de sons.
    # O uso do * no primeiro argumento indica que você pode passar quantos
    # parâmetros você quiser, que ele vai ler todos eles e guardá-los em
    # uma array.
    # No caso, sounds é uma array dos parâmetros que você inseriu.
    #---------------------------------------------------------------------------
    def unlock_sounds(*sounds)
        for s in sounds
            $game_system.unlocked_sounds[s] = true
        end
    end

    #---------------------------------------------------------------------------
    # Bloqueio de sons.
    # Mesma coisa da descrição acima.
    #---------------------------------------------------------------------------
    def lock_sounds(*sounds)
        for s in sounds
            $game_system.unlocked_sounds[s] = false
        end
    end

end

#===============================================================================
# Aqui que nos encarregamos de criar uma variável que será salva com o jogo.
# Como a variável $game_system é global, podemos chamar suas instâncias
# em qualquer lugar. Sem falar que qualquer instância que for salva na
# $game_system será salva com o jogo.
# Porém note que, você não pode salvar nenhuma imagem (Sprite/Bitmap/Viewport)
# dentro do $game_system, visto que ele dará erro e provavelmente corromperá
# o save do jogador.
# Caso você salve uma classe dentro do $game_system, tenha certeza de que
# não exista nenhuma imagem dentro da sua classe também, pois vai dar o
# mesmo problema.
#===============================================================================
class Game_System

    #---------------------------------------------------------------------------
    # Poderemos ler, e apenas ler a variável unlocked_sounds usando
    # $game_system.unlocked_sounds.
    #---------------------------------------------------------------------------
    attr_reader :unlocked_sounds

    #---------------------------------------------------------------------------
    # Aqui nós criamos a variável de antemão no initialize.
    # Ela será uma hash.
    # Assim que o $game_system for iniciado pelo RPG Maker, nossa variável
    # será iniciada junta com todas as outras do $game_system.
    #---------------------------------------------------------------------------
    alias :sound_test_init :initialize
    def initialize
        sound_test_init
        @unlocked_sounds = {}
    end

end

[user]Alisson[/user], meu jovem. Esta é a melhor aula até agora. Ver um sistema sendo criado do zero é bem mais prático que passar por toda a teoria. Claro, sem ela ninguém ia entender nada, mas deu para entender. Enfim, dessa vez não fiquei com nenhuma dúvida e aprendi muita coisa. Até perdoo seus erros.   :U_U: