IF xyz THEN PRINT(message) na tela | Lua parte 1: Crie um jogo de RPG em 2D | Solucionado
IF xyz THEN PRINT(message) na tela
Referente ao curso Lua parte 1: Crie um jogo de RPG em 2D
Iury Ferreira
(52.5k xp, 2 posts)
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)
print('Porta trancada!', 13*8, 6*8, 15)
sfx(misc.id_sfx_porta_sem_chave,
24,    32,    0,    8,    0)
(317.1k xp, 591 posts)
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()
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():
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():
corotinaMsgPortaTrancada = coroutine.create(msgPortaTrancada)
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)
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:
if (coroutine.status(corotinaMsgPortaTrancada == "dead") then
corotinaMsgPortaTrancada = nil
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!
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!
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.