Learning Class : Input Recorder

A new entry in the learning class!!

Subject : What method do you use for your input in a game?

Description

I use 2 differents way to handle input in a game, the first one is the traditionnal input listener and the second one is an input that keep track of every key pressed, key released, mouse down, mouse up and the mouse position. For now, I will only explain how to do the second option.

So, what do you need to make a custom input container? :

  1. First, you need to have input listener that will catch the event for you
  2. Then, you send theses event to the InputRecorder.
  3. Finally, you can access those datas through the Input interface.

Code

Here is a part of the code that does that.

The listener that receive input from the player and send them to the InputRecorder

private class KeyControl implements KeyListener{

	@Override
	public void keyPressed(KeyEvent e) {
		inputRecorder.setKeyPressed(e.getKeyCode(), true);
	}

	@Override
	public void keyReleased(KeyEvent e) {
		inputRecorder.setKeyPressed(e.getKeyCode(), false);
	}

	@Override
	public void keyTyped(KeyEvent e) {
		
	}	
}

The interface that the programmer use to get the information about the player input

public interface Input {
	
	public boolean isKeyPressed(int code);
	
	public boolean isMouseDown(int code);
	
	public int getMouseX();
	
	public int getMouseY();

}

The class the record every input from the player

public class InputRecorder implements Input{
	
	private ArrayList<Boolean> keyPressed = new ArrayList<Boolean>();
	private ArrayList<Boolean> mouseDown = new ArrayList<Boolean>();
	private int mouseX = -1;
	private int mouseY = -1;
	
        @Override
	public synchronized boolean isKeyPressed(int code){
		if(code >= keyPressed.size()){
			increaseSize(keyPressed, code+1);
		}
		return keyPressed.get(code);
	}
	
	public void setKeyPressed(int code, boolean value){
		if(code >= keyPressed.size()){
			increaseSize(keyPressed, code+1);
		}
		keyPressed.set(code, value);
	}

        @Override
	public synchronized boolean isMouseDown(int code){
		if(code >= mouseDown.size()){
			increaseSize(mouseDown, code+1);
		}
		return mouseDown.get(code);
	}
	
	public synchronized void setMouseDown(int code, boolean value){
		if(code >= mouseDown.size()){
			increaseSize(mouseDown, code+1);
		}
		mouseDown.set(code, value);
	}
	
        @Override
	public synchronized int getMouseX(){
		return mouseX;
	}
	
        @Override
	public synchronized int getMouseY(){
		return mouseY;
	}
	
	public synchronized void setMouseX(int pos){
		mouseX = pos;
	}
	
	public synchronized void setMouseY(int pos){
		mouseY = pos;
	}
	
	public synchronized void reset(){
		mouseX = -1;
		mouseY = -1;
		for(int i=0; i<keyPressed.size(); i++){
			keyPressed.set(i, false);
		}
		for(int i=0; i<mouseDown.size(); i++){
			mouseDown.set(i, false);
		}
	}
	
	
	//****************************** HELPING METHODS ********************
	private void increaseSize(ArrayList<Boolean> list, int newSize) {
		while(list.size() < newSize){
			list.add(false);
		}
	}

}

Finally, here is an example of how to use it


if(input.isKeyPressed(KeyEvent.VK_D){
      //execute code
}

Notes

The advantage of using this kind of input is that you can put the logic that depends on input anywhere in your code. You don’t have to put everything in the listener subclass or creating a lot of variable for keeping track of the changes.

	//@Override
	public void keyReleased(KeyEvent e) {
		inputRecorder.setKeyPressed(e.getKeyCode(), false);
		inputManagerRecorder.keyReleased(e);
	}

cough bug cough :wink:

Ty for pointing out (always happen when I copy paste…)

Thanks for this post. It’s something I need to think about. My games tend to end up a mess because of input. I’m not sure I completely agree with saving every input, if that’s what it’s doing, but I need something more thought out that’s available from the main loop.

You jave to store which keys are down to be able to poll them in the main loop and the inputrecorder does exactly that (confusing name though).

The implementation is ok,but needs syncronization.

I’m really not an expert on synchronization but I guess that putting every method in the InputRecorder as synchronized should do the trick right?

Really? Why? Suggestion

private void increaseSize(ArrayList<Boolean> list, int newSize) {
		while(list.size() < newSize){
			list.add(false);
		}
	}

Why not simply replace that with:

private void increaseSize(ArrayList<Boolean> list, int newSize) {
	list.ensureCapacity(newSize);
}

:slight_smile:

Because that has significantly different behavior…

ensureCapacity(cap) only makes sure the backing array’s length is at least ‘cap’. It has no impact on the size() of the collection.

The increaseSize() method posted here adds items to the list, which obviously has an effect on the size of the collection.

Oh I see