Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ----------------------------------------------------------------
- -- CONFIGURAÇÕES INICIAIS
- ----------------------------------------------------------------
- largura = 16
- altura = 16
- nivel = 1
- pontuacao = 0
- vidas = 3
- gameOver = false
- -- Tabelas globais para obstáculos e para a base
- obstacles = {} -- Obstáculos (tijolos destruíveis)
- ----------------------------------------------------------------
- -- DEFINIÇÃO DA BASE PROTETORA
- -- A base tem o formato:
- -- 🧱🧱🧱
- -- 🧱🌟🧱
- -- 🧱🧱🧱
- ----------------------------------------------------------------
- baseCenter = { x = math.floor(largura/2), y = math.floor(altura/2) }
- -- A tabela baseCells armazena todas as células que compõem a base.
- baseCells = {
- {x = baseCenter.x - 1, y = baseCenter.y - 1},
- {x = baseCenter.x, y = baseCenter.y - 1},
- {x = baseCenter.x + 1, y = baseCenter.y - 1},
- {x = baseCenter.x - 1, y = baseCenter.y},
- {x = baseCenter.x, y = baseCenter.y}, -- Centro (🌟)
- {x = baseCenter.x + 1, y = baseCenter.y},
- {x = baseCenter.x - 1, y = baseCenter.y + 1},
- {x = baseCenter.x, y = baseCenter.y + 1},
- {x = baseCenter.x + 1, y = baseCenter.y + 1}
- }
- ----------------------------------------------------------------
- -- FUNÇÃO AUXILIAR: VERIFICA SE A POSIÇÃO (x,y) ESTÁ LIVRE
- -- (não ocupada por um obstáculo ou por uma célula da base)
- ----------------------------------------------------------------
- function posLivre(x, y)
- for _, obs in ipairs(obstacles) do
- if obs.x == x and obs.y == y then return false end
- end
- for _, cell in ipairs(baseCells) do
- if cell.x == x and cell.y == y then return false end
- end
- return true
- end
- ----------------------------------------------------------------
- -- FUNÇÃO AUXILIAR: VERIFICA SE A CÉLULA (x,y) FAZ PARTE DA BASE
- ----------------------------------------------------------------
- function baseContains(x, y)
- for _, cell in ipairs(baseCells) do
- if cell.x == x and cell.y == y then return true end
- end
- return false
- end
- ----------------------------------------------------------------
- -- GERAÇÃO DE OBSTÁCULOS (tijolos destruíveis)
- ----------------------------------------------------------------
- function spawnObstaculos(qtd)
- obstacles = {}
- for i = 1, qtd do
- local ox, oy
- repeat
- ox = math.random(2, largura-1)
- oy = math.random(2, altura-1)
- until posLivre(ox, oy)
- table.insert(obstacles, {x = ox, y = oy})
- end
- end
- spawnObstaculos(10)
- ----------------------------------------------------------------
- -- DEFINIÇÃO DAS FORMAS DO TANQUE (6 quadrados)
- -- O "canhão" é o quadrado de índice 2.
- ----------------------------------------------------------------
- formas = {
- Cima = {
- {dx = -1, dy = 0}, -- Lado esquerdo
- {dx = 0, dy = -1}, -- CANHÃO (frente)
- {dx = 1, dy = 0}, -- Lado direito
- {dx = -1, dy = 1}, -- Roda esquerda
- {dx = 0, dy = 0}, -- Corpo central
- {dx = 1, dy = 1} -- Roda direita
- },
- Baixo = {
- {dx = 1, dy = 0},
- {dx = 0, dy = 1}, -- CANHÃO (frente para baixo)
- {dx = -1, dy = 0},
- {dx = 1, dy = -1},
- {dx = 0, dy = 0},
- {dx = -1, dy = -1}
- },
- Direita = {
- {dx = 0, dy = -1},
- {dx = 1, dy = 0}, -- CANHÃO à direita
- {dx = 0, dy = 1},
- {dx = -1, dy = -1},
- {dx = 0, dy = 0},
- {dx = -1, dy = 1}
- },
- Esquerda = {
- {dx = 0, dy = 1},
- {dx = -1, dy = 0}, -- CANHÃO à esquerda
- {dx = 0, dy = -1},
- {dx = 1, dy = 1},
- {dx = 0, dy = 0},
- {dx = 1, dy = -1}
- }
- }
- ----------------------------------------------------------------
- -- TANQUE DO JOGADOR (inicia na parte inferior central)
- ----------------------------------------------------------------
- tanque = {
- pos = {x = math.floor(largura/2), y = altura - 2},
- direcao = "Cima",
- partes = {}
- }
- function atualizarTanque(obj)
- local t = obj or tanque
- t.partes = {}
- local offsets = formas[t.direcao]
- for i, off in ipairs(offsets) do
- table.insert(t.partes, {x = t.pos.x + off.dx, y = t.pos.y + off.dy})
- end
- end
- atualizarTanque()
- ----------------------------------------------------------------
- -- TANQUES INIMIGOS
- ----------------------------------------------------------------
- function criarTanqueInimigo(x, y)
- local t = {
- pos = {x = x, y = y},
- direcao = "Cima",
- partes = {}
- }
- atualizarTanque(t)
- return t
- end
- tanqueinimigos = {}
- function spawnInimigos(qtd)
- tanqueinimigos = {}
- for i = 1, qtd do
- local ex, ey
- repeat
- ex = math.random(3, largura-3)
- ey = math.random(2, math.floor(altura/2))
- until posLivre(ex, ey)
- table.insert(tanqueinimigos, criarTanqueInimigo(ex, ey))
- end
- end
- spawnInimigos(nivel + 2) -- Ex: nível 1 -> 3 inimigos
- ----------------------------------------------------------------
- -- DESENHO DO TABULEIRO
- ----------------------------------------------------------------
- function desenharTabuleiro()
- local board = ""
- for y = 1, altura do
- for x = 1, largura do
- local celula = "⬛" -- fundo padrão
- -- Se a célula faz parte da base
- local isBase = false
- for _, cell in ipairs(baseCells) do
- if cell.x == x and cell.y == y then
- if x == baseCenter.x and y == baseCenter.y then
- celula = "🌟"
- else
- celula = "🧱"
- end
- isBase = true
- break
- end
- end
- if not isBase then
- -- Verifica obstáculos
- for _, obs in ipairs(obstacles) do
- if obs.x == x and obs.y == y then
- celula = "🧱"
- break
- end
- end
- end
- -- Sobrepõe com o jogador (prioridade máxima)
- for _, parte in ipairs(tanque.partes) do
- if parte.x == x and parte.y == y then
- celula = "🟩"
- break
- end
- end
- -- Sobrepõe com os inimigos
- for _, inimigo in ipairs(tanqueinimigos) do
- for _, parte in ipairs(inimigo.partes) do
- if parte.x == x and parte.y == y then
- celula = "🟥"
- break
- end
- end
- end
- board = board .. celula
- end
- board = board .. "\n"
- end
- board = board .. "\nVidas: " .. tostring(vidas) .. " | Pontuação: " .. tostring(pontuacao) .. " | Nível: " .. tostring(nivel)
- return board
- end
- ----------------------------------------------------------------
- -- FUNÇÃO scanShot: varredura do tiro
- -- A partir de (sx, sy) e com vetor (dx, dy) verifica obstáculos,
- -- a base e os alvos (inimigo ou jogador), retornando:
- -- "obstacle", índice => tiro atinge obstáculo
- -- "base_protect", índice => tiro atinge um tijolo de proteção
- -- "base", índice => tiro atinge o centro da base (se desprotegido)
- -- "enemy" ou "player", índice => alvo atingido
- ----------------------------------------------------------------
- function scanShot(sx, sy, dx, dy, shooterType)
- local x = sx
- local y = sy
- while x >= 1 and x <= largura and y >= 1 and y <= altura do
- -- Obstáculos
- for i, obs in ipairs(obstacles) do
- if obs.x == x and obs.y == y then
- return "obstacle", i
- end
- end
- -- Base
- local isBaseCell = false
- local baseIndex = nil
- for j, cell in ipairs(baseCells) do
- if cell.x == x and cell.y == y then
- isBaseCell = true
- baseIndex = j
- break
- end
- end
- if isBaseCell then
- if x == baseCenter.x and y == baseCenter.y then
- -- É o centro; só pode ser atingido se não houver proteção
- local protecaoRestante = false
- for j, cell in ipairs(baseCells) do
- if not (cell.x == baseCenter.x and cell.y == baseCenter.y) then
- protecaoRestante = true
- break
- end
- end
- if protecaoRestante then
- -- Retorna que atingiu uma proteção (mesmo que não tenha índice definido)
- return "base_protect", nil
- else
- return "base", baseIndex
- end
- else
- -- É um tijolo de proteção
- return "base_protect", baseIndex
- end
- end
- if shooterType == "player" then
- for i, inimigo in ipairs(tanqueinimigos) do
- for j, parte in ipairs(inimigo.partes) do
- if parte.x == x and parte.y == y then
- return "enemy", i
- end
- end
- end
- elseif shooterType == "enemy" then
- for j, parte in ipairs(tanque.partes) do
- if parte.x == x and parte.y == y then
- return "player", nil
- end
- end
- end
- x = x + dx
- y = y + dy
- end
- return "none", nil
- end
- ----------------------------------------------------------------
- -- DISPARO DO JOGADOR
- ----------------------------------------------------------------
- function dispararJogador()
- local canhao = tanque.partes[2] -- o canhão (índice 2)
- local dx, dy = 0, 0
- if tanque.direcao == "Cima" then dx, dy = 0, -1
- elseif tanque.direcao == "Baixo" then dx, dy = 0, 1
- elseif tanque.direcao == "Direita" then dx, dy = 1, 0
- elseif tanque.direcao == "Esquerda" then dx, dy = -1, 0
- end
- local target, index = scanShot(canhao.x, canhao.y, dx, dy, "player")
- if target == "obstacle" then
- table.remove(obstacles, index)
- elseif target == "enemy" then
- pontuacao = (pontuacao or 0) + 100
- table.remove(tanqueinimigos, index)
- elseif target == "base_protect" then
- -- Remove o tijolo de proteção atingido
- if index then
- table.remove(baseCells, index)
- else
- -- Se não tiver índice, procura por algum tijolo (exceto o centro)
- for j, cell in ipairs(baseCells) do
- if not (cell.x == baseCenter.x and cell.y == baseCenter.y) then
- table.remove(baseCells, j)
- break
- end
- end
- end
- elseif target == "base" then
- gg.alert("Você destruiu a base! Game Over.\nPontuação: " .. tostring(pontuacao))
- os.exit()
- end
- end
- ----------------------------------------------------------------
- -- DISPARO DOS INIMIGOS
- ----------------------------------------------------------------
- function dispararInimigos()
- for _, inimigo in ipairs(tanqueinimigos) do
- local canhaoI = inimigo.partes[2]
- local dx, dy = 0,0
- if inimigo.direcao == "Cima" then dx, dy = 0, -1
- elseif inimigo.direcao == "Baixo" then dx, dy = 0, 1
- elseif inimigo.direcao == "Direita" then dx, dy = 1, 0
- elseif inimigo.direcao == "Esquerda" then dx, dy = -1, 0
- end
- local target, index = scanShot(canhaoI.x, canhaoI.y, dx, dy, "enemy")
- if target == "obstacle" then
- table.remove(obstacles, index)
- elseif target == "base_protect" then
- if index then
- table.remove(baseCells, index)
- else
- for j, cell in ipairs(baseCells) do
- if not (cell.x == baseCenter.x and cell.y == baseCenter.y) then
- table.remove(baseCells, j)
- break
- end
- end
- end
- elseif target == "base" then
- gg.alert("A base protetora foi destruída! Game Over.\nPontuação: " .. tostring(pontuacao))
- os.exit()
- elseif target == "player" then
- vidas = vidas - 1
- if vidas <= 0 then
- gg.alert("Você perdeu todas as vidas! Game Over.\nPontuação: " .. tostring(pontuacao))
- os.exit()
- end
- end
- end
- end
- ----------------------------------------------------------------
- -- MOVIMENTAÇÃO DO JOGADOR (somente se todas as células futuras estiverem livres)
- ----------------------------------------------------------------
- function moverJogador(dx, dy)
- local newPos = { x = tanque.pos.x + dx, y = tanque.pos.y + dy }
- local offsets = formas[tanque.direcao]
- for _, off in ipairs(offsets) do
- local nx = newPos.x + off.dx
- local ny = newPos.y + off.dy
- if nx < 1 or nx > largura or ny < 1 or ny > altura or (not posLivre(nx, ny)) then
- return -- movimento bloqueado
- end
- end
- tanque.pos = newPos
- atualizarTanque()
- end
- ----------------------------------------------------------------
- -- MOVIMENTAÇÃO DOS INIMIGOS (movimento aleatório, se destino estiver livre)
- ----------------------------------------------------------------
- function moverInimigos()
- local opcoes = {"Cima", "Baixo", "Direita", "Esquerda"}
- for _, inimigo in ipairs(tanqueinimigos) do
- local dir = opcoes[math.random(1, #opcoes)]
- inimigo.direcao = dir
- local dx, dy = 0, 0
- if dir == "Cima" then dy = -1
- elseif dir == "Baixo" then dy = 1
- elseif dir == "Direita" then dx = 1
- elseif dir == "Esquerda" then dx = -1
- end
- local newPos = { x = inimigo.pos.x + dx, y = inimigo.pos.y + dy }
- local canMove = true
- for _, off in ipairs(formas[inimigo.direcao]) do
- local nx = newPos.x + off.dx
- local ny = newPos.y + off.dy
- if nx < 1 or nx > largura or ny < 1 or ny > altura or (not posLivre(nx, ny)) then
- canMove = false
- break
- end
- end
- if canMove then
- inimigo.pos = newPos
- atualizarTanque(inimigo)
- end
- end
- end
- ----------------------------------------------------------------
- -- CHECA COLISÃO: Se alguma parte do jogador colide com um inimigo
- ----------------------------------------------------------------
- function checarColisoes()
- for _, parteJ in ipairs(tanque.partes) do
- for _, inimigo in ipairs(tanqueinimigos) do
- for _, parteI in ipairs(inimigo.partes) do
- if parteJ.x == parteI.x and parteJ.y == parteI.y then
- return true
- end
- end
- end
- end
- return false
- end
- ----------------------------------------------------------------
- -- MENU DE AÇÕES (via gg.choice)
- ----------------------------------------------------------------
- function menuAcoes()
- local opcoes = {
- " ⬆️ Cima",
- " ⬅️ Esquerda",
- " ➡️ Direita",
- " ⬇️ Baixo",
- " 💥 Disparar",
- " ❌ Desistir!😪"
- }
- local texto = desenharTabuleiro() .. "\nEscolha uma ação:"
- local escolha = gg.choice(opcoes, nil, texto)
- if escolha == nil then
- gg.setVisible(false)
- return nil
- end
- return escolha
- end
- ----------------------------------------------------------------
- -- LOOP PRINCIPAL DO JOGO
- ----------------------------------------------------------------
- function iniciarJogo()
- while not gameOver do
- -- Se não houver inimigos, o jogador deve proteger/pegar a base
- if #tanqueinimigos == 0 then
- -- A base já está desenhada; o jogador precisa alcançar o centro para avançar.
- for _, parte in ipairs(tanque.partes) do
- if parte.x == baseCenter.x and parte.y == baseCenter.y then
- gg.alert("Nível " .. tostring(nivel) .. " concluído!")
- nivel = nivel + 1
- if nivel > 5 then
- gg.alert("Você completou todos os níveis! Parabéns!\nPontuação Final: " .. tostring(pontuacao))
- os.exit()
- end
- -- Reinicia para o novo nível:
- spawnInimigos(nivel + 2)
- spawnObstaculos(10)
- tanque.pos = { x = math.floor(largura/2), y = altura - 2 }
- atualizarTanque()
- -- Restaura a base completa
- baseCells = {
- {x = baseCenter.x - 1, y = baseCenter.y - 1},
- {x = baseCenter.x, y = baseCenter.y - 1},
- {x = baseCenter.x + 1, y = baseCenter.y - 1},
- {x = baseCenter.x - 1, y = baseCenter.y},
- {x = baseCenter.x, y = baseCenter.y},
- {x = baseCenter.x + 1, y = baseCenter.y},
- {x = baseCenter.x - 1, y = baseCenter.y + 1},
- {x = baseCenter.x, y = baseCenter.y + 1},
- {x = baseCenter.x + 1, y = baseCenter.y + 1}
- }
- break
- end
- end
- end
- local acao = menuAcoes()
- if acao == nil then break end
- if acao == 1 then
- tanque.direcao = "Cima"
- moverJogador(0, -1)
- elseif acao == 2 then
- tanque.direcao = "Esquerda"
- moverJogador(-1, 0)
- elseif acao == 3 then
- tanque.direcao = "Direita"
- moverJogador(1, 0)
- elseif acao == 4 then
- tanque.direcao = "Baixo"
- moverJogador(0, 1)
- elseif acao == 5 then
- dispararJogador()
- elseif acao == 6 then
- gg.alert("Jogo Finalizado. Pontuação: " .. tostring(pontuacao))
- os.exit()
- end
- moverInimigos()
- dispararInimigos()
- if checarColisoes() then
- gg.alert("Colisão! Você foi atingido. Game Over.\nPontuação: " .. tostring(pontuacao))
- os.exit()
- end
- gg.sleep(100)
- end
- end
- -- Inicia o jogo
- iniciarJogo()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement