Slick2D Top Down Control

Hey guys, so I’m using slick2d to build a little game.
This is my controls method:

public void useControlls(){
		if (!(CoreGameState.inputHandler.isKeyDown(Input.KEY_W)) && !(CoreGameState.inputHandler.isKeyDown(Input.KEY_D)) && !(CoreGameState.inputHandler.isKeyDown(Input.KEY_A)) && !(CoreGameState.inputHandler.isKeyDown(Input.KEY_S))){
			 pc.moving = false; 
		}
		if (CoreGameState.inputHandler.isKeyDown(Input.KEY_W)) {
			pc.pDirection = PlayerDirections.North;
			if(!pc.checkCollisionNorth()){
			pc.y -= pc.maxSpeed;	
			CoreGameState.inputHandler.clearKeyPressedRecord();
			pc.moving = true;
			}
		}
		else if (CoreGameState.inputHandler.isKeyDown(Input.KEY_S)) {
			pc.pDirection = PlayerDirections.South;
			if(!pc.checkCollisionSouth()){			
			pc.y += pc.maxSpeed;
			CoreGameState.inputHandler.clearKeyPressedRecord();
			pc.moving = true;
			}

		}
		else if (CoreGameState.inputHandler.isKeyDown(Input.KEY_A)) {	
			pc.pDirection = PlayerDirections.West;
			if(!pc.checkCollisionWest()){
			pc.x -= pc.maxSpeed;
			CoreGameState.inputHandler.clearKeyPressedRecord();
			pc.moving = true;
			}
			
		}
		else if (CoreGameState.inputHandler.isKeyDown(Input.KEY_D)) {
			pc.pDirection = PlayerDirections.East;
			if(!pc.checkCollisionEast()){
			pc.x += pc.maxSpeed;
			CoreGameState.inputHandler.clearKeyPressedRecord();
			pc.moving = true;
			}

		}
		
		
	}

Pretty much speaks for itself.

So my problem is that the movement does not feel good due to the fact that if i pess W or S and then D or A he does not move left or right.
He continious moving up or down. So if pressed D or A first and then press W or S the character moves up or down.

What i want to achieve is that if I’m pressing W (i keep pressing the W) and then press D that the character moves right. So far thats only possible for D & A but not for W & S.
I can see the flaw in the code. It’s because W & S are in the if-else before A & D. I tried playing with booleans and restrictions but somehow nothing did work.

I need some advice how to fix that.

Why not turn all the “else if” statements into just “if” statements. If you have “else if” statements I’d assume that only one of these conditions can be true, which is not the case for you. Multiple of these keys can be pressed at the same time, and not just one.

hey thanks for the reply, if i do this the character is able to move diagonal, i dont want this.
only 4 directions.

Ah I see, I misunderstood you sorry.

I couldn’t actually test this but I think it should have the desired effect.
Basically I have a lastKey variable that remembers the key that was pressed last, and only if the key was indeed pressed last will i move in that direction.
So if You were to press W and then D, it will recognize D as the latest one and move in that direction. If I let go of W and press it down again, it will move in that direction.

Hope that works, or at least gives you the right idea :slight_smile:

boolean wKeyWasPressed, sKeyWasPressed, aKeyWasPressed, dKeyWasPressed = false;
    String lastKey = "";

    public void useControlls(){
        if (!(CoreGameState.inputHandler.isKeyDown(Input.KEY_W)) && !(CoreGameState.inputHandler.isKeyDown(Input.KEY_D)) && !(CoreGameState.inputHandler.isKeyDown(Input.KEY_A)) && !(CoreGameState.inputHandler.isKeyDown(Input.KEY_S))){
            pc.moving = false;
        }
        
        if (CoreGameState.inputHandler.isKeyDown(Input.KEY_W ) && !wKeyWasPressed) {
            wKeyWasPressed = true;
            lastKey = "W";
        }
        else if (!CoreGameState.inputHandler.isKeyDown(Input.KEY_W )) {
            wKeyWasPressed = false;
        }
        
        if (CoreGameState.inputHandler.isKeyDown(Input.KEY_S ) && !sKeyWasPressed) {
            sKeyWasPressed = true;
            lastKey = "S";
        }
        else if (!CoreGameState.inputHandler.isKeyDown(Input.KEY_S )) {
            sKeyWasPressed = false;
        }
        
        if (CoreGameState.inputHandler.isKeyDown(Input.KEY_A ) && !aKeyWasPressed) {
            aKeyWasPressed = true;
            lastKey = "A";
        }
        else if (!CoreGameState.inputHandler.isKeyDown(Input.KEY_A )) {
            aKeyWasPressed = false;
        }
        
        if (CoreGameState.inputHandler.isKeyDown(Input.KEY_D ) && !dKeyWasPressed) {
            dKeyWasPressed = true;
            lastKey = "D";
        }
        else if (!CoreGameState.inputHandler.isKeyDown(Input.KEY_D )) {
            dKeyWasPressed = false;
        }

        if (CoreGameState.inputHandler.isKeyDown(Input.KEY_W) && lastKey.equals("W")) {
            pc.pDirection = PlayerDirections.North;
            if(!pc.checkCollisionNorth()){
                pc.y -= pc.maxSpeed;
                CoreGameState.inputHandler.clearKeyPressedRecord();
                pc.moving = true;
            }
        }
        else if (CoreGameState.inputHandler.isKeyDown(Input.KEY_S) && lastKey.equals("S")) {
            pc.pDirection = PlayerDirections.South;
            if(!pc.checkCollisionSouth()){
                pc.y += pc.maxSpeed;
                CoreGameState.inputHandler.clearKeyPressedRecord();
                pc.moving = true;
            }

        }
        else if (CoreGameState.inputHandler.isKeyDown(Input.KEY_A) && lastKey.equals("A")) {
            pc.pDirection = PlayerDirections.West;
            if(!pc.checkCollisionWest()){
                pc.x -= pc.maxSpeed;
                CoreGameState.inputHandler.clearKeyPressedRecord();
                pc.moving = true;
            }

        }
        else if (CoreGameState.inputHandler.isKeyDown(Input.KEY_D) && lastKey.equals("D")) {
            pc.pDirection = PlayerDirections.East;
            if(!pc.checkCollisionEast()){
                pc.x += pc.maxSpeed;
                CoreGameState.inputHandler.clearKeyPressedRecord();
                pc.moving = true;
            }

        }
    }

