Solucionado (ver solução)
Solucionado
(ver solução)
3
respostas

IF xyz THEN PRINT(message) na tela

Estava querendo fazer algo tipo mostrar uma mensagem na tela, caso o usuário tente abrir a porta, sem ter a chave. Mas o print (nem o rect que também tentei) não aparece de jeito nenhum.

Se eu tentar fazer um print dentro da função TIC, ele aparece sem problemas.

Entendo que no momento em que eu paro de segurar a tecla para colidir na porta, a função também para. Mas não teria como eu dar uma pequena travada no personagem, ou fazer meio que uma programação assíncrona e deixar o texto flutuando lá por alguns segundos?

Uma outra dúvida, menos importante, mas com certa ligação à dúvida anterior é que se eu manter a tecla pressionada contra a porta, o SFX fica travado nos primeiros quadros, e só toca o restante, quando eu solto a tecla. É possível, em LUA, fazer com que o som toque inteiramente antes de iniciar de novo?

function abrirPorta(indice)
        if jogador.chaves > 0 then
                    sfx(misc.id_sfx_porta_com_chave,
                                    60, -- quantos oitavos = 5 oitavos * 12 notas
                                    32, -- quantos quadros de som
                                    0, -- qual canal de som
                                    8, -- volume do som
                                    0) -- velocidade do som
                    jogador.chaves = jogador.chaves - 1
                    table.remove(objetos, indice)
                    return false
        end
        print('Porta trancada!', 13*8, 6*8, 15)
        sfx(misc.id_sfx_porta_sem_chave,
            24,    32,    0,    8,    0)

        return true
end

Obrigado desde já!

3 respostas
solução!

Olá Iury!

Como você percebeu, colocar o print dentro da função abrirPorta() vai fazer com que essa mensagem seja apresentada apenas quando essa função for chamada. Como ela só é chamada quando o jogador encosta em alguma porta, a mensagem só é apresentada enquanto o jogador está encostando na porta.

A sua ideia de fazer isso de forma assíncrona é bem boa e vou te mostrar aqui como fazer isso em Lua.

A primeira coisa a fazer é colocar o código que você quer executar assincronamente dentro de uma nova função. Então, por exemplo, supondo que a gente queira mostrar a mensagem por 30 quadros, escreveríamos a função assim:

function msgPortaTrancada()
  for i=1,30 do
    print('Porta trancada!', 13*8, 6*8, 15)
  end
end

Por enquanto, ela é apenas uma função normal. Só que agora, nós vamos dizer pra Lua que não queremos que a função seja executada de uma só vez. Queremos que ela exiba a mensagem e espere até o próximo quadro pra fazer a próxima iteração do for. Para fazer isso vamos usar a função coroutine.yield():

function msgPortaTrancada()
  for i=1,30 do
    print('Porta trancada!', 13*8, 6*8, 15)
    coroutine.yield()
  end
end

Legal, agora precisamos dizer pra Lua que queremos tratar essa função como uma função que pode ser executada aos poucos. Para isso, vamos inicializar essa função como uma corotina. De forma simplificada, uma corotina é uma função que pode ser executada em partes para obtermos algo parecido como uma execução assíncrona.

Para fazer a inicialização, vamos chamar a função coroutine.create() passando o nome da função que queremos transformar em uma corotina:

Idealmente você vai querer fazer isso na função abrirPorta():

function abrirPorta(indice)
        if jogador.chaves > 0 then
                    sfx(misc.id_sfx_porta_com_chave,
                                    60, -- quantos oitavos = 5 oitavos * 12 notas
                                    32, -- quantos quadros de som
                                    0, -- qual canal de som
                                    8, -- volume do som
                                    0) -- velocidade do som
                    jogador.chaves = jogador.chaves - 1
                    table.remove(objetos, indice)
                    return false
        end
        corotinaMsgPortaTrancada = coroutine.create(msgPortaTrancada)
        sfx(misc.id_sfx_porta_sem_chave,
            24,    32,    0,    8,    0)

        return true
end

Perceba que estamos armazenando a corotina que foi criada em uma variável chamada corotinaMsgPortaTrancada. Esse variável precisa ser criada e inicializada com nil naquela função de inicialização do jogo.

Precisamos dizer quando essa função vai ser executada. Para que a mensagem apareça corretamente, vamos invocar a corotina ao final da função que desenha os elementos do jogo. Nesse caso, só vamos executar a corotina se ela existir, isto é, se a variável corotinaMsgPortaTrancada não for nil:

function desenhaTela() 
  -- resto do código

  if (corotinaMsgPortaTrancada) then
    coroutine.resume(corotinaMsgPortaTrancada)
  end
end

Agora sim, todo quadro do nosso jogo vamos executar uma iteração do for que exibe a nossa mensagem até que a corotina termine. Quando isso acontecer, é interessante atribuir novamente o valor nil para a variável da corotina pra que a gente não fique executando ela à toa.

O código então ficaria assim:

function desenhaTela() 
  -- resto do código

  if (corotinaMsgPortaTrancada) then
    coroutine.resume(corotinaMsgPortaTrancada)
    if (coroutine.status(corotinaMsgPortaTrancada == "dead") then
      corotinaMsgPortaTrancada = nil
    end
  end
end

Pronto! Agora é só testar e ver se você consegue o resultado que queria!

Bacana que você percebeu a necessidade de ter alguma forma de fazer as coisas de forma assíncrona!

Boa noite, professor,

Muito obrigado pela atenção que você deu a esse meu problema e à resposta super detalhada. Ficou tudo muito claro e fácil de entender.

A solução funcionou perfeitamente.

Só me restou uma pequena dúvida boba.

Se eu não nular a variável, poderia acontecer da função vir a executar novamente? Mesmo nesse caso, onde o único trigger dela é encostar na porta trancada, que não estaria mais trancada quando o player estiver com a chave? Seria o mesmo caso de eu não resetar/nular uma variável no início de um programa e correr o risco de trazer "sujeira" dela?

Enfim, novamente muito obrigado pela resposta, foi de grande ajuda!

Olá Iury,

A ideia de atribuir o valor pra variável é só pra gente não ficar tentando executar a corotina a cada quadro do jogo. Não teria problema deixar ela lá pois o que vai acontecer se tentarmos executá-la é que a Lua vai simplesmente ignorar o comando. Talvez se a gente estivesse trabalhando com muitas corotinas isso pudesse ter algum impacto no tempo de execução de cada quadro do jogo.