Disable mouse / cursor detection - c++

I'm making a simple Pong game.
When I ran the program, all the moves are perfect (the moving are not too fast nor too slow).
However, when I move my cursor around, the movement are faster which making the game much harder.
while (enable_loop)
{
Ticks = SDL_GetTicks();
while (SDL_PollEvent(&any_event))
{
if (any_event.type == SDL_QUIT)
{
enable_loop = false;
}
// Process keyboard event
keyPressed = SDL_GetKeyboardState(NULL);
if (keyPressed[SDL_SCANCODE_ESCAPE])
{
enable_loop = false;
}
if (keyPressed[SDL_SCANCODE_UP] )
{
player2.Update(25);
}
if (keyPressed[SDL_SCANCODE_DOWN])
{
player2.Update(-25);
}
if (keyPressed[SDL_SCANCODE_W])
{
player1.Update(20);
}
if (keyPressed[SDL_SCANCODE_S])
{
player1.Update(-20);
}
}
Grouping.update(surface, background);
SDL_UpdateWindowSurface(window);
limitFPS(Ticks);
}
}
Note : I've tried SDL_Delay(5) but the movement are too junky and jumping around, not usable :/
This game does not require mouse and I just may plug out my mouse, but I'm asking this for my experience and knowledge purposes.
I've used SDL_ShowCursor(SDL_DISABLE), SDL_CaptureMouse(SDL_FALSE) and limit my FPS to 60.
The effect is lessen but still noticeable.
How do I disable mouse detection or any code that will stop the effect?

Move the keyPressed checks outside the SDL_PollEvent() loop:
while (enable_loop)
{
Ticks = SDL_GetTicks();
while (SDL_PollEvent(&any_event))
{
if (any_event.type == SDL_QUIT)
{
enable_loop = false;
}
}
// Process keyboard event
keyPressed = SDL_GetKeyboardState(NULL);
if (keyPressed[SDL_SCANCODE_ESCAPE])
{
enable_loop = false;
}
if (keyPressed[SDL_SCANCODE_UP] )
{
player2.Update(25);
}
if (keyPressed[SDL_SCANCODE_DOWN])
{
player2.Update(-25);
}
if (keyPressed[SDL_SCANCODE_W])
{
player1.Update(20);
}
if (keyPressed[SDL_SCANCODE_S])
{
player1.Update(-20);
}
Grouping.update(surface, background);
SDL_UpdateWindowSurface(window);
limitFPS(Ticks);
}
That way you're only processing keyboard input once per frame instead of once per event.

Related

How to detect mouse scroll events with the emulated mouse (connecting to a pc by VNC)?