Just thought of a flaw with this… if you hold W, then press D and let go of D again, it still registers D as the last key pressed and will not move up.
So you’ll also have to do a check to count a key as the “lastKey” if it’s the only one that’s pressed.

edit: aight wait a sec, let me think on this :cranky:

I was thinking of a similiar approach but it felt too complex for me somehow. :smiley:
I just tested this and it works. As you already have stated while pressind D or A it’s not possible to move up (W) or down (S).
So the problem is reversed. A check to count a key as the “lastKey” might solve this problem.
I didnt try that yet.

Okay friend, I got angry and used a list. But I think this is a pretty smart solution now. I just store they keys in the order they were pressed and always look at the last one. Again I can’t test this, but I’ll be damned if it doesn’t work.

 boolean wKeyWasPressed, sKeyWasPressed, aKeyWasPressed, dKeyWasPressed = false;
    ArrayList<String> keyOrderList = new ArrayList<String>();

    private void determineKeyOrder() {
        if (!CoreGameState.inputHandler.isKeyDown(Input.KEY_W ) && wKeyWasPressed) {
            wKeyWasPressed = false;
            keyList.remove("W");
        }
        if (!CoreGameState.inputHandler.isKeyDown(Input.KEY_S ) && sKeyWasPressed) {
            sKeyWasPressed = false;
            keyList.remove("S");
        }
        if (!CoreGameState.inputHandler.isKeyDown(Input.KEY_A ) && aKeyWasPressed) {
            aKeyWasPressed = false;
            keyList.remove("A");
        }
        if (!CoreGameState.inputHandler.isKeyDown(Input.KEY_D ) && dKeyWasPressed) {
            dKeyWasPressed = false;
            keyList.remove("D");
        }

        if (CoreGameState.inputHandler.isKeyDown(Input.KEY_W ) && !wKeyWasPressed) {
            wKeyWasPressed = true;
            keyList.add("W");
        }
        if (CoreGameState.inputHandler.isKeyDown(Input.KEY_S ) && !sKeyWasPressed) {
            sKeyWasPressed = true;
            keyList.add("S");
        }
        if (CoreGameState.inputHandler.isKeyDown(Input.KEY_A ) && !aKeyWasPressed) {
            aKeyWasPressed = true;
            keyList.add("A");
        }
        if (CoreGameState.inputHandler.isKeyDown(Input.KEY_D ) && !dKeyWasPressed) {
            dKeyWasPressed = true;
            keyList.add("D");
        }
    }

    public void useControlls(){
        if (!(CoreGameState.inputHandler.isKeyDown(Input.KEY_W)) && !(CoreGameState.inputHandler.isKeyDown(Input.KEY_D)) && !(CoreGameState.inputHandler.isKeyDown(Input.KEY_A)) && !(CoreGameState.inputHandler.isKeyDown(Input.KEY_S))){
            pc.moving = false;
        }

        determineKeyOrder();
        String lastKey = keyOrderList.get(keyOrderList.size() - 1);

        if (CoreGameState.inputHandler.isKeyDown(Input.KEY_W) && lastKey.equals("W")) {
            pc.pDirection = PlayerDirections.North;
            if(!pc.checkCollisionNorth()){
                pc.y -= pc.maxSpeed;
                CoreGameState.inputHandler.clearKeyPressedRecord();
                pc.moving = true;
            }
        }
        else if (CoreGameState.inputHandler.isKeyDown(Input.KEY_S) && lastKey.equals("S")) {
            pc.pDirection = PlayerDirections.South;
            if(!pc.checkCollisionSouth()){
                pc.y += pc.maxSpeed;
                CoreGameState.inputHandler.clearKeyPressedRecord();
                pc.moving = true;
            }

        }
        else if (CoreGameState.inputHandler.isKeyDown(Input.KEY_A) && lastKey.equals("A")) {
            pc.pDirection = PlayerDirections.West;
            if(!pc.checkCollisionWest()){
                pc.x -= pc.maxSpeed;
                CoreGameState.inputHandler.clearKeyPressedRecord();
                pc.moving = true;
            }

        }
        else if (CoreGameState.inputHandler.isKeyDown(Input.KEY_D) && lastKey.equals("D")) {
            pc.pDirection = PlayerDirections.East;
            if(!pc.checkCollisionEast()){
                pc.x += pc.maxSpeed;
                CoreGameState.inputHandler.clearKeyPressedRecord();
                pc.moving = true;
            }

        }
    }

