2017-08-04 4 views
0

Je travaille donc sur un jeu de tower defense. Et j'ai besoin de sélectionner une tuile où l'utilisateur clique sur la souris (en ce moment je dessine juste une bordure autour de la tuile). Maintenant, le code que j'ai fonctionne parfois et je ne suis pas sûr de savoir comment le faire fonctionner mieux. En ce moment avec le code que j'ai quand je clique sur une zone, la tuile est sélectionnée et parfois elle désélectionne tout de suite et d'autres fois non. Presque comme si je maintenais la souris enfoncée et que je continuais à "cliquer" sur la souris. Ce dont j'ai besoin, c'est de sélectionner la tuile sans la désélectionner, peu importe la durée d'appui sur le bouton de la souris. Ma classe d'entrée de la souris est mis en place comme ceci:SDL C++ Effet de bascule de gestion des entrées de la souris

MouseInput.h

#pragma once 

#include <SDL.h> 

class MouseInput 
{ 
public: 
    MouseInput(); 
    ~MouseInput(); 

    void Update(); 

    bool GetMouseButton(int index); 
    SDL_Event GetEvent(); 

    bool GetPressed(); 
    bool GetReleased(); 

private: 
    void GetButtonStates(); 

private: 
    bool mouseArray[3]; 
    int x, y; 
    bool justReleased; 
    bool justPressed; 
    SDL_Event e; 
}; 

MouseInput.cpp

#include "Input.h" 

MouseInput::MouseInput() 
    : 
    x(0), 
    y(0), 
    justReleased(false), 
    justPressed(false) 
{ 
    SDL_PumpEvents(); 

    for (int i = 0; i < 3; i++) 
    { 
     mouseArray[i] = false; 
    } 
} 

MouseInput::~MouseInput() 
{ 

} 

void MouseInput::Update() 
{ 
    SDL_PollEvent(&e); 

    justReleased = false; 
    justPressed = false; 

    if (e.type == SDL_MOUSEBUTTONDOWN && e.button.button == SDL_BUTTON_LEFT) 
     justPressed = true; 
    else if (e.type == SDL_MOUSEBUTTONUP && e.button.button == SDL_BUTTON_LEFT) 
     justReleased = true; 
} 

bool MouseInput::GetPressed() 
{ 
    return justPressed; 
} 

bool MouseInput::GetReleased() 
{ 
    return justReleased; 
} 

bool MouseInput::GetMouseButton(int index) 
{ 
    if (index <= 3 && index >= 1) 
    { 
     return mouseArray[index - 1]; 
    } 

    return false; 
} 

SDL_Event MouseInput::GetEvent() 
{ 
    return e; 
} 

void MouseInput::GetButtonStates() 
{ 
    SDL_PollEvent(&e); 

    if (e.type == SDL_MOUSEBUTTONDOWN) 
    { 
     // 1 = Left; 2 = Center; 3 = Right 
     mouseArray[e.button.button - 1] = true; 
    } 

    if (e.type == SDL_MOUSEBUTTONUP) 
    { 
     mouseArray[e.button.button - 1] = false; 
    } 
} 

Dans ma classe de jeu, j'ai installé le mouseinput ainsi qu'une variable pour stocker les coordonnées de la tuile sur laquelle vous avez cliqué. J'ai aussi une variable pressed pour vérifier si la souris a été pressée. Dans ma fonction de mise à jour, je vérifie si la souris n'a pas été pressée. Si la souris n'a pas été pressée, je vérifie si la souris est pressée de cette façon que le jeu peut obtenir les coordonnées de la position de la souris. Je sais que ça paraît fou alors voici est une partie de mon code:

std::pair<int, int> coords; // Will store the coordinates of the tile position that the mouse rests in 
bool pressed; // If the mouse was pressed (i should call it toggle because it's true if the mouse was pressed once, then false if the mouse was pressed again, then true...ect.) 

Mise à jour fonction

classe Mouse

bool clicked; // In my custom Mouse.h file and set to false in constructor 
MouseInput input; // In my custom Mouse.h file 

Mise à jour de classe Mouse()

input.Update(); // Calls the MouseInput updating 

if (input.GetPressed() && !clicked) 
{ 
    clicked = !clicked; 
    printf("OK"); 
} 
//else if (clicked && input.GetReleased()) 
else if (clicked && input.GetPressed()) // Somewhat works. It works almost like before. If I click the mouse it shows up then sometimes when I click again it works, and other times I have to click a couple times 
{ 
    clicked = !clicked; 
} 

Dans mon jeu classe je vérifie juste si la souris est cliquée, puis dessine ce dont j'ai besoin

if (mouse.GetClicked()) 
{ 
    // Draw what I need here. 
    // Currently is only drawn when I hold down the mouse 
    // And not drawn when I release the mouse. 
} 

