GMBR
Gostaria de reagir a esta mensagem? Crie uma conta em poucos cliques ou inicie sessão para continuar.
Entrar

Esqueci-me da senha

Últimos assuntos
» Colisões não funcionando
por RastaMaan Hoje à(s) 19:49

» Como ajustar velocidade de cada frame da animação no game maker
por pequetux Hoje à(s) 16:45

» Preciso de ajuda
por AftonDuGrau Dom 21 Abr 2024, 20:18

» Como faz o evento drawn GUI, não se repetir?
por aminaro Sex 19 Abr 2024, 20:30

» PROBLEMAS COM FÍSICAS DE ÁGUA
por aminaro Ter 16 Abr 2024, 10:07

» Retorno da GMBR!!!
por Ralphed Sex 12 Abr 2024, 22:45

» JOGADOR PARANDO NO AR QUANDO ATACA
por aminaro Qua 10 Abr 2024, 13:51

» Problemas com texto interativo
por Kaaru72 Dom 07 Abr 2024, 11:31

» Erro escondido e indecifrável
por dev_gabize.azv Qui 04 Abr 2024, 10:11

» Mudar cor de apenas uma palavra
por Ralphed Sáb 30 Mar 2024, 00:39

» Procuro Programador de game maker
por Wou Sex 15 Mar 2024, 10:27

» Mod APK
por gamerainha Qua 13 Mar 2024, 06:30

» Aceito pedidos de sprites (Com exemplos meus)
por Sevilha Qua 28 Fev 2024, 12:17

» Inventário simples
por Isquilo_Roedor Qui 22 Fev 2024, 15:18

» Problemas na programaçnao de inimigo [jogo DOOM LIKE]
por Black Mirror Dom 11 Fev 2024, 13:34

» ANDROID MULTI TOUCH
por DiegoBr Dom 04 Fev 2024, 12:13

» Servidor de Discord do fórum?
por Lighter Sáb 27 Jan 2024, 17:18

» Save e Load Json
por Klinton Rodrigues Qui 25 Jan 2024, 11:12

» Colisão com mais de um objeto
por aminaro Seg 22 Jan 2024, 15:02

» Oi sou novo aqui
por Thiago Silveira Alexandre Sáb 20 Jan 2024, 20:55

» Como acessar conteudo comprado no marketplace
por macmilam Sex 19 Jan 2024, 07:42

» Devlogs em vídeos do Block Room
por Joton Seg 15 Jan 2024, 16:56

» Alguém aqui já ganha dinheiro com seus games?
por Joton Seg 15 Jan 2024, 16:49

» ACERVO GMBR MAGAZINE
por Joton Qui 11 Jan 2024, 19:21

» como aumentar o obj sem aumentar a colisão??
por GabrielXavier Qua 10 Jan 2024, 07:21


Efeito luz e sombra [parte 1]

2 participantes

Ir para baixo

Efeito luz e sombra [parte 1] Empty Efeito luz e sombra [parte 1]

Mensagem por Lighter Sex 07 Jul 2017, 22:39

Título: Efeito luz e sombra
Plataforma: Funcionou sem problemas em HTML5 e Android.
Dificuldade: Sem dificuldades Laughing
Pré requisitos: Conhecimento básico em Blending, surfaces, e um pouco de matemática Basketball

Olá pessoal do fórum, venho trazer uma série de tutoriais sobre efeito de luz e sombra. Nesse primeiro tutorial, separei para estudarmos mais a parte matemática do funcionamento. Creio que para alguns leitores esse tema é um tanto quanto complexo, mas não é nada disso, vou desenvolver esse tutorial de forma simples e eficiente para iniciantes no GameMaker. O resultado final será um efeito muito parecido com esse:
Efeito luz e sombra [parte 1] WXJyAg6wSt6JBmE50D8rCw

Introdução e Convenções
Essa solução de luz e sombra que eu desenvolvi funciona apenas para objetos "quadrados", pois eles possuem as extremidades bem definidas. Basicamente todo objeto que poderá interromper a luz armazenará informações da localização de suas bordas. Por exemplo, um objeto com uma Sprite quadrada (32x32), as extremidades serão os pontos (0,0), (32,0), (32,32), (0,32). Portanto, vamos estipular essa regra, todo objeto com capacidade de "fazer" sombra armazenará uma matriz contendo as informações do ponto de cada extremidade.

Desenvolvimento do algoritmo principal
Vamos começar a programar, crie um projeto e também 2 objetos, nomeie eles com "LightController" e "Block", o Block será capaz de interromper a luz, então como a gente já tinha combinado antes, vamos fazer uma matriz que contenha as informações de cada extremidade da Sprite desse objeto, se a sua Sprite estiver centralizada apenas altere o código:

Event Create Block -> Create:
Código:
edge[0,0] = x;
edge[0,1] = y;

edge[1,0] = x+sprite_width;
edge[1,1] = y;

edge[2,0] = x+sprite_width;
edge[2,1] = y+sprite_height;

edge[3,0] = x;
edge[3,1] = y+sprite_height;
//Edge será a matriz com 4 elementos contendo a extremidade das arestas, a segunda chave representa x se for 0, e y se for 1

Agora no objeto LightController vamos desenhar linhas partindo da posição do mouse até as extremidades dos blocos. Para isso, percorreremos por todas as instancias, e se caso uma delas for do tipo "Block", então o controlador irá desenhar a linha para cada extremidade do bloco.

Event Draw LightController -> Draw
Código:
for(i = 0; i < instance_count; i++){
    if(instance_id[i].object_index == Block){
        tmp = instance_id[i];
        for(j = 0; j < 4; j++){
            draw_line(x, y, tmp.edge[j,0], tmp.edge[j,1]);
        }
    }
}

//Percorrerá todas as instancias, e se caso a instancia for da classe Bloco, ira desenhar uma linha partindo da posição do mouse até as extremidades do bloco

Efeito luz e sombra [parte 1] MfleK1lzSfmSQ57SRuRW9A

Ao final desse passo, teremos uma noção do comportamento da sombra, ao compilar você terá um resultado muito parecido com a imagem acima, deve estar pensando que a direção das linhas estão erradas, e realmente estão. A sombra deverá ser repelida e não atraída pela fonte de luz (fonte de luz é a posição do mouse), ou seja, devemos inverter o sentido de cada linha, vamos modificar o evento draw.

Event Draw LightController -> Draw
Código:
for(i = 0; i < instance_count; i++){
    if(instance_id[i].object_index == Block){
        tmp = instance_id[i]; //variável temporária para instancia do Bloco.
        for(j = 0; j < 4; j++){ //Percorrerá as 4 extremidades do Bloco, j = 0 extremidade 0, e assim por diante.
            dir  = point_direction(mouse_x, mouse_y, tmp.edge[j,0], tmp.edge[j,1]); //pega a direção entre o mouse e a extremidade "j" do bloco;
            posx = tmp.edge[j,0]; //posx será nossa posição em relação a X da extremidade "j".
            posy = tmp.edge[j,1]; //...
            draw_line(posx, posy, posx + lengthdir_x(100, dir), posy + lengthdir_y(100, dir)); //Irá desenhar linhas partindo das extremidades, essas terão tamanho de 100 pixels e estarão na direção da variável "dir", usaremos lengtdir_x,y. Poderíamos ter usado seno e cosseno, mas não precisamos reinventar a roda.
        }
    }
}

Efeito luz e sombra [parte 1] UTYrg-uSTX6qnV4Evm7lDA

Ao compilar terá um resultado parecido com a imagem acima, note que pintei de vermelho os vértices das linhas que não precisam ser desenhadas. Tem um truque simples para remover essas linhas indesejadas, repare que o par de linhas a desenhar possui um angulo maior que as outras, vou colocar uma imagem para você entender melhor.

Efeito luz e sombra [parte 1] NLWN7Bd7T7ifablrd_ibBQ

Na imagem desenhei todos os ângulos, presta atenção que o par de linhas que definirão nossa sombra será o par que possui o maior ângulo, e nesse caso serão as linhas do ângulo vermelho. No próximo passo irei novamente modificar o evento "draw" do LightController, iremos calcular o maior angulo e apenas duas linhas serão desenhadas e representarão nossa sombra.

