When to reset input

Hello everyone. Other than a comment on someone else’s game this is my fist post. It seems like a really nice forum with nice people.

I’ve made a few simple games, like tetris and snake, but I always made an input class for each game. (Edit:What I mean is, now I’m trying to write an input class that is a bit more profesional and can be reused) I’ve never really been that sure on the best way to do it. The thing I’m a bit confused about is mouse input and when to reset it in the input class. The game I am making is a simple (although extremely violent and it bad taste) Whack A Mole type game. So the only control is pressing the mouse. The problem was, even on the menu screens, sometimes it would not register that my mouse had been clicked. I worked out the problem.

In sudo code my game loop went a bit like this.

update game
render
reset input (reseted mouseWasPushed variable)

I reallised what was happening was if I pushed the mouse button after update game, but before or during render, the mouse input variable was reset before upate game could read it. The game uses some pretty large image files as backgrounds. I will learn later about image compression and such.

Anyway I switched it round to this.

update game
reset input
render

So I even if I pushed the mouse button during rendering it would still work. It works fine now. I have not noticed one time when the mouse was unresponsive so it solved the bug. But what would happen with games with complex long calcuations in the update? I would have the same problem.

So how am I supposed to handle reseting such varables as mouseWasPushed? Am I not supposed to reset them and there is some other way? Or do I leave it inside the game logic and out of the loop, so I can reset it as soon as it was used. Any advice would be great.

Well, for simple games, I have a Controls class that handles all mouse/keyboard input, but for a more complex game with menus and stuff you will probably want game states.

Basically though, Controls.java implements KeyListener, MouseListener, and MouseMotionListener and overrides all their respective methods. It also gets passed a reference to your game in the constructor so it can access things.

So, I can check in keyPressed method of Controls.java if the spacebar was pressed, if it was I can simply say game.getPlayer().jump(). Easy as pie!

The listeners run on a separate thread in the background. So while you do your normal update, render, sleep it waits in the background for an event to happen. When something does get pressed, Controls.java will catch it and handle it.

Hi and thanks for the reply. I have my game states all sorted out. That’s not a problem.

“So, I can check in keyPressed method of Controls.java if the spacebar was pressed, if it was I can simply say game.getPlayer().jump(). Easy as pie!”

I understand this. But say if you were using the mouse to jump. You click to jump. Your game reads it and jumps. That mousePressed variable still says mousePressed, so you will keep jumping repeatedly until you reset it. So when do you reset it?

You don’t need variables :slight_smile:

Controls is a key listener, a mouse listener, and a mouse motion listener. Once you set it as the default listener with your component’s addKeyListener, addMouseListener, and addMouseMotionListener methods, anytime any of those events happen, the respective method in Controls will be called 1 time.

So, after setting it as a listener, let’s say you click the left mouse button. The Dispatch thread will be like “Oh! He pressed something on the mouse. Let’s see who he told us was the class that should be notified. Controls? Ok, I’ll call Controls’ mousePressed method and pack the event details with it (MouseEvent).”

From there you can get the details on which exact mouse button it was with MouseEvent and make the player jump.

Does that make sense?

I did make sense, because it’s kind of like what I’m doing. But I must be misunderstanding you, because i’m still thinking I need to reset it some place. Let me show you what I have so far in my input class.

import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseEvent;
import java.awt.Component;

public class InputManager implements Input, MouseListener, MouseMotionListener {
    
    private boolean mouseWasPressed;
    private boolean mouseWasReleased;
    private int mouseX;
    private int mouseY;
    private int mousePressX;
    private int mousePressY;
    private int mouseReleaseX;
    private int mouseReleaseY;
    
    public InputManager(Component component) {
        component.addMouseListener(this);
        component.addMouseMotionListener(this);
    }
    
    public void update() {
        reset();
    }
    
    public void reset() {
        mouseWasPressed = false;
        mouseWasReleased = false;
    }
    public boolean mousePressed() {
        return mouseWasPressed;
    }
    
    public boolean mouseReleased() {
        return mouseWasReleased;
    }
    
    public int getMouseX() {
        return mouseX;
    }
    
    public int getMouseY() {
        return mouseY;
    }
    
    public int getMousePressX() {
        return mousePressX;
    }
    
    public int getMousePressY() {
        return mousePressY;
    }
    
    public int getMouseReleaseX() {
        return mouseReleaseX;
    }
    
