solitaire

Ver o tópico anterior Ver o tópico seguinte Ir em baixo

solitaire

Mensagem por saim em Qui 04 Out 2012, 15:54

Como exercício, estou fazendo um solitaire. Sempre achei que a programação desse tipo de jogo era mais complicada do que parece, agora estou sentindo na pele. Meu problema está em selecionar apenas a carta em que cliquei. As que estão abaixo dela serão arrastadas junto e as que estão acima dela DEVERIAM ser ignoradas. Por enquanto, eu ainda não tomei nenhuma providência pra verificar se as cartas abaixo daquela clicada estão em ordem, eu apenas verifico isso na hora de soltar uma carta sobre a outra.

Estou ciente que uma carta estar por cima da outra não elimina o evento do clique da carta abaixo dela. Pra contornar isso, eu verifico se existe alguma carta sobre aquela clicada. Se não houver, o evento pode acontecer normalmente. Se houver, o evento só acontece se o mouse estiver na área visível da carta. No código, a variável "borda" é o espaçamento-padrão do jogo, também usado pra separar uma carta da outra.

A título de organização, eu uso um monte de triggers pra arrastar a carta clicada, pra arrastar as cartas acima dela, pra soltar as cartas, etc.

Quando as cartas estão fora de ordem, a coisa funciona direitinho. Eu consigo arrastar todas as cartas acima da clicada e nenhuma carta abaixo dela.

Quando eu já organizei umas 3 cartas, o caldo entorna. Eu clico na carta de cima de todas e mesmo assim arrasto as que estão abaixo dela. Tenho certeza que é alguma coisa no evento do clique, porque se o mouse está na parte de baixo da sprite, numa parte que NÃO toca a mask da carta de baixo, ela não é arrastada. Mas, bom, eu vim aqui porque não sei o que diabos está acontecendo.

Estou usando os seguintes códigos:
left_press_event
Código:
// só rodar o evento se o mouse estiver no espaço visível da carta,
// evitando arrastar cartas que estejam sob o mouse, mas abaixo da escolhida
var rodaEvento; rodaEvento = false;
if (cartaSobre == noone){ // a carta toda é visível
   rodaEvento = true;
   }
   else { // só um espaço da carta é visível
      if (mouse_y == median(y, y + borda, mouse_y)){ // se o mouse está entre o topo e o começo da próxima carta
         rodaEvento = true;
         }
      }

if (rodaEvento == false){
   exit;
   }
   else {
      if (keyboard_check(vk_enter)){
         show_message(id);
         }
      }

if (noMonte == false){ // se não é a carta no topo da coluna
   var cartaUnder;
   with(objCarta){
      if (cartaSobre == other . id){ // se eu estou por cima da outra
         cartaUnder = id; // a outra está abaixo de mim
         }
      }
   ultimaPos = cartaUnder; // pra poder voltar em caso de movimento inválido
   cartaUnder . cartaSobre = noone; // pra carta abaixo de mim saber que não estou mais lá
   }
   else { // noMonte == true
      ultimaPos = instance_place(x, y, objMonteJogo);
      noMonte = false;
      with (ultimaPos){
         primeiraCarta = noone;
         }
      }
event_perform(ev_trigger, 0); // define dx e dy e passa a arrastar a carta
trigger 0:
Código:
// evento de tirar a carta do lugar
drag1 = true;
dx = x - mouse_x; dy = y - mouse_y;
if (depth > -100) {
   depth = -100;
   }
event_perform(ev_trigger, 2); // manda as cartas acima serem arrastadas também
trigger 2:
Código:
if (cartaSobre != noone){
   with(cartaSobre){
      drag2 = true;
      dx = x - mouse_x; dy = y - mouse_y;
      depth = other . depth - 1;
      event_perform(ev_trigger, 2); // é esse mesmo evento, na próxima carta
      }
   }
