Arrastando com o mouse

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

Arrastando com o mouse

Mensagem por saim em Qua 04 Abr 2012, 12:17

Sim, essa é uma pergunta muito básica, mas é justamente porque é tão simples que eu não consigo imaginar onde está o erro.
Toda vez que quero arrastar um objeto com o mouse, eu uso a seguinte rotina:
Create:
Código:
mxp = mouse_x; myp = mouse_y; //as posições (x/y) do mouse no step anterior
drag = false; //se é pra arrastar
step:
Código:
if (drag == true){
   x += mouse_x - mxp; //desloca o objeto na mesma quantidade que o mouse
   y += mouse_y - myp; //desloca o objeto na mesma quantidade que o mouse
   }
mxp = mouse_x; myp = mouse_y; //atualiza a posição prévia do mouse no FINAL do evento, depois de ter arrastado
clicar:
Código:
drag = true;
soltar o botão do mouse:
Código:
drag = false

Isso funciona até eu me empolgar. Arrasto o objeto pra todo canto e ele continua preso no cursor do mouse, na mesmíssima posição relativa ao mouse em que ele estava quando foi clicado.
Mas quando eu me empolgo (chacoalho o objeto rapidamente até onde a tela alcança), o objeto muda de posição com relação ao mouse, o que me permite arrastar um objeto que NÃO ESTÁ sob o cursor e, se eu uso o evento "left released" ao invés do "global left released", até me impede de soltar o objeto.
Em alguns casos, isso demora a acontecer, em outros, acontece rapidamente.

Fiz um teste que consiste em adicionar as seguintes linhas:
create:
Código:
v3 = 0; //um valor pra testar (já tinha feito outros testes)
draw:
Código:
v3 = max(v3, abs(mouse_x - mxp));
draw_text(20, 40, string(v3));
Por um tempo, o valor de v3 permaneceu constante (0), mas depois de um pouco de empolgação subiu pra 153.

Como pode um valor que, no final do normal step event tem a instrução de se igualar a mouse_x ser diferente dele no draw event?

Obs: o erro acontece da mesma forma quando eu uso o begin step ou o end step

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: Arrastando com o mouse

Mensagem por PedroX em Qua 04 Abr 2012, 12:23

Código:
if mouse_check_button_pressed(mb_left) && position_meeting(mouse_x, mouse_y, id)
{
mx = x - mouse_x
my = y - mouse_y
drag = 1
}

if mouse_check_button_released(mb_left) && drag
{
drag = 0
}

if drag
{
x = mouse_x + mx
y = mouse_y + my
}

Você poderia tentar isso. Eu não testei, mas pode funcionar.

PedroX

Ranking : Nota C
Número de Mensagens : 6034
Idade : 21
Data de inscrição : 26/07/2008
Notas recebidas : C+B
Reputação : 286
Insignia 1 x 0 Insignia 2 x 0 Insignia 3 x 0
Prêmios
   :
   :
   :

Voltar ao Topo Ir em baixo

Re: Arrastando com o mouse

Mensagem por saim em Qua 04 Abr 2012, 16:46

Funcionou, Pedrø! E, aparentemente, eu posso empolgar à vontade. Seu sistema é bem mais confiável.
Demorei, mas entendi seu raciocínio, você define, ao clicar, um deslocamento entre a posição do mouse e a posição x/y do objeto e, ao invés de definir o quanto ele se move no step, você define a posição que ele está. Certo?
Bom, isso resolve a questão prática, já adaptei pros eventos que eu usava antes (isso é importante pra minha cabeça ficar organizada) e funcionou direitinho.

Mas ainda tem a questão teórica, aquele último teste que eu fiz no post original:
create:
Código:
v3 = 0; //um valor pra testar (já tinha feito outros testes)

step (begin, normal ou end):
Código:
mxp = mouse_x; myp = mouse_y; //atualiza a posição prévia do mouse no FINAL do evento, depois de ter arrastado

draw:
Código:
v3 = max(v3, abs(mouse_x - mxp));
draw_text(20, 40, string(v3));
O valor desenhado deveria ser SEMPRE zero, mas é alterado quando a gente empolga. Tenho certeza que é isso o que causa os erros do meu (antigo) sistema, mas não sei porque acontece.
Alguém arrisca um palpite?

Edit: Pensando bem, não resolve o problema. Já te explico porque, só não responda ainda. O buraco é mais embaixo.

Bom, como sempre, eu expliquei somente parte do problema. É que eu estou tentando criar um sistema de arrastar o objeto em que a posição do mouse possa fazer ele ficar pendurado. Deixa eu copiar/colar os eventos completos (avisando que a origem/âncora do objeto está no centro da sprite):
create:
Código:

angAcc = 0.01; //aceleração angular
angSpeed = 0; //velocidade angular
drag = false; //se está sendo arrastado
step:
Código:

if (drag == true){
   dist = point_distance(x, y, mouse_x, mouse_y); //distância do centro ao mouse
   ang = point_direction(x, y, mouse_x, mouse_y); //ângulo do centro ao mouse
   px1 = mouse_x; py1 = mouse_y; //o ponto do mouse no início do movimento
   angSpeed += (mouse_x - x) * angAcc; //se o mouse_x não for igual a x, o objeto ganha momento angular
   angSpeed *= 0.99; //um pouco de atrito
   if (abs(angSpeed) <= 0.01){
      angSpeed = 0; //um arredondamento (pode ser útil no futuro)
      }
   image_angle += angSpeed; //se (angSpeed != 0), o objeto gira
   px2 = x + lengthdir_x(dist, ang + angSpeed); py2 = y + lengthdir_y(dist, ang + angSpeed); //o ponto do objeto em que o mouse estava se deslocou pra posição px2,py2
   x += px1 - px2; y += py1 - py2; //o objeto se desloca na mesma proporção
   // x = (mouse_x - dx); y = (mouse_y - dy); //o objeto é arrastado pelo mouse
   }
   else {
      angSpeed = 0; //isso é só pra teste, na versão definitiva, o movimento continua
      }
apertar botão esquerdo (poderia ser apertar pra drag=true e soltar pra drag=false, mas minha mão estava começando a doer):
Código:
drag = !drag;
if (drag == true){
   dx = mouse_x - x;
   dy = mouse_y - y;
   }
Bom, ainda tem mais um pouco de código, mas é que eu usei pra testes. AGORA acho que está completo.

Se não ficou claro, eu explico o código: ao arrastar o clicar no objeto, eu quero que o peso dele e a posição do mouse influenciem no ângulo dele, ou seja, que ele pareça estar pendurado no cursor. Como ele não tem PESO, eu defini o ganho de momento como uma aceleração angular e fiz essa aceleração depender da distância entre a posição (em x) do mouse e o centro de gravidade (que, POR ENQUANTO, é a origem do objeto).

Ora, se o objeto vai girar em torno do seu centro de gravidade, NÃO vai girar em torno da posição do mouse, então vai se desprender do mouse. Depois de muita geometria, concluí que seria mais fácil calcular esse deslocamento após o giro do que através de trigonometria. Por isso peguei a distância e ângulo antes do giro e usei pra calcular a posição do mouse após o giro. Usei esses valores pra DESLOCAR o objeto de modo que a nova posição dele faça com que o ponto clicado permanesça sob o mouse.

Por isso o novo método não funciona. Ele define a posição do objeto, de forma que o deslocamento definido anteriormente fica ignorado.

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: Arrastando com o mouse

Mensagem por PedroX em Qua 04 Abr 2012, 18:38

Você poderia usar o código passado, centralizar a sprite em tempo de execução na posição do mouse. Ai você muda o ângulo da sprite para que a antiga origem fique para baixo.

sprite_set_offset(sprite_index, mouse_x + sprite_width/2 - x, mouse_y + sprite_height/2 - y)

Até mais!

PedroX

Ranking : Nota C
Número de Mensagens : 6034
Idade : 21
Data de inscrição : 26/07/2008
Notas recebidas : C+B
Reputação : 286
Insignia 1 x 0 Insignia 2 x 0 Insignia 3 x 0
Prêmios
   :
   :
   :

Voltar ao Topo Ir em baixo

Re: Arrastando com o mouse

Mensagem por saim em Qua 04 Abr 2012, 22:16

Pedrø, desculpe por estar sendo chato, mas é que o que eu quero MESMO é saber o motivo do erro.

Quanto a mudar a origem... isso é fácil quando a sprite é retangular: o centro de massa fica no centro da caixa de colisão, não importa o ângulo em que ela esteja. Isso me permite usar esse método. Tem que adaptar a posição do objeto, mas dá.
Mas no jogo (utópico, atualmente) em que essa engine seria utilizada, o centro de massa poderia ser calculado de forma complexa. Quer dizer, as sprites seriam complexas, geradas pelo jogador. Então calcular o centro de massa em tempo real pode ser inviável.
Não digo que eu vá, efetivamente, chegar nesse nível de complexidade. Provavelmente será bem mais prático (até para o jogador) permitir ao jogador carregar alguns objetos e criar sprites fatiadas a partir de outros.

Mas é que eu gostaria de corrigir o problema ao invés de encontrar uma solução alternativa. Ou pelo menos entender o problema antes de mudar o paradigma.

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: Arrastando com o mouse

Mensagem por cascavelo em Qua 04 Abr 2012, 23:28