    public int getMouseReleaseY() {
        return mouseReleaseY;
    }
        
    @Override
    public void mouseClicked(MouseEvent event) {
        
    }
    
    @Override
    public void mousePressed(MouseEvent event) {
        mouseWasPressed = true;
        mousePressX = event.getX();
        mousePressY = event.getY();
    }
    
    @Override
    public void mouseReleased(MouseEvent event) {
        mouseWasReleased = true;
        mouseReleaseX = event.getX();
        mouseReleaseY = event.getY();
    }
    
    @Override 
    public void mouseEntered(MouseEvent event) {}
    
    @Override
    public void mouseExited(MouseEvent event) {}
    
    @Override
    public void mouseMoved(MouseEvent event){
        mouseX = event.getX();
        mouseY = event.getY();
    }
    
    @Override
    public void mouseDragged(MouseEvent event) {
        mouseX = event.getX();
        mouseY = event.getY();
    }
}


And here is a snippet of code that uses that input class.

 public void checkInput() {
        
        if (input.mousePressed()) {
            
            int x = input.getMousePressX();
            int y = input.getMousePressY();
            
            for (MoleHole moleHole :  moleHoles) {
                
                if (moleHole.hit(x, y) ) {
                    
                    if (!moleHole.moleIsDead()) {
                        moleHole.killMole();
                        updateScore(moleHole);
                        moleGenerator.newMole();
                    }
                 }
            }
        }
     }

So the Input class is the class that handles all the events. But it still stores the info. And that info needs to be reset. I thought that the input should be checked in the same time of every loop, not just react as soon as the user clicks?

The place to reset any “key pressed” variable is on the “key release” event. :slight_smile: Same goes with the mouse.

But I need to find out if the mouse WAS pressed. Not just if it is pressed right now. I need to know if it has been pressed this loop. What if someone presses the mouse and releases before before my game can read that it was pressed at all?

Well I hope I haven’t scared you all away with my stupidity. haha

So I tried doing as Regenuluz said and it still worked. I think maybe I just wasn’t compehending how fast the loop goes. No matter how fast I clicked and released the game upate stil caught the click. So I guess that solves it then.

Thanks both of you for your help. If anyone has anything to add, though, please feel free.

Oh, I see. You’re having concurrency issues.

It shouldn’t really make a difference if it was pressed this loop or not. The game loops upwards of 60x/second. I don’t use variables, I just have the dispatch thread do my dirty work. =p

What exactly is it doing? Is there lag between a press and an action?

No, in my first post I explained the problem I was having but since moving my code around it works. It’s just i could imagine there could be a problem if my game update methods take too long.

This is not thread safe.
You need to either synchronize methods you call from your game loop or at least declare the boolean variables as volatile.
Otherwise you are not guranteed to see the same values as the AWT event thread does.

Usually you have two approaches to handling input:

  • polling
  • event processing

The first is how most action oriented games handle input, the latter is how Swing/AWT does it. Both have usecases in games.

For polling you usually have state variables like your mousePressed variable. You usually don’t reset them in the game loop, but set it to false in the mouseReleased() method. This obviously has the upside that you encupsulate the mouse state completely in your listener, but the downside of missing clicks (rather rare with decent FPS) and “continuous repeat”, meaning that as long as the user presses the mouse the action will be repeated every frame. But there are enough usecases (like movement control) where this behavious is exactly what you want.

