🎮 Tutorial de Jogo de Empilhamento de Torre

Aprenda a programar um jogo divertido de empilhamento em Ruby2D

📋 O Que Você Vai Construir

Neste tutorial, você criará um jogo de empilhamento de torre onde os jogadores devem cronometrar seus cliques para empilhar blocos precisamente um em cima do outro. Os blocos se movem horizontalmente, e os jogadores devem pará-los no momento exato para criar a torre mais alta possível!

🚀 Começando

1Instalar Ruby2D

Primeiro, você precisa instalar a gem Ruby2D:

gem install ruby2d

2Criar Seu Arquivo de Jogo

Crie um novo arquivo chamado tower_stack.rb ou baixe aqui:tower_stack.rb e adicione a configuração básica:

require 'ruby2d'

set title: "Tower Stacking Game"
set width: 400
set height: 600
set background: '#1a1a2e'

show

Isso cria uma janela com um fundo azul escuro.

🎯 Conceitos Principais

Variáveis de Estado do Jogo

Precisamos rastrear várias informações ao longo do jogo:

@blocks = []           # Array para armazenar todos os blocos empilhados
@current_block = nil   # O bloco atualmente em movimento
@direction = 1         # Direção do movimento (1 = direita, -1 = esquerda)
@speed = 2             # Quão rápido os blocos se movem
@score = 0             # Pontuação do jogador
@game_over = false     # Flag de estado do jogo
@base_width = 100      # Largura do bloco inicial
@block_height = 30     # Altura de cada bloco
💡 Nota: Variáveis de instância (prefixadas com @) persistem durante toda a vida útil do jogo, permitindo rastrear o estado em diferentes métodos.

Criando Elementos de Interface

Adicione elementos de texto para exibir informações do jogo:

@score_text = Text.new(
  'Score: 0',
  x: 10, y: 10,
  size: 20,
  color: 'white'
)

@instruction_text = Text.new(
  'Press SPACE to stack',
  x: 10, y: 40,
  size: 16,
  color: 'gray'
)

@game_over_text = Text.new(
  'GAME OVER! Press R to restart',
  x: 50, y: 250,
  size: 16,
  color: 'red',
  opacity: 0  # Inicialmente oculto
)

🏗️ Construindo a Lógica do Jogo

3Criar o Bloco Base

Toda torre precisa de uma fundação. Este método cria o primeiro bloco na parte inferior:

def create_base
  base = Rectangle.new(
    x: (Window.width - @base_width) / 2,  # Centralizar horizontalmente
    y: Window.height - @block_height - 10,  # Perto da parte inferior
    width: @base_width,
    height: @block_height,
    color: '#16a085'
  )
  @blocks << {
    rect: base,
    x: base.x,
    width: @base_width
  }
end

Armazenamos tanto o objeto Rectangle quanto suas propriedades para cálculos posteriores.

4Criar Blocos em Movimento

Este método cria um novo bloco que se move horizontalmente:

def create_block
  return if @game_over
  
  last_block = @blocks.last
  y_pos = last_block[:rect].y - @block_height  # Empilhar em cima
  
  @current_block = {
    rect: Rectangle.new(
      x: 0,
      y: y_pos,
      width: last_block[:width],  # Mesma largura do anterior
      height: @block_height,
      color: ['#e74c3c', '#3498db', '#f39c12', 
              '#9b59b6', '#e67e22'].sample  # Cor aleatória
    ),
    width: last_block[:width],
    moving: true
  }
end

Cada novo bloco começa com a mesma largura do anterior e recebe uma cor aleatória!

5O Mecanismo de Empilhamento

Este é o coração do jogo - calcular a sobreposição e aparar os blocos:

def stack_block
  return if !@current_block || @game_over
  
  last_block = @blocks.last
  current_x = @current_block[:rect].x
  last_x = last_block[:x]
  
  # Calcular região de sobreposição
  overlap_start = [current_x, last_x].max
  overlap_end = [current_x + @current_block[:width], 
                 last_x + last_block[:width]].min
  overlap = overlap_end - overlap_start
  
  if overlap <= 0
    # Sem sobreposição - fim de jogo!
    @game_over = true
    @game_over_text.opacity = 1
    @current_block[:rect].color = '#c0392b'
    return
  end
  
  # Aparar bloco para área de sobreposição
  @current_block[:rect].x = overlap_start
  @current_block[:rect].width = overlap
  @current_block[:width] = overlap
  @current_block[:x] = overlap_start
  @current_block[:moving] = false
  
  @blocks << @current_block
  @current_block = nil
  
  @score += 1
  @score_text.text = "Score: #{@score}"
  @speed += 0.1  # Aumentar dificuldade
  
  create_block
end
🧮 Como Funciona a Sobreposição: Encontramos onde ambos os blocos existem no eixo X. A região sobreposta se torna o novo bloco. Se os blocos não se sobrepuserem, é fim de jogo!

🎮 Loop de Jogo e Controles

Lógica de Movimento

O bloco update é executado a cada frame e gerencia o movimento do bloco:

update do
  if @current_block && @current_block[:moving] && !@game_over
    # Mover bloco horizontalmente
    @current_block[:rect].x += @speed * @direction
    
    # Rebater nas paredes
    if @current_block[:rect].x <= 0
      @direction = 1  # Mover para direita
    elsif @current_block[:rect].x + @current_block[:width] >= Window.width
      @direction = -1  # Mover para esquerda
    end
  end
end

Manipulação de Entrada

Responder à entrada do teclado do jogador:

on :key_down do |event|
  if event.key == 'space'
    stack_block unless @game_over
  elsif event.key == 'r'
    reset_game if @game_over
  end
end

6Função de Reinicialização

Permitir que os jogadores reiniciem após o fim do jogo:

def reset_game
  @blocks.each { |b| b[:rect].remove }  # Remover todos os blocos
  @blocks.clear
  @current_block[:rect].remove if @current_block
  @current_block = nil
  
  @score = 0
  @speed = 2
  @game_over = false
  @score_text.text = "Score: 0"
  @game_over_text.opacity = 0
  
  create_base
  create_block
end