Saim, sobre o seu código de simulação de fisica eu não entedi muita coisa, mas no primeiro código postado o problema é que no step o computador está somando ou subtraindo mais de uma vez entre as posições do mouse.
Ele entra várias vezes no if (drag == true) enquanto você move um Pixel e vai acumulando ou retirando posições.

cascavelo

Ranking : Nota A
Número de Mensagens : 1011
Idade : 46
Data de inscrição : 08/12/2011
Notas recebidas : A - A - A - A - A -A -C
Reputação : 71
Insignia 1 x 0 Insignia 2 x 0 Insignia 3 x 0
Prêmios
   : 1
   : 2
   : 1

Voltar ao Topo Ir em baixo

Re: Arrastando com o mouse

Mensagem por saim em Seg 09 Abr 2012, 15:43

@cascavelo:
Não entendi o que você quis dizer... no primeiro código só há uma soma em x e uma em y.

A parte PRÁTICA foi resolvida! Eu realmente não quero mudar a origem de sprite, porque preciso dela pra ser o centro de massa (porque não quero ficar calculando esse centro a todo instante), mas com a primeira dica do Pedrø, fiz o seguinte:
step:
Código:
if (drag == true){
//move em função de dx e dy
//gira e atualiza a posição, como antes
//atualiza os valores de dx e dy
}
ou, mais exatamente,
Código:
if (drag == true){
   //move
   x = mouse_x - dx; y = mouse_y - dy;

   //gira
   ang = point_direction(x, y, mouse_x, mouse_y);
   angSpeed += (mouse_x - x) * angAcc;
   angSpeed *= atrito;
   p1x = mouse_x; p1y = mouse_y;
   image_angle += angSpeed;
   p2x = x + lengthdir_x(comp, ang + angSpeed); p2y = y + lengthdir_y(comp, ang + angSpeed);
   x += p1x - p2x; y += p1y - p2y;

   //atualiza dx e dy
   dx = mouse_x - x; dy = mouse_y - y;
   }
left click:
Código:
drag = true;
dx = mouse_x - x; dy = mouse_y - y;
global_left_release:
Código:
drag = false;
angSpeed = 0;
Agora posso arrastar o objeto à vontade sem medo da posição do mouse em relação a ele mudar. O que faltava era atualizar a posição antes de girar e atualizar a diferença após o giro.

MAS ainda restam algumas miudezas que podem estar relacionadas ou não.
Notaram o negrito em global_left_released? É que a posição do mouse parece ser atualizada em algum momento obscuro. Não importa em que evento eu coloque aquele código do "step" (begin step, normal step, end step ou até draw), o cursor do mouse parece ter um avanço anterior ao do objeto, o que permite, em algumas circunstâncias, de SOLTAR o botão do mouse ANTES do objeto estar sob o mouse, de forma que o evento de soltar, pra funcionar sempre, tenha que ser global. Alguém sabe como fazer pra evitar isso?

E, claro, tem aquele outro problema: porque é que mesmo eu colocando "mxp = mouse_x" em diversos tipos de eventos, o valor de "mouse_x - mxp" ainda consegue ser diferente de zero no draw_event (se eu chacoalhar o mouse com força suficiente)?

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: Arrastando com o mouse

Mensagem por Kabeção em Seg 09 Abr 2012, 17:44

Como a posição do mouse é global ele deve ser atualizado depois do draw antes mesmo do begin step então do begin step ao draw mouse_x é sempre o mesmo.
Mas o Windows não atualiza o mouse só a alguns fps então acho impossível não ter atraso. Talvez usando window_mouse_get_x ele de a posição exata mas como mouse_x só atualiza 60 ou 30 vezes por segundo dependendo da room_speed ele nunca vai ser exato se o mouse se mexe rapidamente.
Já notou como o mouse costuma ser mais lento em jogos do que no desktop? Não é apenas porque o jogo pode diminuir a precisão dele mas sim porque ele tem uma velocidade de atualização muito mais baixo que o sistema operacional.

O ideal seria não usar o cursor padrão do sistema e desenha-lo você mesmo no jogo para não ter aquela sensação de atraso (embora tenha a sensação de lentidão).

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: Arrastando com o mouse

Mensagem por cascavelo em Ter 10 Abr 2012, 10:49

Kabeção, acho que que é isto mesmo, estou fazendo um editor de fases para um jogo meu e uma mira acompanha o ponteiro do mouse sempre na mesma posição e acontece o seguinte: No meu PC de casa que é top a mira fica sempre embaixo do ponteiro do mouse, já no PC do escritório que é meia boca ela começa embaixo do mouse mas quando arrasto para o final da fase que tem 6000 px ele fica uns 10cm atrasada, quando clico o iten aparece na posição da mira, então eu só ia esconder o ponteiro do mouse é tava tudo bem, mas achei bem estranho este comportamento do editor, já que o código que me lembro é simplesmente x=mouse_x. A room speed é de 50, vou alterar pra ver o que acontece. Em outro jogo usei a função window_mouse_get_x, funcionou bem mas quando testei em um monitor de formato diferente,(não de resolução diferente, mas formato mesmo), bagunçou tudo. No fim minha cabeça já deu um nó, quando tiver tempo vou examinar tudo passo a passo pra entender o que acontece. Por enquanto vou continuar assim mesmo porque té funcionando bem.