Event Draw LightController -> Draw
Código:
for(i = 0; i < instance_count; i++){
    if(instance_id[i].object_index == Block){
        tmp = instance_id[i];
        linha[0,0] = 0; //Matriz que armazenara as posições x,y e a direção. A primeira chave indica qual linha estamos manipulando, no nosso caso 2 linhas a 0 e 1. Na segunda chave 0 é o ponto X da extremidade, 1 é o ponto y, e 2 é o angulo entre a extremidade e o mouse.
        
        maxAngle = 0; //Antes de entrar no looping com 2 fors, setaremos o máximo angulo como 0.
        for(l = 0; l < 4; l++){
            for(j = 0; j < 4; j++){ //Os 2 fors combinarão todas as nossas extremidades, e iremos pegar a que tiver o maior angulo entre si.
                if(i != j){ //Não iremos comparar a mesma extremidade..
                    dirLinha1 = point_direction(mouse_x, mouse_y, tmp.edge[l,0], tmp.edge[l,1]); //Direção da extremidade "l" em relação a posição do mouse
                    dirLinha2 = point_direction(mouse_x, mouse_y, tmp.edge[j,0], tmp.edge[j,1]); //Direção da extremidade "j" em relação a posição do mouse
                    ang = abs(angle_difference(dirLinha1, dirLinha2)); //calcula o angulo entre a linha1 e a linha2
                    
                    if(l == 0 || abs(ang) > maxAngle){ //Se caso o angulo atual for maior maxAngle, então devemos atualizar o par de linhas a serem escolhidas
                        linha[0,0] = tmp.edge[l, 0];
                        linha[0,1] = tmp.edge[l, 1];
                        linha[0,2] = dirLinha1;
                        //A nova linha escolhida partirá da extremidade "l"

                        linha[1,0] = tmp.edge[j, 0];
                        linha[1,1] = tmp.edge[j, 1];
                        linha[1,2] = dirLinha2;
                        //A outra nova linha escolhida partirá da extremidade "j"
                        
                        maxAngle = ang; //Atualiza o maxAngle para o angulo atual
                    }
                }
            }
        }
        
        draw_line(linha[0,0], linha[0,1], linha[0,0] + lengthdir_x(100, linha[0,2]), linha[0,1] + lengthdir_y(100, linha[0,2]));  //Desenha a linha 0
        draw_line(linha[1,0], linha[1,1], linha[1,0] + lengthdir_x(100, linha[1,2]), linha[1,1] + lengthdir_y(100, linha[1,2]));  //Desenha a linha 1

    }
}

No código, a matriz "linha" armazenará as informações das extremidades selecionadas. A primeira chave indica qual linha estou manipulando, e a segunda chave caso for: 0 é a posição X da linha, 1 posição Y da linha, 2 é o ângulo entre a posição da extremidade e a posição mouse.

Efeito luz e sombra [parte 1] -UUSvqGCRzOd07U3KvOGkw

Ao compilar você terá algo parecido com a imagem acima, agora as duas linhas desenhadas representam corretamente nossa sombra. Brinque um pouco e veja que as linhas se alteram de acordo com a posição do mouse do modo que queríamos que fosse.

Desenhando formas primitivas no lugar das linhas  Cool
As linhas deram um efeito bacana, mas ainda não é o que procuramos. A melhor maneira de representar a sombra seria usando uma trapézio, sabemos que no GameMaker podemos desenhar várias formas, por exemplo, círculos, quadrados, e triângulos. Entretanto nenhum se encaixa para o nosso formato, uma saída que encontrei para isso seria utilizar as formas primitivas. Basicamente, para desenhar uma forma primitiva passamos uma sequência de pontos e o GameMaker magicamente une os pontos formando assim um polígono. Aconselho a dar uma olhada no help sobre o tema, 2D primitives. Vamos para última alteração do código!

Event Draw LightController -> Draw
Código:
for(i = 0; i < instance_count; i++){
    if(instance_id[i].object_index == Block){
        tmp = instance_id[i];
        linha[0,0] = 0;
        maxAngle = 0;
        for(l = 0; l < 4; l++){
            for(j = 0; j < 4; j++){
                if(i != j){
                    dirLinha1 = point_direction(mouse_x, mouse_y, tmp.edge[l,0], tmp.edge[l,1]);
                    dirLinha2 = point_direction(mouse_x, mouse_y, tmp.edge[j,0], tmp.edge[j,1]);
                    ang = abs(angle_difference(dirLinha1, dirLinha2));
                    
                    if(i == 0 || abs(ang) > maxAngle){
                        linha[0,0] = tmp.edge[l, 0];
                        linha[0,1] = tmp.edge[l, 1];
                        linha[0,2] = dirLinha1;
                        
                        linha[1,0] = tmp.edge[j, 0];
                        linha[1,1] = tmp.edge[j, 1];
                        linha[1,2] = dirLinha2;
                        maxAngle = ang;
                    }
                }
            }
        }
        
        //draw_line(linha[0,0], linha[0,1], linha[0,0] + lengthdir_x(100, linha[0,2]), linha[0,1] + lengthdir_y(100, linha[0,2]));
        //draw_line(linha[1,0], linha[1,1], linha[1,0] + lengthdir_x(100, linha[1,2]), linha[1,1] + lengthdir_y(100, linha[1,2]));
        //Comentei as linhas pois agora usaremos primitivas \o/
        
        draw_set_color(c_black);
        draw_set_alpha(1);
        //Só definindo a opacidade e a cor da sombra.

        draw_primitive_begin(pr_trianglestrip); //Começa a desenhar uma primitiva, antes do comando draw_primitive_end() passamos uma lista de pontos, triangleship é o tipo de preenchimento (vá no help do gamemaker para ver os outros tipos).

        //Passamos então a nossa lista de pontos
        draw_vertex(linha[0,0], linha[0,1]);
        draw_vertex(linha[0,0] + lengthdir_x(6000, linha[0,2]), linha[0,1] + lengthdir_y(6000, linha[0,2])); //6000 é um valor bem alto, pois queremos garantir que a sombra seja maior que o tamanho da Room.
        draw_vertex(linha[1,0] + lengthdir_x(6000, linha[1,2]), linha[1,1] + lengthdir_y(6000, linha[1,2]));
        draw_vertex(linha[1,0], linha[1,1]);
        draw_vertex(linha[0,0], linha[0,1]);

        draw_primitive_end(); //Após passar a lista de pontos chamamos a função para renderizar a primitiva.
    }
}

