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!