Talvez seja alguma coisa definida em outros eventos. A seguir, mais alguns eventos que podem ser considerados importantes:
create:
Código:
// algumas variáveis são declaradas por outros objetos, ao criar da carta.
// valor, drag, sprite_index
drag1 = false; //drag pra carta arrastada
drag2 = false; //drag pras cartas acima dela
cartaSobre = noone;
noMonte = false;
global_left_release:
Código:
if (drag1 == true){ // evita de rodar o código em muitas cartas
   // deixa de arrastar
   drag1 = false;

   var jogadaPermitida; jogadaPermitida = false;

   var cartaUnder, monteUnder; cartaUnder = noone; monteUnder = noone;
   with(objCarta){
      if place_meeting(x, y, other){ // se está em contato
         if (cartaSobre == noone){ // se é a última da coluna
            if (valor[valor52] == valor[other . valor52] + 1 && cor[valor52] != cor[other . valor52]){ // se o valor é 1 acima da carta solta e a cor é diferente
               cartaUnder = id;
               }
            }
         }
      }
   with(objMonteJogo){
      if (primeiraCarta == noone && place_meeting(x, y, other)){
         monteUnder = id;
         }
      }

   if (cartaUnder != noone){ // se é permitido soltar numa carta
      jogadaPermitida = true;
      x = cartaUnder . x; y = cartaUnder . y + borda;
      depth = cartaUnder . depth - 1;
      cartaUnder . cartaSobre = id;
      // noMonte = false;
      }
      else if (monteUnder != noone){ // se não tem carta, mas tem coluna vazia
         jogadaPermitida = true;
         x = monteUnder . x; y = monteUnder . y;
         depth = monteUnder . depth - 1;
         monteUnder . primeiraCarta = id;
         noMonte = true;
         }

   if (jogadaPermitida == false){
      switch (ultimaPos . object_index){ // ultimaPos = id da última posição
         case objMonteCompra: {
            with(objMonteCompra){
               ds_list_add(ds_cartasMonteCompra, other . valor52);
               nCartasTela = min(nCartasTela + 1, 3);
               }
               instance_destroy();
            }; break;
         case objCarta: {
            x = ultimaPos . x; y = ultimaPos . y + borda;
            depth = ultimaPos . depth - 1;
            ultimaPos . cartaSobre = id;
            }; break;
         case objMonteJogo: {
            x = ultimaPos . x; y = ultimaPos . y;
            depth = ultimaPos . depth - 1;
            noMonte = true;
            ultimaPos . primeiraCarta = id;
            }; break;
         }
      }

   event_perform(ev_trigger, 1); // traz todo mundo pro lugar e para de arrastar

   }
trigger 1:
Código:
// junta todo mundo no mesmo lugar
with (cartaSobre){
   x = other . x; y = other . y + borda; drag2 = false; depth = other . depth - 1;
   event_perform(ev_trigger, 1);
   }
e, não acho importante, mas já que estamos aqui, tem o step também...
Código:
if (drag1 == true || drag2 == true){
   x = mouse_x + dx; y = mouse_y + dy;
   }
Se precisar de alguma explicação quanto ao significado de variáveis ou coisas assim, podem perguntar. Eu não verifiquei se está tudo comentado.

saim

Ranking : Nota B
Número de Mensagens : 2964
Idade : 38
Data de inscrição : 14/01/2011
Notas recebidas : C-D-A-B
Reputação : 121
Insignia 1 x 0 Insignia 2 x 0 Insignia 3 x 0
Prêmios
   : 1
   : 0
   : 3

Voltar ao Topo Ir em baixo

Re: solitaire

Mensagem por Kabeção em Qui 04 Out 2012, 18:57

É do tipo Paciência Spider?

Me parece que você está deixando a coisa mais complicada do que precisa ser. Happy

A começar pelo fato das próprias cartas controlarem suas ações. Isso da em confusão na certa.
Elas precisam apenas saber seu valor, sua coluna e o id da carta que está abaixo pois as de cima não interferem em nada, todo o resto pode ser controlado por outro objeto.
Com um controlador você tem mais precisam no debug já que não vai precisar monitorar um deck que pode até dezenas de cartas.

Na hora de checar a carta embaixo do mouse:
Código:
// objControle
if mouse_check_button_pressed(mb_left) {
    carta_id = noone;
    var yy;
    yy = 0;
   
    with (objCarta) {
        if (mouse_y > bbox_top && mouse_x > bbox_left && mouse_x < bbox_right) && y > yy {
            if instance_exists(carta_abaixo) {
                if (carta_abaixo.valor = valor-1) {
                    yy = y;
                    other.carta_id = id;
                }
            } else {
                yy = y;
                other.carta_id = id;
            }
        }
    }
}

if mouse_check_button(mb_left) && carta_id != noone {
    with (carta_id) {
        // ações
    }
}

O with torna essa tarefa mais fácil e precisa já que posso executar um código em todas as instancias do objCarta de uma vez e como eu trabalho apenas a variável carta_id do controlador eu removo qualquer possibilidade de duas ou mais cartas executarem suas ações ao mesmo tempo ou uma interferir com a outra.

