Como identifico cliques do mouse versus mouse down nos jogos?

8

Qual é a maneira mais comum de lidar com cliques do mouse em jogos?

Dado que tudo que você tem para detectar a entrada do mouse é se um botão está para cima ou para baixo.

Atualmente, apenas confio no mouse para baixo como um clique, mas essa abordagem simples me limita muito no que quero alcançar. Por exemplo, eu tenho algum código que deve ser executado apenas uma vez em um clique do mouse, mas usar o mouse para baixo como um clique do mouse pode fazer com que o código seja executado mais de uma vez, dependendo de quanto tempo o botão for pressionado. Então, eu preciso fazer isso com um clique!

Mas qual é a melhor maneira de lidar com um clique? É um clique quando o mouse passa do mouse para cima ou para baixo ou de baixo para cima ou é um clique se o botão estiver pressionado por menos de x quadros / milissegundos e, em caso afirmativo, será considerado o mouse para baixo e um clique se estiver pressionado por x quadros / milissegundos ou um clique e depois o mouse para baixo?

Percebo que cada uma das abordagens pode ter seus usos, mas qual é a mais comum em jogos? E talvez eu pergunte mais especificamente qual é o mais comum nos jogos RTS?

Tristan
fonte
11
Você está no caminho certo. Acrescente algo sobre o fato de que o mouse para baixo e o mouse para cima precisam estar próximos um do outro (ou dentro dos limites do objeto clicado) e você consegue. Clicar em um botão, arrastar e soltar o botão não é um clique do mouse. Mas clicar no botão e soltá-lo em qualquer lugar do botão é um clique do mouse.
Tim Holt

Respostas:

12

Você está no caminho certo para descobrir quando o mouse está fazendo a transição de baixo para cima e escrevendo um manipulador para isso. Para muitos jogos, é bom o suficiente para tratar um evento mouseUp como um clique.

Dependendo do seu jogo, você provavelmente desejará lidar com ambos os eventos - por exemplo, em um RTS, você provavelmente incorporará a seleção da caixa de arrasto e a seleção com um único clique. A diferença está em determinar quanto tempo o mouse estava no estado Inativo antes de ser lançado.

(Sim, você basicamente respondeu sua própria pergunta)

Conta
fonte
2
Como outros comentadores apontaram, você provavelmente também desejará verificar se o mesmo alvo foi apontado no mouseDown e mouseUp ao trabalhar com cliques únicos.
Bill
Eu não tenho tanta certeza. Por exemplo, os botões do Windows não se importam onde o mouse estava pressionado, contanto que o botão receba o evento mouse up. Talvez outros sistemas operacionais se importem mais.
John McDonald
@ John McD Não é tanto um requisito técnico, mas um requisito de "descobrir o que seu usuário realmente queria clicar".
Bill
11
@John McD. isso não é verdade. Pressione o botão do mouse em algum lugar da área de trabalho, mova o cursor para o Menu Iniciar e solte - o Menu Iniciar aparece? Não é para mim.
Kylotan
@Kylotan, você estaria correto, embora o "botão" do menu iniciar se comporte de maneira diferente de todos os outros botões padrão. Parece que os botões padrão do Windows realmente exigem os eventos de mouse para baixo e de mouse para cima, embora o mouse possa se mover para fora dos limites do botão no meio. Minimizar, Maximizar e Fechar funcionam assim, assim como os botões normais dentro dos aplicativos. Mas observe que nenhuma ação ocorre (exceto com o botão iniciar) até que o botão do mouse seja liberado, pessoas como eu perceberão. De qualquer forma ... Bill está certo, tudo se resume a requisitos.
John McDonald
4

Não há 'melhor' - você precisa de todos eles.

Se estou disparando uma arma, não quero esperar que o mouse seja liberado para ativar o efeito de disparo da arma. E se você estiver arrastando uma caixa em torno de várias unidades, inicie a ação de arrastar com o mouse para baixo.

Por outro lado, se eu estiver clicando em um item da GUI, desejo aguardar o clique completo, porque é com isso que estou acostumado.

Portanto, você provavelmente deve implementar o mouse para baixo, o mouse para cima, o arraste do mouse (mouse para cima em um local significativamente diferente do mouse para baixo) e clique com o mouse (mouse para cima no mesmo local que o mouse para baixo) e conectá-los a partes do jogo como você achar melhor.

Kylotan
fonte
1

A maneira como a maioria dos sistemas de janelas lida com isso, assim como os jogos nos quais trabalhei (e tive que me implementar parcialmente) é ter um pouco em cada botão que detecta se o mouse entrou no estado de inatividade do mouse sobre o botão fornecido. É definido apenas o quadro em que o mouse fica pressionado e limpo somente quando o botão do mouse é liberado. Se, e somente se, o mouse for liberado sobre o botão e o bit estiver definido, dispare o evento clicado no botão.