cascavelo

Ranking : Nota A
Número de Mensagens : 1011
Idade : 46
Data de inscrição : 08/12/2011
Notas recebidas : A - A - A - A - A -A -C
Reputação : 71
Insignia 1 x 0 Insignia 2 x 0 Insignia 3 x 0
Prêmios
   : 1
   : 2
   : 1

Voltar ao Topo Ir em baixo

Re: Arrastando com o mouse

Mensagem por saim em Ter 10 Abr 2012, 12:19

Kabeção escreveu:Como a posição do mouse é global ele deve ser atualizado depois do draw antes mesmo do begin step então do begin step ao draw mouse_x é sempre o mesmo.
Se é sempre o mesmo valor, porque mxp (definido "=mouse_x" em algum step) poderia ser diferente de mouse_x no draw? Ou o que você disse depois contradiz essa afirmação? (eu fiquei meio confuso mesmo).
Kabeção escreveu:O ideal seria não usar o cursor padrão do sistema e desenha-lo você mesmo no jogo para não ter aquela sensação de atraso (embora tenha a sensação de lentidão).
Deixa eu ver se acompanhei seu raciocínio: Eu desabilito a exibição do cursor do windows, crio um novo e defino, (digamos) no começo do begin step uma variável "meuMouseX = mouse_x" e passo o resto da programação do objeto usando essa nova variável? É, se o problema for alguma atualização da posição do mouse entre os eventos, pode resolver.

@Cascavelo, o que está acontecendo contigo é um problema muito comum. Você está forçando a view ou a room pra caber numa tela menor que ela. Isso dá uma zica na posição do mouse, que fica proporcional ao enquadramento. Assim, ele nunca irá tocar o ponto inferior direito da tela, embora o cursor do windows o faça. Sugiro adaptar suas views pra caberem em qualquer monitor (você pode usar display_get_width/height pra saber o tamanho do monitor).
Não me pergunte porque acontece. Quando entra nesses assuntos de escala, minha cabeça dá nó.

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: Arrastando com o mouse

Mensagem por Kabeção em Ter 10 Abr 2012, 12:56

Se é sempre o mesmo valor, porque mxp (definido "=mouse_x" em algum step) poderia ser diferente de mouse_x no draw? Ou o que você disse depois contradiz essa afirmação? (eu fiquei meio confuso mesmo).
Hum, eu já tinha testado aqui e do begin step ao draw os valores eram os mesmos. Quando saiu o GM HTML Beta parecia que algumas variáveis globais não eram definidas da mesma forma.
Pode ter alguma diferença entre as versões, eu uso a 8.0.

Acabei de testar o window_get_mouse e ele é a mesmo coisa que mouse_x/y...

Deixa eu ver se acompanhei seu raciocínio: Eu desabilito a exibição do cursor do windows, crio um novo e defino, (digamos) no começo do begin step uma variável "meuMouseX = mouse_x" e passo o resto da programação do objeto usando essa nova variável? É, se o problema for alguma atualização da posição do mouse entre os eventos, pode resolver.
É, pelo menos assim o cursor não vai ficar desatualizado com mouse_x/y.

@cascavelo
Ai já é mesmo um problema de resolução como o saim mencionou.

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: Arrastando com o mouse

Mensagem por cascavelo em Ter 10 Abr 2012, 13:55

Realmente saim, o problema aqui era a room maior que a resolução deste monitor, eu havia colocado 1400px na view de edição de fases e não sabia que a resolução deste monitor era só de 1280 na horizontal.
Passei a view para 1280 e agora a mira chega no fim da room, só que atrazada, o ponteiro chega um pouco antes dela, mas é só desabilitar o ponteiro e tá resolvido. Grato pela dica.

cascavelo

Ranking : Nota A
Número de Mensagens : 1011
Idade : 46
Data de inscrição : 08/12/2011
Notas recebidas : A - A - A - A - A -A -C
Reputação : 71
Insignia 1 x 0 Insignia 2 x 0 Insignia 3 x 0
Prêmios
   : 1
   : 2
   : 1

Voltar ao Topo Ir em baixo

Re: Arrastando com o mouse

Mensagem por Conteúdo patrocinado Hoje à(s) 15:41


Conteúdo patrocinado


Voltar ao Topo Ir em baixo

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

- Tópicos similares

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