Kabeção

Ranking : Sem avaliações
Número de Mensagens : 2314
Data de inscrição : 08/06/2008
Reputação : 100
Insignia 1 x 0 Insignia 2 x 0 Insignia 3 x 0
Prêmios
   : 3
   : 0
   : 1

http://blackcapapps.blogspot.com.br/

Voltar ao Topo Ir em baixo

Re: solitaire

Mensagem por saim em Qui 04 Out 2012, 19:49

Por alto é como o spider, mas é diferente. É o solitaire mesmo, do windows. Ah, agora entendi, ele agora vem traduzido! É o paciência.

Eu pensei nessa possibilidade mesmo, de usar um controlador, mas concluí que daria na mesma. Veja bem, o problema de usar o evento na própria carta é que pode selecionar mais de uma carta, certo? Isso foi contornado (em teoria) com a primeira parte do evento do clique. O problema é que tem uma diacha de uma situação em que isso não acontece.

Eu tenho outros objetos (os montes de onde comprar as cartas, os montes onde dispô-las no final) que também respondem aos cliques, por isso resolvi evitar o global_click.
Ah, e eu PRECISO interferir nas cartas que estão sobre a carta clicada, pra permitir arrastar uma coluna inteira de cartas que estão alinhadas. Portanto, preciso acompanhar quais cartas estão acima de quais. Eu posso fazer isso de um objeto externo, também, mas só se eu usar um "with(carta_id)", o que é o mesmo que rodar o código direto na carta.

Aparentemente, meu problema é isolar a carta clicada, mas estou com a impressão que não é isso... Eu tenho um debug_code que mostra a id da carta, repete o teste da posição do mouse, além de outras coisas e mostra em uma show_message. Quando eu testo isso, tudo acontece conforme esperado. Mas ao clicar na carta de cima que está em ordem, a de baixo ainda é arrastada...

saim

Ranking : Nota B
Número de Mensagens : 2964
Idade : 38
Data de inscrição : 14/01/2011
Notas recebidas : C-D-A-B
Reputação : 121
Insignia 1 x 0 Insignia 2 x 0 Insignia 3 x 0
Prêmios
   : 1
   : 0
   : 3

Voltar ao Topo Ir em baixo

Re: solitaire

Mensagem por Kabeção em Sex 05 Out 2012, 12:51

Também não consigo ver o erro pelo código.
Talvez com um exemplo executável...

Porque não tenta reprogramar?
As vezes corrigir isso vai ser mais demorado ou mais trabalhoso do que refazer.

Kabeção

Ranking : Sem avaliações
Número de Mensagens : 2314
Data de inscrição : 08/06/2008
Reputação : 100
Insignia 1 x 0 Insignia 2 x 0 Insignia 3 x 0
Prêmios
   : 3
   : 0
   : 1

http://blackcapapps.blogspot.com.br/

Voltar ao Topo Ir em baixo

Re: solitaire

Mensagem por saim em Sex 05 Out 2012, 13:41

Hehehe... eu demorei pra enviar a edição da minha postagem anterior, você postou antes. Eis o que eu ia colocar:

Não, kabeção, você tem razão. Tem outros aspectos do jogo que podem ser agilizados ao usar mais ativamente o controle (eu posso abandonar códigos recursivos e usar loops simples). Vou refazer os códigos.
Na prática, esse tópico perdeu o sentido, já que os códigos serão bem diferentes. Se alguém conseguir identificar o erro, a título de curiosidade, me mande uma MP. No mais, podem trancar o tópico.

Ou seja, concordo plenamente. Acho que recomeçar, nesse caso, tem mais vantagens que desvantagens.

Obrigado!

saim

Ranking : Nota B
Número de Mensagens : 2964
Idade : 38
Data de inscrição : 14/01/2011
Notas recebidas : C-D-A-B
Reputação : 121
Insignia 1 x 0 Insignia 2 x 0 Insignia 3 x 0
Prêmios
   : 1
   : 0
   : 3

Voltar ao Topo Ir em baixo

Re: solitaire

Mensagem por Conteúdo patrocinado Hoje à(s) 07:42


Conteúdo patrocinado


Voltar ao Topo Ir em baixo

Ver o tópico anterior Ver o tópico seguinte Voltar ao Topo


 
Permissão deste fórum:
Você não pode responder aos tópicos neste fórum