The event approach is for actions that should happen on a state change (like changing from mouse pressed to mouse released). The easiest is to utilize the already existing Listener framework of Swing/AWT, but this has the downside of not playing too well with active rendering and gameloops in general due to threading problematics like 65K already explained. So you usually “convert” the awt events to your own events and put these in a thread safe queue (like ConcurrentLinkedQueue. In your update phase you can then pop events from this queue and process them to update your game state. This approach is great for selections and other non-repeating interactions.

Your code tries to get away with the polling approach for an event based action, which can only result in a fragile solution and will eventually break for other use-cases introduced later to your game. Best would be to support both in your InputManager and use the right approach for the individual use-case

To make this thread safe you can create a GamePanel class like this

class GamePanel extends JPanel {
    ConcurrentLinkedQueue<InputEvent> eventQueue = new ConcurrentLinkedQueue<InputEvent>(); 
    @Override
    protected void processEvent(AWTEvent e) {
        if(e instanceof InputEvent) eventQueue.add((InputEvent)e);
        else super.processEvent(e);
    }
    {
        enableEvents(  AWTEvent.MOUSE_EVENT_MASK
                     | AWTEvent.MOUSE_MOTION_EVENT_MASK
                     | AWTEvent.KEY_EVENT_MASK);
        addHierarchyListener(new HierarchyListener() {
            public void hierarchyChanged(HierarchyEvent e) {
                if((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) > 0) {
                    requestFocusInWindow();
                }
            }
        });
    }
    public void handleEvents() {
        while(!eventQueue.isEmpty()) super.processEvent(eventQueue.poll());
    }
}

This uses a thread safe queue to store all input events so you can then handle them in your game loop safely.
You have 2 options here. You can add listeners to the game panel and call handleEvents from your game loop or you don’t use listeners and instead poll the events from the queue directly.
e.g.

GamePanel panel = new GamePanel();
panel.addMouseListener(new MouseAdapter() {
    public void mousePressed(MouseEvent e) {
        System.out.println(e);
    }
});
panel.addKeyListener(new KeyAdapter() {
    public void keyPressed(KeyEvent e) {
        System.out.println(e);
    }
});
final JFrame frame = new JFrame();
frame.add(panel);
panel.setPreferredSize(new Dimension(800,600));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
while(true) { // game loop
    panel.handleEvents();
    // do other stuff
}

or with direct polling

GamePanel panel = new GamePanel();
final JFrame frame = new JFrame();
frame.add(panel);
panel.setPreferredSize(new Dimension(800,600));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
while(true) { // game loop
    while(!panel.eventQueue.isEmpty()) {
        InputEvent e = panel.eventQueue.poll();
        System.out.println(e);
    }
    // do other stuff
}

Hi and thanks for the detailed reply. There is just one major thing that is confusing me about your post. It seems that at the beginning you are suggesting that I either use polling or event processing, then later you mention the mouseReleased() method. So if were to use polling, and not event processing, what would call the mouseRelease method? How would I know the mouse was released? Are you a fan of doing it the way DrZoidberg suggests, by checking the actual eventQue?

Thanks DrZoidberg, I was completely unaware that it could be done that way. So I will have a look at the API.

And thanks 65K, I will make what I have thread safe, if I do stick with that way of doing things. I was just learning about volaltile variables today.

You could do this

while(true) {
    while(!panel.eventQueue.isEmpty()) {
        InputEvent e = panel.eventQueue.poll();
        if((e.getModifiers & MouseEvent.MOUSE_RELEASED) > 0) { // mouse was released
            MouseEvent me = (MouseEvent)e;
            ...
        }
    }
    
}

But I would just use a mouse listener. If you need them you can also have state variables that you set from within the listeners.
e.g.

boolean leftMouseDown = false;
...
panel.addMouseListener(new MouseAdapter() {
    public void mousePressed(MouseEvent e) {
        if(e.getButton() == MouseEvent.BUTTON1) leftMouseDown = true;
    }
    public void mouseReleased(MouseEvent e) {
        if(e.getButton() == MouseEvent.BUTTON1) leftMouseDown = false;
    }
});

you could also add a mouse/key listener to each character in the game
and then do something like this

panel.addMouseListener(new MouseAdapter() {
    public void mousePressed(MouseEvent e) {
        for(GameCharacter gc: listOfGameCharacters) gc.getMouseListener().mousePressed(e);
    }

Now I’m starting to feel like I’m going in circles cause that’s pretty much what I had. And I was told that the methods need to be synchronized, and the variables volatile. I was also told I was mixing polling and event based , and that it was a fragile solution.

I’d love to see code for an input class that a few people could agree that was a good solution. If I don’t, I think I will just have to go ahead with something like was already doing but with synchronized methods.

If you use my GamePanel class you don’t need to synchronize your methods and you don’t need volatile variables either. The ConcurrentLinkedQueue in my class does all the work of synchronizing the threads.
There is not just one correct solution. There is an infinite number of possible correct ways of doing this. How about you post your code and we tell you if it’s ok.

Yes, that is fragile code.
Your game code will undoubtably be assuming that the mouse/keyboard state remains the same throughout the duration of 1 game loop iteration.
This would not be the case using the above code.

If you were to implement your keylistener like that you’d need to take a copy of the mouse/keyboard state @ the start of each game loop so the value seen by your game code remained constant for the duration.

My code was intended to be used in combination with the GamePanel class I posted earlier. If used like this, the state will remain the same throughout 1 game loop iteration.