terça-feira, 17 de janeiro de 2012

[Saim] Bugs e dúvidas comuns

Qualidade
Nome: Bugs e dúvidas comuns
Blogueiro: Saim
Descrissao: Existem algumas perguntas que são feitas e refeitas aqui na comunidade. Estou elaborando uma lista dos bugs mais comuns e das soluções mais comuns. Se você tiver algum bug que te aconteça em 9 de 10 jogos que você cria, comente e eu tentarei acrescentar uma solução genérica, colocando seu bug na lista.
Versao: Lite e Pro
Foto(s): [explicaçao]

Tutorial:
Meu personagem fica preso

O primeiro bug da maioria dos desenvolvedores. O persongem (obj_player ou não) anda até uma parede e depois não sai mais. Não importa a força com que o jogador aperte o teclado, o personagem travou!
Normalmente isso é um problema de sobreposição de masks. Seu personagem está entrando alguns pixels no chão/parede. Pode acontecer por dezenas de motivos.
Você programa a velocidade pra ser zero caso o objeto colida com um bloco, então se eles se sobreporem, o natural é que a velocidade seja sempre zero.
Um motivo comum é o uso de sprites irregulares como a mask acompanhando o personagem. Daí, num image_index ele está ok, no outro está alguns pixels dentro do bloco.
Outro motivo é código mal elaborado, que não impede a sobreposição.

Nem sempre é possível enxergar essa sobreposição a olho nu. Além de ser apenas alguns pixels, a mask pode ser diferente da sprite. Nesses casos é bem difícil determinar o problema.

solução

Crie uma variável só pra debugar. Sempre que houver uma colisão, esa variável deve ter o valor true e sempre que não houver, false. Daí você pode usar alguma função de draw pra verificar o valor dessa variável ou simplesmente o debug mode.
Se for verificado que a colisão realmente tornou-se constante enquanto o objeto está travado, não restam mais dúvidas quanto à causa do bug. Daí, parta para a análise dos códigos, das sprites, das masks. Use uma lupa.

Meu sprite não aparece

Você faz o jogo direitinho, se esforça e, na hora que vai rodar, alguns objetos que deveriam estar lá, simplesmente não estão.
Existem algumas causas principais pra isso:
1 - Existe algo no draw event. O game maker usa um draw event "default", que apenas desenha o personagem. Eu diria que ele contém "draw_sprite_ext(sprite_index, image_index, x, y, image_xscale, image_yscale, imgae_angle, c_white, 1);". Se você coloca QUALQUER coisa no seu próprio draw event, esse evento-padrão é ignorado.
2 - Não existe a instância. Acontece. Você acha que criou uma instância, mas ela não foi criada ou foi eliminada sem que você se desse conta.
3 - A instância não está na tela. Ela existe, está sendo desenhada, mas está fora do seu campo de visão.

solução

Em todos os casos, verificar o draw event ou mesmo alterá-lo até encontrar o problema pode ser uma boa. Pra checar se a instância existe, mande desenhar algo numa posição que você SABE que vai aparecer. Como sempre, o modo debug também pode ser útil, se você procurar por termos como "x", "y", "instance_number".
Uma vez determinado qual é o problema, não é difícil corrigir.

Meu jogo trava

No meio do jogo, mesmo sem tocar em nada, o personagem para de obedecer aos comandos. Você tenta fechar a janela do jogo pra procurar o bug e ela não fecha, você tem que abrir o gerenciador de tarefas.
A causa desse bug é (até onde eu sei) única: existe um laço (ou loop) que não encontra a condição de ser finalizado. Porque esse loop não está conseguindo se encerrar, aí a história é outra. Existem dezenas, centenas, talvez até milhares de motivos pra isso. Cada loop, um motivo.
Alguns motivos comuns:
- Erro de digitação: for (i = 0; i < 10; j += 1){
- Erro de lógica: i = 0; while(i < 10){ /* código */ }; Note que não foi colocado o "i += ..." no código
- Erro de lógica2: for (i = 0; i < 10; i += 1){ /* código */; i -=1 }; Note que no final do loop, i volta pro valor inicial

solução

Não sei se existe uma solução padrão pra esses casos. O que eu costumo fazer é:
- Tentar descobrir em que evento o jogo está travando, o que pode dar uma dica de qual loop está com problemas. Se for no início do jogo (quando normalmente existem muitos loops), talvez seja melhor ir direto pra segunda abordagem.
- Tentar isolar o problema eliminando os loops, um por um, não importa o quanto o jogo fique bugado até que se descubra o problema. Não é uma boa solução (porque uma variável usada num loop pode estar sendo definida em outro), mas em muitos casos pode ajudar.
Assim que se descobre qual loop causa o erro, fica viável (ou menos inviável) isolá-lo e testar o comportamento das variáveis, iteração por iterção (ou volta por volta). Algumas vezes pode ser útil usar show_message ou show_debug_message dentro desses loops, já que muitas vezes eles usam variáveis var.

"Unexpected error"

No meio do jogo, essa mensagem enigmática: "unexpected error ocurred while running the game", ou "ocorreu um erro inesperado ao rodar o jogo". Aí, lascou. Afinal, existe algum programador que espera um erro?
O que isso quer dizer é que o game maker verificou todas as funções e scripts e um deles não está funcionando apesar do número e tipos de argumentos estarem corretos. Você comeu mosca em algum ponto.

solução

Se a quantidade e o tipo de argumentos estão corretos, o erro só pode estar no valor deles. Eu constantemente recebo esse erro por trocar a ordem dos argumentos de algumas funções. Por exemplo, você pode trocar o sprite pela surface em "sprite_add_from_surface". Verifique quais funções você está usando sem ter muito hábito de usar. Experimente não usar uma ou outra função (no caso, por exemplo, você pode usar uma sprite sem sub-imagens) até que o problema pare de acontecer. Quando o problema parar de acontecer, eis a função que está com problemas. Cheque o manual, veja o que significa cada argumento, altere o que estiver errado.


Como manter alguma informação?

Ao mudar de room ou reiniciar a room, todas aquelas variáveis que você se esforçou pra mudar, como vidas, score, e outras menos comuns, todas elas voltam pro valor inicial.
Muitas vezes isso é esperado e desejado. Algumas vezes, não.
A causa mais comum desse problema é que o valor dessas variáveis é definido no create event do objeto. Como na programação da room o game maker foi informado pra criar os objetos, ele roda todos os create event, o que reinicia a variável.

solução

Há várias soluções. Pra cada jogo, uma solução. As que eu sugiro tentar são:
- Se for uma variável global, você pode definí-la em alguma room do começo do jogo, ao invés de usar um objeto que será reinicializado. Pode-se usar, também, um objeto persistente que é criado numa room da inicialização do programa.
- Se o problema é que a room está sendo reiniciada, não reinicie a room. O personagem "morrer" não implica, necessariamente no comando instance_destroy() nem no room_restart(). Você pode usar um evento especial (como a colisão com o inimigo ou o final de uma animação de morte) pra fazer o personagem reaparecer na posição inicial, com a tela acompanhando e tudo.
Creditos: Saim

Nenhum comentário:

Postar um comentário