Does anyone have any idea why the scroll is not tracked when I remotely connect to the computer via VNC? The scroll action itself is tracked, but the delta is always 0 (event->delta_y). I want to be able to detect in which direction I scroll (Up or Down) while working with my application remotely - using VNC. I was trying to go around this problem by using x11. This system tracks mouse scroll events correctly, but I must create a loop to track the event, not what I want. Also I was trying to get ( event->direction ), but it always returns SMOOTH_SCROLL, but should return the particular direction. The code I have now:
bool OcctGtkViewer::onMouseScroll(GdkEventScroll *theEvent)
{
bool isPressed = false;
int init_x, init_y, fin_x, fin_y;
Display *xdisplay = XOpenDisplay(0);
XEvent xevent;
::Window xroot = gdk_x11_window_get_xid(gtk_widget_get_window((GtkWidget *)myGLArea->gobj()));
int scr = DefaultScreen(xdisplay);
const Graphic3d_Vec2d aNewPos2d = myView->Window()->ConvertPointToBacking(Graphic3d_Vec2d(theEvent->x, theEvent->y));
XGrabPointer(xdisplay, xroot, 1, ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
while (1)
{
XNextEvent(xdisplay, &xevent);
if (xevent.type == ButtonPress)
{
switch (xevent.xbutton.button)
{
case Button4:
if (true)
{
const Aspect_ScrollDelta aScroll(Graphic3d_Vec2i(aNewPos2d + Graphic3d_Vec2d(0.5)), 1);
if (UpdateMouseScroll(aScroll))
{
myGLArea->queue_draw();
}
break;
}
case Button5:
if (true)
{
const Aspect_ScrollDelta aScroll(Graphic3d_Vec2i(aNewPos2d + Graphic3d_Vec2d(0.5)), -1);
if (UpdateMouseScroll(aScroll))
{
myGLArea->queue_draw();
}
break;
}
default:
break;
}
}
break;
}
XFlush(xdisplay);
XCloseDisplay(xdisplay);
return true;
}

Variable don't update from sfml event loop

I am using sfml library for my graphics. During paused I want to avoid drawing on the screen. I want to intercept a spacebar press using sf::Event::MouseButtonPressed. In the debug mode, the event is successfully intercepted but failed in normal execution, why? The bool variable 'paused' don't seemed to update.
while (window.isOpen()) {
Event event;
while (window.pollEvent(event)) {
/*..*/
if (event.type = Event::KeyPressed) {
if (event.key.code == Keyboard::Space) {
if (!paused) {
paused = true;// UDATE HERE
}
else
if (paused)
{
paused = false; // UDATE HERE
}
}
}
}
if (!paused) //// UDATE DONT SEEM TO AFFECT HERE
{
/* draw here */
}
}
Edited: Even tried by declaring the variable paused as atomic, but still don't work.
Use the Event::KeyReleased instead of the Event::KeyPressed as the key press gets called every loop that a key is down leading to many enters while the Release event is only called once per click.

SDL C++ Mouse Input Handling Toggle Effect

So I'm working on a tower defense game. And I need to select a tile where the user clicks the mouse (right now i'm just drawing a border around the tile). Now the code I have works sometimes and I'm not sure how to get it to work better. Right now with the code I have when I click on an area, the tile gets selected and sometimes it deselects right away and other times it doesn't. Almost like I'm holding the mouse down and it just keeps "clicking" the mouse. What I need is for it to select the tile without deselecting it no matter how long the mouse button is being pressed. My mouse input class is set up like this:
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;
}
}
In my Game class I have setup the mouseinput as well as a variable to store the coordinates of the tile that was clicked. I also Have a variable pressed to check to see if the mouse was pressed. In my updating function I check if the mouse was not pressed. If the mouse was not pressed, then I check if the mouse is pressed that way the game can get the coordinates of the mouse position. I know that sounds crazy so here is some of my 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.)
Updating function
Mouse Class
bool clicked; // In my custom Mouse.h file and set to false in constructor
MouseInput input; // In my custom Mouse.h file
Mouse class Update()
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;
}
In my game class I just check if mouse clicked is true, then draw what i need
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.
}
Then when I'm drawing the square around the tile, I only draw it if pressed = true. Otherwise it is not drawn. This code works sometimes, and other times it doesn't. In order to get the effect I want, I have to real quickly click the mouse. If I don't, sometimes it appears as if I'm holding the mouse button down and the square just flashes.
The issue is that the "mouse-down" event is exactly that - an event. It should happen once, be handled, and then not occur until the button is physically pressed again. With your code, once pressed it'll set the internal state to "pressed" and then not change it until it's released. Which is okay, except your code polling this internal state treats it as if it's an event, not as state, so every time the update function runs while the mouse button is pressed, it'll see a "new button press".
This (simplified version of your code that uses one button and an idea of showing an image only when a button's pressed) might help you visualise it:
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;
}
Do you see how each time the loop runs, even if no events have been fired this iteration, the state remains? This would cause the imageShown variable to keep toggling on and off each iteration, until a "button up" event is fired to reset the state.
You should probably rework a bit of your input controller - you need to expose a way to differentiate from "button being pressed right now" and "button that's been pressed for a while".
An idea would be to provide eg. ButtonsPressed and ButtonsJustPressed members (although I'm sure you can think of more appropriate names). The ButtonsJustPressed members should be reset to false each time you call GetButtonStates, so they're only true if on that specific iteration of the loop, they've been pressed, while the ButtonsPressed members are exactly what you're doing right now.
A tweaked version of the above to take this into account:
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;
}
See how this version will only change the visibility of the image if a button has just been pressed/released - if the button's being held down, the events aren't fired, so the state remains false, and the image's state remains the same.

Non instantaneous/jerky movement using SDL2 & OpenGL