edit: removed the return in the first if statement of useControlls()

Neat solution buddy :slight_smile:
You really helped me out here.
It works and feels really fluent and good.
I just changed the code a little bit to avoid an IndexOutOfBouceException.
I’ll post it below, maybe it helps out someone else someday :slight_smile:


boolean wKeyWasPressed, sKeyWasPressed, aKeyWasPressed, dKeyWasPressed = false;
ArrayList<String> keyOrderList = new ArrayList<String>();

 public void useControlls(){
	        if (!(CoreGameState.inputHandler.isKeyDown(Input.KEY_W)) && !(CoreGameState.inputHandler.isKeyDown(Input.KEY_D)) && !(CoreGameState.inputHandler.isKeyDown(Input.KEY_A)) && !(CoreGameState.inputHandler.isKeyDown(Input.KEY_S))){
	            pc.moving = false;
	        }

	        String lastKey = "";
	        determineKeyOrder();
	        if(!keyOrderList.isEmpty()){
	        lastKey = keyOrderList.get(keyOrderList.size() - 1);
	        }

	        if (CoreGameState.inputHandler.isKeyDown(Input.KEY_W) && lastKey.equals("W")) {
	            pc.pDirection = PlayerDirections.North;
	            if(!pc.checkCollisionNorth()){
	                pc.y -= pc.maxSpeed;
	                CoreGameState.inputHandler.clearKeyPressedRecord();
	                pc.moving = true;
	            }
	        }
	        else if (CoreGameState.inputHandler.isKeyDown(Input.KEY_S) && lastKey.equals("S")) {
	            pc.pDirection = PlayerDirections.South;
	            if(!pc.checkCollisionSouth()){
	                pc.y += pc.maxSpeed;
	                CoreGameState.inputHandler.clearKeyPressedRecord();
	                pc.moving = true;
	            }

	        }
	        else if (CoreGameState.inputHandler.isKeyDown(Input.KEY_A) && lastKey.equals("A")) {
	            pc.pDirection = PlayerDirections.West;
	            if(!pc.checkCollisionWest()){
	                pc.x -= pc.maxSpeed;
	                CoreGameState.inputHandler.clearKeyPressedRecord();
	                pc.moving = true;
	            }

	        }
	        else if (CoreGameState.inputHandler.isKeyDown(Input.KEY_D) && lastKey.equals("D")) {
	            pc.pDirection = PlayerDirections.East;
	            if(!pc.checkCollisionEast()){
	                pc.x += pc.maxSpeed;
	                CoreGameState.inputHandler.clearKeyPressedRecord();
	                pc.moving = true;
	            }

	        }
	    }

		

	    private void determineKeyOrder() {
	        if (!CoreGameState.inputHandler.isKeyDown(Input.KEY_W ) && wKeyWasPressed) {
	            wKeyWasPressed = false;
	            keyOrderList.remove("W");
	        }
	        if (!CoreGameState.inputHandler.isKeyDown(Input.KEY_S ) && sKeyWasPressed) {
	            sKeyWasPressed = false;
	            keyOrderList.remove("S");
	        }
	        if (!CoreGameState.inputHandler.isKeyDown(Input.KEY_A ) && aKeyWasPressed) {
	            aKeyWasPressed = false;
	            keyOrderList.remove("A");
	        }
	        if (!CoreGameState.inputHandler.isKeyDown(Input.KEY_D ) && dKeyWasPressed) {
	            dKeyWasPressed = false;
	            keyOrderList.remove("D");
	        }

	        if (CoreGameState.inputHandler.isKeyDown(Input.KEY_W ) && !wKeyWasPressed) {
	            wKeyWasPressed = true;
	            keyOrderList.add("W");
	        }
	        if (CoreGameState.inputHandler.isKeyDown(Input.KEY_S ) && !sKeyWasPressed) {
	            sKeyWasPressed = true;
	            keyOrderList.add("S");
	        }
	        if (CoreGameState.inputHandler.isKeyDown(Input.KEY_A ) && !aKeyWasPressed) {
	            aKeyWasPressed = true;
	            keyOrderList.add("A");
	        }
	        if (CoreGameState.inputHandler.isKeyDown(Input.KEY_D ) && !dKeyWasPressed) {
	            dKeyWasPressed = true;
	            keyOrderList.add("D");
	        }
	    }

Thanks for the help!
I really thought this would be much simpler :smiley:

Glad I could help!