Efeito luz e sombra [parte 1] TA1CyqtEQ1eMADuCb01GeQ
O resultado final será algo como a imagem acima. Repare que todos as sombras devem ser maior que o tamanho da room.

Conclusão
Finalizamos a parte 1, acho que a mais difícil (pra tu ver como é fácil, a mais difícil já acabou cheers). No próximo tutorial vou trazer um pouco de Blending de superfícies, isso vai dar um toque bem interessante na sombra. É isso, qualquer dúvida, ou crítica é só deixar nos comentários. Vlw.


Última edição por Lighter em Seg 10 Jul 2017, 05:07, editado 1 vez(es)
Lighter
Lighter

Games Ranking : Sem avaliações

Data de inscrição : 16/01/2014
Reputação : 31
Número de Mensagens : 317
Prêmios : Efeito luz e sombra [parte 1] Empty

Medalhas x 0 Tutoriais x 0 Moedas x 0

Ouro x 0 Prata x 1 Bronze x 0

Insignia 1 x 0 Insignia 2 x 1 Insignia 3 x 0

http://google.com

Ir para o topo Ir para baixo

Efeito luz e sombra [parte 1] Empty Re: Efeito luz e sombra [parte 1]

Mensagem por Tedi Ripper Dom 09 Jul 2017, 00:56

Wow, curti muito o tutorial, parabéns.

Achei muito bem explicado, eu sempre tive um pouco de dificuldade de entender como estas sombras eram projetadas.

Fico no aguardo do próximo tuto, também nunca sei usar surfaces kkk

+1

Vlw
Tedi Ripper
Tedi Ripper

Games Ranking : Sem avaliações

Data de inscrição : 21/11/2010
Reputação : 25
Número de Mensagens : 777
Prêmios : Efeito luz e sombra [parte 1] Empty

Medalhas x 0 Tutoriais x 0 Moedas x 0

Ouro x 0 Prata x 0 Bronze x 0

Insignia 1 x 0 Insignia 2 x 0 Insignia 3 x 0

Ir para o topo Ir para baixo

Efeito luz e sombra [parte 1] Empty Re: Efeito luz e sombra [parte 1]

Mensagem por Lighter Seg 10 Jul 2017, 04:58

Tedi Ripper escreveu:Wow, curti muito o tutorial, parabéns.

Achei muito bem explicado, eu sempre tive um pouco de dificuldade de entender como estas sombras eram projetadas.

Fico no aguardo do próximo tuto, também nunca sei usar surfaces kkk

+1

Vlw

Vlw tedi. Legal que deu de entender, achei que expliquei mal ou enrolei em algumas partes (T.T). Vou tentar trazer a segunda parte no final de semana. E realmente, esse efeito parece ser um sistema bem complexo de implementar, mas é só uma projeção entre 2 linhas XD.
Lighter
Lighter

Games Ranking : Sem avaliações

Data de inscrição : 16/01/2014
Reputação : 31
Número de Mensagens : 317
Prêmios : Efeito luz e sombra [parte 1] Empty

Medalhas x 0 Tutoriais x 0 Moedas x 0

Ouro x 0 Prata x 1 Bronze x 0

Insignia 1 x 0 Insignia 2 x 1 Insignia 3 x 0

http://google.com

Ir para o topo Ir para baixo

Efeito luz e sombra [parte 1] Empty Re: Efeito luz e sombra [parte 1]

Mensagem por Conteúdo patrocinado


Conteúdo patrocinado


Ir para o topo Ir para baixo

Ir para o topo

- Tópicos semelhantes

 
Permissões neste sub-fórum
Não podes responder a tópicos