Untitled

 avatar
unknown
plain_text
a month ago
3.7 kB
3
Indexable
-- Calcula a nova posição e direção do inimigo
novaPosicaoEDirecao :: Float -> (Int, Int) -> Mapa -> (Float, Float) -> Float -> ((Float, Float), (Float, Float))
novaPosicaoEDirecao dt destino mapa (xAtual, yAtual) velocidade =
    let celulaAtual = (floor yAtual, floor xAtual) -- Célula onde o inimigo está (em coordenadas linha-coluna)
        caminho = gerarCaminho celulaAtual destino mapa -- Calcula o caminho
    in case caminho of
        [] -> ((xAtual, yAtual), (0, 0)) -- Sem caminho, o inimigo não se move
        (prox:_) ->
            let (linhaProx, colunaProx) = prox -- Próxima célula no caminho
                (xProx, yProx) = centroCelula prox -- Centro da próxima célula
                -- Decide a direção do movimento (apenas vertical ou horizontal)
                direcao | xAtual < xProx = (1, 0)  -- Vai para a direita
                        | xAtual > xProx = (-1, 0) -- Vai para a esquerda
                        | yAtual < yProx = (0, 1)  -- Vai para baixo
                        | yAtual > yProx = (0, -1) -- Vai para cima
                        | otherwise = (0, 0)      -- Já está no centro da célula
                -- Calcula o próximo movimento com base na velocidade
                vel = velocidade * dt
                (dx, dy) = (fromIntegral (fst direcao) * vel, fromIntegral (snd direcao) * vel)
                novaPos = (xAtual + dx, yAtual + dy)
                -- Garante que o inimigo não ultrapasse o centro da próxima célula
                posFinal = limitarPosicao novaPos (xProx, yProx) direcao
            in (posFinal, direcao)

-- Calcula o centro de uma célula do mapa
centroCelula :: (Int, Int) -> (Float, Float)
centroCelula (linha, coluna) =
    (fromIntegral coluna + 0.5, fromIntegral linha + 0.5)

-- Garante que o inimigo não ultrapasse o centro da célula
limitarPosicao :: (Float, Float) -> (Float, Float) -> (Float, Float) -> (Float, Float)
limitarPosicao (xAtual, yAtual) (xProx, yProx) (dx, dy)
    | dx > 0 && xAtual > xProx = (xProx, yAtual) -- Indo para a direita
    | dx < 0 && xAtual < xProx = (xProx, yAtual) -- Indo para a esquerda
    | dy > 0 && yAtual > yProx = (xAtual, yProx) -- Indo para baixo
    | dy < 0 && yAtual < yProx = (xAtual, yProx) -- Indo para cima
    | otherwise = (xAtual, yAtual)

-- Gera o caminho usando BFS
gerarCaminho :: (Int, Int) -> (Int, Int) -> Mapa -> [(Int, Int)]
gerarCaminho inicio destino mapa =
    bfs inicio destino mapa

-- BFS para calcular o caminho no mapa
bfs :: (Int, Int) -> (Int, Int) -> Mapa -> [(Int, Int)]
bfs inicio destino mapa = bfsAux [(inicio, [inicio])] [] destino mapa
  where
    bfsAux [] _ _ _ = [] -- Sem caminho possível
    bfsAux ((atual, caminho):fila) visitados destino mapa
        | atual == destino = reverse caminho -- Chegou ao destino
        | atual `elem` visitados = bfsAux fila visitados destino mapa -- Ignorar visitados
        | otherwise =
            let vizinhosValidos = filter (ehCelulaValida mapa) (vizinhos atual)
                novos = [(viz, viz:caminho) | viz <- vizinhosValidos, viz `notElem` visitados]
            in bfsAux (fila ++ novos) (atual:visitados) destino mapa

-- Retorna os vizinhos de uma célula
vizinhos :: (Int, Int) -> [(Int, Int)]
vizinhos (linha, coluna) =
    [(linha-1, coluna), (linha+1, coluna), (linha, coluna-1), (linha, coluna+1)] -- Norte, Sul, Oeste, Este

-- Verifica se uma célula é válida
ehCelulaValida :: Mapa -> (Int, Int) -> Bool
ehCelulaValida mapa (linha, coluna) =
    linha >= 0 && linha < length mapa &&
    coluna >= 0 && coluna < length (head mapa) &&
    (mapa !! linha !! coluna == Relva) -- Apenas células de Relva são válidas
Leave a Comment