Ensuite, quand je dessine le carré autour de la tuile, je ne le dessine que si pressed = true. Sinon, il n'est pas dessiné. Ce code fonctionne parfois, et d'autres fois non. Afin d'obtenir l'effet que je veux, je dois réellement cliquer rapidement sur la souris. Si ce n'est pas le cas, il semble parfois que je maintiens le bouton de la souris enfoncé et que le carré clignote.

+0

Pas lié, mais dans 'GetMouseButton', je pense que vous vouliez dire' index> = 1', pas '-1'. – hnefatl

+0

Vous avez raison lol. Je ne sais pas pourquoi j'ai eu -1. Cela n'a même pas de sens haha. – Vince

Répondre

0

Le problème est que l'événement "mouse-down" est exactement cela - un événement. Cela devrait arriver une fois, être manipulé, et ne pas se produire jusqu'à ce que le bouton soit de nouveau pressé physiquement. Avec votre code, une fois pressé, l'état interne sera "pressé" et ne sera pas modifié jusqu'à ce qu'il soit libéré. Ce qui est correct, sauf que votre code interrogeant cet état interne le traite comme s'il s'agissait d'un événement et non comme un état. Ainsi, chaque fois que la fonction de mise à jour est activée, le bouton de la souris enfonce.

Cette (version simplifiée de votre code qui utilise un bouton et une idée de montrer une image que lorsqu'il est pressé de bouton) peut vous aider à le visualiser:

bool buttonPressed = false; 
bool imageShown = false; 
while (true) 
{ 
    SDL_Event e; 
    SDL_PollEvent(&e); 
    if (e.type == SDL_MOUSEBUTTONDOWN) 
     buttonPressed = true; 
    else if (e.type == SDL_MOUSEBUTTONUP) 
     buttonPressed = false; 

    if (!imageShown && buttonPressed) 
     imageShown = true; 
    else if (buttonPressed) 
     imageShown = false; 
} 

Voyez-vous comment chaque fois que les pistes en boucle , même si aucun événement n'a été déclenché cette itération, l'état reste? Cela entraînerait la variable imageShown pour continuer à activer et désactiver chaque itération, jusqu'à ce qu'un événement "bouton en haut" est déclenché pour réinitialiser l'état.

Vous devriez probablement retravailler un peu de votre contrôleur d'entrée - vous devez exposer un moyen de différencier de "bouton pressé maintenant" et "bouton qui a été pressé pendant un moment".

Une idée serait de fournir par exemple. ButtonsPressed et ButtonsJustPressed membres (bien que je suis sûr que vous pouvez penser à des noms plus appropriés). Les membres ButtonsJustPressed doivent être réinitialisés à false chaque fois que vous appelez GetButtonStates, donc ils sont seulement true si sur cette itération spécifique de la boucle, ils ont été pressés, tandis que les membres ButtonsPressed sont exactement ce que vous faites en ce moment.

A peaufiné la version de ce qui précède pour tenir compte:

bool buttonJustPressed = false; 
bool buttonJustReleased = false; 
bool imageShown = false; 
while (true) 
{ 
    // As far as we know, this iteration no events have been fired 
    buttonJustPressed = false; 
    buttonJustReleased = false 
    SDL_Event e; 
    SDL_PollEvent(&e); 
    if (e.type == SDL_MOUSEBUTTONDOWN) 
     buttonJustPressed = true; 
    else if (e.type == SDL_MOUSEBUTTONUP) 
     buttonJustReleased = true; 

    if (!imageShown && buttonJustPressed) 
     imageShown = true; 
    else if (imageShown && buttonJustReleased) 
     imageShown = false; 
} 

Voyez comment cette version ne changera la visibilité de l'image si un bouton vient d'être pressé/libéré - se tient de la touche bas, les événements ne sont pas déclenchés, donc l'état reste false et l'état de l'image reste le même.

+0

Je comprends ce que vous dites ici mais j'ai encore des problèmes. J'ai réussi à être capable de l'activer. (lorsque l'utilisateur appuie sur la souris). Mais quand l'utilisateur appuie à nouveau sur la souris pour désactiver, c'est ce que j'ai de la difficulté à gérer maintenant. – Vince

+0

Ce que j'essaie de faire, c'est quand l'utilisateur clique sur la souris, il affichera les tours qui sont disponibles pour construire. et quand l'utilisateur clique à nouveau sur la souris, il s'en ira. Tout de suite en sortant de votre exemple que vous avez donné, je dois tenir la souris pour avoir les tours montrées et elles disparaissent lorsque la souris est relâchée. – Vince

+0

@Vince Et vous avez changé votre code de fonction de mise à jour pour qu'il soit plus proche de 'if (! Pressed && mouseInput.GetMouseButtonJustPressed (1))'? Dans ce cas, modifiez votre message pour inclure votre code mis à jour (code d'entrée et "code d'affichage") et j'y reviendrai plus tard. – hnefatl