(Você provavelmente também deseja um sinalizador que seja definido quando o bit estiver definido e o mouse passar o mouse sobre o botão, para que você possa alterá-lo para usar uma textura pressionada em vez da textura normal.)

Este é o esquema básico por trás da maioria dos botões. Vá em frente e encontre um prompt de diálogo. Pressione o botão Cancelar, mas não solte. O botão fica pressionado enquanto o mouse está sobre ele e volta ao normal se o mouse parar de pairar sobre ele, mas voltará a ser pressionado se você voltar sobre ele. Ele só executa sua ação se você deixar ir e acabar com isso. Não use uma contagem de milissegundos, principalmente para detectar cliques duplos dentro do seu limite.

(e se você realmente quer ser chique, tem eventos que podem ser conectados a cada uma dessas transições. por exemplo, MouseOver ao entrar e à saída, MouseDown entra / sai, MouseUp entra / sai, MouseUp entra / sai, MouseClicked entra / sai, etc. )

Alex Ames
fonte
1

Os botões do mouse e as teclas do teclado podem ter vários eventos diferentes, o que está disponível depende da sua escolha de idioma / biblioteca, o mais comum:

Pressione a tecla, dispara quando um botão é pressionado.
Tecla para cima, dispara quando um botão é liberado.
A tecla pressionada é pressionada, é acionada quando um botão é pressionado e é acionada repetidamente em algum intervalo dependente do sistema até que a tecla seja liberada.

Além disso, também pode haver uma ligação para informar se uma tecla está ou não pressionada no momento.

É importante que você esteja ciente exatamente de qual ferramenta está usando; geralmente, você precisará primeiro das duas, se elas não estiverem disponíveis, construa-as a partir do que estiver disponível.

O método padrão para registrar que um botão na tela é pressionado usando o mouse é afirmar que o mesmo botão foi apontado para os eventos down e up. No entanto, para muitos elementos do jogo, isso pode ser muito lento, portanto, para muitas ações, pode ser prudente fazê-las acontecer no evento inativo.

aaaaaaaaaaaa
fonte
0

XOr pode ser seu amigo nesta situação.

bool oldIsButtonUp = true;

void pollMouse(bool isButtonUp) {
    if ((oldIsButtonUp ^ isButtonUp) && isButtonUp) {
        sendMouseClickEvent();
    }
    oldIsButtonUp = isButtonUp;
}

Isso chamará sendMouseClickEvent () sempre que o estado do botão do mouse for alterado de falso para verdadeiro.

Asgeir
fonte
4
Ou, de modo a não tornar um programador criar um truthtable em sua (ela?) Cabeça: if (!oldIsButtonUp && isButtonUp) {.
Deceleratedcaviar
-1

Uma versão XNA desse código seria algo como (simplificado apenas para detectar o evento do mouse para baixo, para detectar cliques duplos, você precisará de algo mais sofisticado);

MouseState previousMouseState; 
protected override void Initialize() 
{ 
    // TODO: Add your initialization logic here 
    //store the current state of the mouse 
    previousMouseState = Mouse.GetState(); 
} 


protected override void Update(GameTime gameTime) 
{ 
    // .. other update code 


    //is there a mouse click? 
    //A mouse click begins if the button goes from a released state 
    //in the previous frame  to a pressed state  
    //in the current frame 
    if (previousMouseState.LeftButton == ButtonState.Released  
        && Mouse.GetState().LeftButton == ButtonState.Pressed) 
    { 
        //do your mouse click response... 

    } 

    //save the current mouse state for the next frame 
    // the current  
    previousMouseState = Mouse.GetState(); 

    base.Update(gameTime); 
} 
Ken
fonte
Além disso, há um código para o MouseUp, não o MouseClick - com que frequência o Update é executado? O que aconteceria se um clique fosse menor que o tempo do jogo?
Kromster
depende do jogo, mas na atualização do XNA acontece cerca de 60fps por padrão. Seria muito difícil pressionar E soltar um botão do mouse nesse período de tempo.
Ken
Na verdade, é um código detectar um evento do mouse para baixo.
Ken
Eu não consigo ver uma resposta real para a questão real neste exemplo de código XNA abstrato
Kromster
Obrigado pelas correções, porém, fiz um pequeno teste e o Click leva de 16 a 100ms, um pouco mais do que o comprimento da atualização. Ainda assim, eu não incentivaria que a entrada de processamento em um loop de atualização para timestep pudesse ser menor que 60fps, especialmente sem as entradas de enfileiramento.
Kromster #