I've been working on a little 3D engine trying to fix up the camera and make it less jerky. I've been using SDL for the input and while it works it's doing this thing where if I press and hold a button it will instantly move once then pause and then start moving properly making the movement feel unresponsive.
I recorded a GIF of it and while it may be slightly hard to see what's happening hopefully it'll give some idea:
Moving forward and then right would be like:
w wwwwwwwwwwwwwwww a aaaaaaaaaaaaaaaaaaaaa
The important code is here but feel free to ask for more if necessary:
//Poll events
SDL_Event event;
while (m_EngineState != EngineState::EXIT)
{
m_last = m_current;
m_current = SDL_GetPerformanceCounter();
deltaTime = (double)((m_current - m_last) * 1000 / SDL_GetPerformanceFrequency());
while (SDL_PollEvent(&event))
{
switch (event.type) {
case SDL_QUIT:
m_EngineState = EngineState::EXIT;
break;
case SDL_MOUSEMOTION:
break;
case SDL_KEYDOWN:
m_Keys[event.key.keysym.sym] = true;
break;
case SDL_KEYUP:
m_Keys[event.key.keysym.sym] = false;
break;
}
ProcessEvents();
}
void Engine::ProcessEvents()
{
if (m_Keys[SDLK_w])
{
m_Camera->MoveForward(5.0f*(deltaTime*0.001));
}
if (m_Keys[SDLK_s])
{
m_Camera->MoveForward(-5.0f*(deltaTime*0.001));
}
if (m_Keys[SDLK_d])
{
m_Camera->MoveRight(5.0f*(deltaTime*0.001));
}
if (m_Keys[SDLK_a])
{
m_Camera->MoveRight(-5.0f*(deltaTime*0.001));
}
}
void Camera::MoveForward(float amount)
{
m_pos += m_forward * amount;
}
void Camera::MoveRight(float amount)
{
m_pos += glm::cross(m_forward, m_up) * amount;
}
Do not use SDL_PollEvent with the SDL_KEYDOWN and SDL_KEYUP events, it is subject to OS keyboard repeat rates. Which is great for typing, but not for camera/player controls. Use SDL_GetKeyboardState(NULL) in stead to query the current state of the keys.
For example:
Uint8* keystate = SDL_GetKeyboardState(NULL);
if (keystate[SDL_SCANCODE_W])
{
m_Camera->MoveForward(5.0f*(deltaTime*0.001));
}
if (keystate[SDL_SCANCODE_S])
{
m_Camera->MoveForward(-5.0f*(deltaTime*0.001));
}

SFML2 Mouse::isButtonPressed filling up event queue

First of all I'd like to say that I'm not sure if the title is appropriate but it's the only logical explanation I could find.
What I'm trying to do is move my window by clicking a sprite (sort of like simulating a titlebar).
All working fine until I let go of the mouse button the rate new mouse events are emitted is way lower and with huge 1.5~2s pauses between them.
Is it possible that sf::Mouse::isBUttonPressed is filling the queue or is it another issue?
Edit: The window class has a sf::Event object and passes it to each object's event handler.
The sprite class has an event handler of this form:
bool object::handleEvents(sf::Event& event)
{
switch(event.type)
{
case sf::Event::MouseMoved:
case sf::Event::MouseButtonPressed:
case sf::Event::MouseButtonReleased:
{
auto mouse_pos = sf::Mouse::getPosition(*this->parent);
if(this->isPointInside(mouse_pos))
{
if(event.type == sf::Event::MouseMoved)
{
this->hovering = true;
if(this->callback["onHover"])
this->callback["onHover"](this, nullptr);
return true;
}
else if(event.type == sf::Event::MouseButtonPressed)
{
this->clicked = true;
this->focused = true;
if(event.mouseButton.button == sf::Mouse::Left)
if(this->callback["onLClick"])
this->callback["onLClick"](this, ref(mouse_pos));
if(event.mouseButton.button == sf::Mouse::Right)
if(this->callback["onRClick"])
this->callback["onRClick"](this, ref(mouse_pos));
return true;
}
else if(event.type == sf::Event::MouseButtonReleased && this->clicked)
{
this->clicked = false;
if(event.mouseButton.button == sf::Mouse::Left)
if(this->callback["onLClickReleased"])
this->callback["onLClickReleased"](this, ref(mouse_pos));
if(event.mouseButton.button == sf::Mouse::Right)
if(this->callback["onRClickReleased"])
this->callback["onRClickReleased"](this, ref(mouse_pos));
return true;
}
}
else
{
if(this->hovering)
{
if(this->callback["onHoverLost"])
this->callback["onHoverLost"](this, nullptr);
this->hovering = false;
}
}
}break;
default: ;
}
return false;
}
and the code responsible for moving the window:
titlebar->callback["onLClick"] = [&](object* obj, void* data)
{
sf::Vector2i* relpos = (sf::Vector2i*)(data);
while(sf::Mouse::isButtonPressed(sf::Mouse::Left))
{
sf::Vector2i abspos = sf::Mouse::getPosition();
window.setPosition(sf::Vector2i((abspos.x - relpos->x),(abspos.y - relpos->y)));
}
titlebar->clicked = false;
};
The sf::Mouse class as well as sf::Keyboard and sf::Joystick aren't connected to the event system, but are completely independent, thus it's impossible that isButtonPressed would've any influence on the events.
The real problem in your code is the 'infinite' loop when the left mouse button is pressed. If the left mouse button is pressed, everything that happens in your application is, that the window gets moved around. There won't be any event dispatches (= processing) and every event that happens within that time, will get pilled in the event queue. Thus when you return to process the events, you'll have a longer queue than usual and will start dispatching with the oldest event.
So if you now move your window around for 2 seconds, you'll get a filled queue worth 2 seconds which can delay the further processing.
To solve this problem, you'll most probably have to dispatch all the events while you're moving the window.