From f28811ae9271b028e72beb52737234f47710f44e Mon Sep 17 00:00:00 2001 From: Bram Teurlings Date: Mon, 25 May 2026 01:54:45 +0200 Subject: [PATCH 1/5] Attempting to fix input Everything works for the player animations are jittery on controller now. haven't tested mobile either but mouse works. --- .../src/forge/adventure/stage/GameStage.java | 74 ++++++++++++++++--- .../src/forge/adventure/util/KeyBinding.java | 4 + 2 files changed, 66 insertions(+), 12 deletions(-) diff --git a/forge-gui-mobile/src/forge/adventure/stage/GameStage.java b/forge-gui-mobile/src/forge/adventure/stage/GameStage.java index 4944c9822a4e..39c71c04f1c2 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/GameStage.java +++ b/forge-gui-mobile/src/forge/adventure/stage/GameStage.java @@ -1,5 +1,6 @@ package forge.adventure.stage; +import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input; import com.badlogic.gdx.controllers.Controller; import com.badlogic.gdx.files.FileHandle; @@ -75,6 +76,9 @@ public abstract class GameStage extends Stage { private float animationTimeout = 0; public static float maximumScrollDistance = 1.5f; public static float minimumScrollDistance = 0.3f; + private final Vector2 keyboardInput = new Vector2(); + private final Vector2 controllerInput = new Vector2(); + private final Vector2 touchInput = new Vector2(); private String extraAnnouncement = ""; @@ -253,8 +257,7 @@ public boolean axisMoved(Controller controller, int axisIndex, float value) { if (MapStage.getInstance().isDialogOnlyInput() || isPaused()) { return true; } - player.getMovementDirection().x = controller.getAxis(0); - player.getMovementDirection().y = -controller.getAxis(1); + controllerInput.set(controller.getAxis(0), -controller.getAxis(1)); if (player.getMovementDirection().len() < 0.2) { player.stop(); } @@ -354,6 +357,55 @@ public Group getBackgroundSprites() { @Override public final void act(float delta) { + keyboardInput.setZero(); + + for (int key : KeyBinding.Left.getBindings()) { + if (Gdx.input.isKeyPressed(key)) { + keyboardInput.x = -1; + break; + } + } + + for (int key : KeyBinding.Right.getBindings()) { + if (Gdx.input.isKeyPressed(key)) { + keyboardInput.x = 1; + break; + } + } + + for (int key : KeyBinding.Up.getBindings()) { + if (Gdx.input.isKeyPressed(key)) { + keyboardInput.y = 1; + break; + } + } + + for (int key : KeyBinding.Down.getBindings()) { + if (Gdx.input.isKeyPressed(key)) { + keyboardInput.y = -1; + break; + } + } + + + Vector2 dir = new Vector2(); + + // Input priority: touch > controller > keyboard + if (touchX >= 0 && touchInput.len() > 0.2f) { + dir.set(touchInput); + + } else if (controllerInput.len() > 0.2f) { + dir.set(controllerInput); + + } else { + dir.set(keyboardInput); + } + if (dir.len() < 0.01f) { + player.stop(); + } else { + player.getMovementDirection().set(dir); + } + super.act(delta); if (animationTimeout >= 0) { @@ -375,7 +427,6 @@ public final void act(float delta) { return; } - if (onEndAction != null) { onEndAction.run(); @@ -384,14 +435,15 @@ public final void act(float delta) { if (touchX >= 0) { Vector2 target = this.screenToStageCoordinates(new Vector2(touchX, touchY)); + target.x -= player.getWidth() / 2f; Vector2 diff = target.sub(player.pos()); if (diff.len() < 2) { - diff.setZero(); - player.stop(); + touchInput.setZero(); + } else { + touchInput.set(diff); } - player.setMovementDirection(diff); } camera.position.x = Math.min(Math.max(Scene.getIntendedWidth() / 2f, player.pos().x), getViewport().getWorldWidth() - Scene.getIntendedWidth() / 2f); camera.position.y = Math.min(Math.max(Scene.getIntendedHeight() / 2f, player.pos().y), getViewport().getWorldHeight() - Scene.getIntendedHeight() / 2f); @@ -422,16 +474,16 @@ public boolean keyDown(int keycode) { if (isPaused()) return true; if (KeyBinding.Left.isPressed(keycode)) { - player.getMovementDirection().x = -1; + keyboardInput.x = -1; } if (KeyBinding.Right.isPressed(keycode)) { - player.getMovementDirection().x = +1; + keyboardInput.x = +1; } if (KeyBinding.Up.isPressed(keycode)) { - player.getMovementDirection().y = +1; + keyboardInput.y = +1; } if (KeyBinding.Down.isPressed(keycode)) { - player.getMovementDirection().y = -1; + keyboardInput.y = -1; } if (keycode == Input.Keys.F5)//todo config { @@ -558,12 +610,10 @@ public boolean keyUp(int keycode) { if (isPaused()) return true; if (KeyBinding.Left.isPressed(keycode) || KeyBinding.Right.isPressed(keycode)) { - player.getMovementDirection().x = 0; if (!player.isMoving()) stop(); } if (KeyBinding.Down.isPressed(keycode) || KeyBinding.Up.isPressed(keycode)) { - player.getMovementDirection().y = 0; if (!player.isMoving()) stop(); } diff --git a/forge-gui-mobile/src/forge/adventure/util/KeyBinding.java b/forge-gui-mobile/src/forge/adventure/util/KeyBinding.java index cb103c6b8a9b..a1d1fbb7d7ee 100644 --- a/forge-gui-mobile/src/forge/adventure/util/KeyBinding.java +++ b/forge-gui-mobile/src/forge/adventure/util/KeyBinding.java @@ -49,6 +49,10 @@ public boolean isPressed(int key, Boolean requiredCondition) { return false; } + public int[] getBindings() { + return bindings; + } + // The controller binding always has index 1. final static String controllerPrefix = "XBox_"; From b26085161bab6b4efe855a73f26465d7b1dd9f29 Mon Sep 17 00:00:00 2001 From: Bram Teurlings Date: Mon, 25 May 2026 02:06:12 +0200 Subject: [PATCH 2/5] Fixed controller jitter. Still not tested on mobile but will do later. (Should be the same as mouse input) --- forge-gui-mobile/src/forge/adventure/stage/GameStage.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/forge-gui-mobile/src/forge/adventure/stage/GameStage.java b/forge-gui-mobile/src/forge/adventure/stage/GameStage.java index 39c71c04f1c2..d0f022bc050e 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/GameStage.java +++ b/forge-gui-mobile/src/forge/adventure/stage/GameStage.java @@ -258,9 +258,6 @@ public boolean axisMoved(Controller controller, int axisIndex, float value) { return true; } controllerInput.set(controller.getAxis(0), -controller.getAxis(1)); - if (player.getMovementDirection().len() < 0.2) { - player.stop(); - } return true; } @@ -387,7 +384,6 @@ public final void act(float delta) { } } - Vector2 dir = new Vector2(); // Input priority: touch > controller > keyboard From 467ab526ea45477cfaf057bcbdde5f33b9c86802 Mon Sep 17 00:00:00 2001 From: Bram Teurlings Date: Mon, 25 May 2026 02:11:59 +0200 Subject: [PATCH 3/5] Cleanup of GameStage.java --- .../src/forge/adventure/stage/GameStage.java | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/forge-gui-mobile/src/forge/adventure/stage/GameStage.java b/forge-gui-mobile/src/forge/adventure/stage/GameStage.java index d0f022bc050e..55ea9ee9f553 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/GameStage.java +++ b/forge-gui-mobile/src/forge/adventure/stage/GameStage.java @@ -252,7 +252,6 @@ public void showDeckAwardDialog(String message, Deck deck, Runnable runnable) { showDialog(); } - public boolean axisMoved(Controller controller, int axisIndex, float value) { if (MapStage.getInstance().isDialogOnlyInput() || isPaused()) { return true; @@ -268,7 +267,6 @@ enum PlayerModification { } - HashMap currentModifications = new HashMap<>(); public void modifyPlayer(PlayerModification mod, float value) { @@ -355,28 +353,24 @@ public Group getBackgroundSprites() { @Override public final void act(float delta) { keyboardInput.setZero(); - for (int key : KeyBinding.Left.getBindings()) { if (Gdx.input.isKeyPressed(key)) { keyboardInput.x = -1; break; } } - for (int key : KeyBinding.Right.getBindings()) { if (Gdx.input.isKeyPressed(key)) { keyboardInput.x = 1; break; } } - for (int key : KeyBinding.Up.getBindings()) { if (Gdx.input.isKeyPressed(key)) { keyboardInput.y = 1; break; } } - for (int key : KeyBinding.Down.getBindings()) { if (Gdx.input.isKeyPressed(key)) { keyboardInput.y = -1; @@ -384,9 +378,8 @@ public final void act(float delta) { } } - Vector2 dir = new Vector2(); - // Input priority: touch > controller > keyboard + Vector2 dir = new Vector2(); if (touchX >= 0 && touchInput.len() > 0.2f) { dir.set(touchInput); @@ -463,7 +456,6 @@ private void onRemoveEffect(PlayerModification mod) { abstract protected void onActing(float delta); - @Override public boolean keyDown(int keycode) { super.keyDown(keycode); From 82714d1921baf30d9f0098e4ce91ffb5ca2d7735 Mon Sep 17 00:00:00 2001 From: BramTeurlings Date: Mon, 6 Jul 2026 16:07:15 +0200 Subject: [PATCH 4/5] Mirroring changes from https://github.com/Card-Forge/forge/pull/11167 --- .../src/forge/adventure/stage/Console.java | 5 +- .../src/forge/adventure/stage/GameStage.java | 120 ++++++++++-------- .../src/forge/adventure/stage/WorldStage.java | 4 +- 3 files changed, 70 insertions(+), 59 deletions(-) diff --git a/forge-gui-mobile/src/forge/adventure/stage/Console.java b/forge-gui-mobile/src/forge/adventure/stage/Console.java index 5bc67052d157..03823d7d364a 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/Console.java +++ b/forge-gui-mobile/src/forge/adventure/stage/Console.java @@ -18,11 +18,13 @@ public class Console extends Window { public void toggle() { if (isVisible()) { + Forge.advFreezePlayerControls = false; setVisible(false); getStage().unfocus(input); Gdx.input.setOnscreenKeyboardVisible(false); } else { if (!Forge.advFreezePlayerControls) { + Forge.advFreezePlayerControls = true; setVisible(true); getStage().setKeyboardFocus(input); } @@ -58,7 +60,6 @@ public boolean keyUp(InputEvent event, int keycode) { textField.setCursorPosition(Integer.MAX_VALUE); } else { index = 0; - textField.setText(commands.get(index)); textField.setCursorPosition(Integer.MAX_VALUE); } } else if (!commands.isEmpty()) { @@ -78,7 +79,7 @@ public boolean keyUp(InputEvent event, int keycode) { textField.setCursorPosition(Integer.MAX_VALUE); } else { index = commands.size - 1; - textField.setText(commands.get(index)); + textField.setText(""); textField.setCursorPosition(Integer.MAX_VALUE); } } else if (!commands.isEmpty()) { diff --git a/forge-gui-mobile/src/forge/adventure/stage/GameStage.java b/forge-gui-mobile/src/forge/adventure/stage/GameStage.java index 55ea9ee9f553..422f1c0e3c3b 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/GameStage.java +++ b/forge-gui-mobile/src/forge/adventure/stage/GameStage.java @@ -352,55 +352,13 @@ public Group getBackgroundSprites() { @Override public final void act(float delta) { - keyboardInput.setZero(); - for (int key : KeyBinding.Left.getBindings()) { - if (Gdx.input.isKeyPressed(key)) { - keyboardInput.x = -1; - break; - } - } - for (int key : KeyBinding.Right.getBindings()) { - if (Gdx.input.isKeyPressed(key)) { - keyboardInput.x = 1; - break; - } - } - for (int key : KeyBinding.Up.getBindings()) { - if (Gdx.input.isKeyPressed(key)) { - keyboardInput.y = 1; - break; - } - } - for (int key : KeyBinding.Down.getBindings()) { - if (Gdx.input.isKeyPressed(key)) { - keyboardInput.y = -1; - break; - } - } - - // Input priority: touch > controller > keyboard - Vector2 dir = new Vector2(); - if (touchX >= 0 && touchInput.len() > 0.2f) { - dir.set(touchInput); - - } else if (controllerInput.len() > 0.2f) { - dir.set(controllerInput); - - } else { - dir.set(keyboardInput); - } - if (dir.len() < 0.01f) { - player.stop(); - } else { - player.getMovementDirection().set(dir); - } - super.act(delta); if (animationTimeout >= 0) { animationTimeout -= delta; return; } + Array modsToRemove = new Array<>(); for (Map.Entry mod : currentModifications.entrySet()) { mod.setValue(mod.getValue() - delta); @@ -412,28 +370,75 @@ public final void act(float delta) { onRemoveEffect(mod); } - if (isPaused()) { - return; - } - if (onEndAction != null) { - onEndAction.run(); onEndAction = null; } - if (touchX >= 0) { - Vector2 target = this.screenToStageCoordinates(new Vector2(touchX, touchY)); + if (isPaused() || isDialogOnlyInput() || Forge.advFreezePlayerControls) { + keyboardInput.setZero(); + controllerInput.setZero(); + touchInput.setZero(); + player.getMovementDirection().setZero(); + player.stop(); + } else { + keyboardInput.setZero(); + for (int key : KeyBinding.Left.getBindings()) { + if (Gdx.input.isKeyPressed(key)) { + keyboardInput.x = -1; + break; + } + } + for (int key : KeyBinding.Right.getBindings()) { + if (Gdx.input.isKeyPressed(key)) { + keyboardInput.x = 1; + break; + } + } + for (int key : KeyBinding.Up.getBindings()) { + if (Gdx.input.isKeyPressed(key)) { + keyboardInput.y = 1; + break; + } + } + for (int key : KeyBinding.Down.getBindings()) { + if (Gdx.input.isKeyPressed(key)) { + keyboardInput.y = -1; + break; + } + } + + // Input priority: touch > controller > keyboard + Vector2 dir = new Vector2(); + if (touchX >= 0 && touchInput.len() > 0.2f) { + dir.set(touchInput); - target.x -= player.getWidth() / 2f; - Vector2 diff = target.sub(player.pos()); + } else if (controllerInput.len() > 0.2f) { + dir.set(controllerInput); - if (diff.len() < 2) { - touchInput.setZero(); } else { - touchInput.set(diff); + dir.set(keyboardInput); + } + if (dir.len() < 0.01f) { + player.stop(); + } else { + player.getMovementDirection().set(dir); + } + + if (touchX >= 0) { + Vector2 target = this.screenToStageCoordinates(new Vector2(touchX, touchY)); + target.x -= player.getWidth() / 2f; + Vector2 diff = target.sub(player.pos()); + + if (diff.len() < 2) { + touchInput.setZero(); + player.stop(); + } else { + touchInput.set(diff); + } } } + camera.position.x = Math.min(Math.max(Scene.getIntendedWidth() / 2f, player.pos().x), getViewport().getWorldWidth() - Scene.getIntendedWidth() / 2f); camera.position.y = Math.min(Math.max(Scene.getIntendedHeight() / 2f, player.pos().y), getViewport().getWorldHeight() - Scene.getIntendedHeight() / 2f); @@ -582,6 +587,9 @@ public boolean touchDown(int screenX, int screenY, int pointer, int button) { public void stop() { WorldStage.getInstance().getPlayerSprite().setMovementDirection(Vector2.Zero); MapStage.getInstance().getPlayerSprite().setMovementDirection(Vector2.Zero); + touchInput.setZero(); + keyboardInput.setZero(); + controllerInput.setZero(); touchX = -1; touchY = -1; player.stop(); @@ -598,10 +606,12 @@ public boolean keyUp(int keycode) { if (isPaused()) return true; if (KeyBinding.Left.isPressed(keycode) || KeyBinding.Right.isPressed(keycode)) { + player.getMovementDirection().x = 0; if (!player.isMoving()) stop(); } if (KeyBinding.Down.isPressed(keycode) || KeyBinding.Up.isPressed(keycode)) { + player.getMovementDirection().y = 0; if (!player.isMoving()) stop(); } diff --git a/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java b/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java index a843e4b434ae..043005647efa 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java +++ b/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java @@ -230,8 +230,8 @@ public boolean handlePointsOfInterestCollision() { public void loadPOI(PointOfInterest poi) { try { - TileMapScene.instance().load(poi); stop(); + TileMapScene.instance().load(poi); TileMapScene.instance().setFromWorldMap(true); Forge.switchScene(TileMapScene.instance()); } catch (Exception e) { @@ -266,7 +266,7 @@ private void handleMonsterSpawn(float delta) { } World world = WorldSave.getCurrentSave().getWorld(); - int currentBiome = World.highestBiome(world.getBiome((int) player.getX() / world.getTileSize(), (int) player.getY() / world.getTileSize())); + int currentBiome = World.highestBiome(world.getBiome((int) ((player.getX() + player.getWidth() / 2f) / world.getTileSize()), (int) (player.getY() / world.getTileSize()))); List biomeData = WorldSave.getCurrentSave().getWorld().getData().GetBiomes(); float sprintingMod = currentModifications.containsKey(PlayerModification.Sprint) ? 2 : 1; if (biomeData.size() <= currentBiome) {// "if isOnRoad From a631d4fc4e41468d24d025fa1abd9215a03b102d Mon Sep 17 00:00:00 2001 From: BramTeurlings Date: Tue, 11 Aug 2026 10:21:55 +0200 Subject: [PATCH 5/5] Opposing directions now cancel each other out on keyboard Added helper function to KeyBinding.java for getting pressed key from libGDX --- .../src/forge/adventure/stage/GameStage.java | 32 +++++++------------ .../src/forge/adventure/util/KeyBinding.java | 14 +++++--- 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/forge-gui-mobile/src/forge/adventure/stage/GameStage.java b/forge-gui-mobile/src/forge/adventure/stage/GameStage.java index 422f1c0e3c3b..4556094c3469 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/GameStage.java +++ b/forge-gui-mobile/src/forge/adventure/stage/GameStage.java @@ -1,6 +1,5 @@ package forge.adventure.stage; -import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input; import com.badlogic.gdx.controllers.Controller; import com.badlogic.gdx.files.FileHandle; @@ -383,29 +382,20 @@ public final void act(float delta) { player.stop(); } else { keyboardInput.setZero(); - for (int key : KeyBinding.Left.getBindings()) { - if (Gdx.input.isKeyPressed(key)) { - keyboardInput.x = -1; - break; - } + if (KeyBinding.Left.isPressed()) { + keyboardInput.x -= 1; } - for (int key : KeyBinding.Right.getBindings()) { - if (Gdx.input.isKeyPressed(key)) { - keyboardInput.x = 1; - break; - } + + if (KeyBinding.Right.isPressed()) { + keyboardInput.x += 1; } - for (int key : KeyBinding.Up.getBindings()) { - if (Gdx.input.isKeyPressed(key)) { - keyboardInput.y = 1; - break; - } + + if (KeyBinding.Up.isPressed()) { + keyboardInput.y += 1; } - for (int key : KeyBinding.Down.getBindings()) { - if (Gdx.input.isKeyPressed(key)) { - keyboardInput.y = -1; - break; - } + + if (KeyBinding.Down.isPressed()) { + keyboardInput.y -= 1; } // Input priority: touch > controller > keyboard diff --git a/forge-gui-mobile/src/forge/adventure/util/KeyBinding.java b/forge-gui-mobile/src/forge/adventure/util/KeyBinding.java index a1d1fbb7d7ee..d929dd6efafd 100644 --- a/forge-gui-mobile/src/forge/adventure/util/KeyBinding.java +++ b/forge-gui-mobile/src/forge/adventure/util/KeyBinding.java @@ -1,5 +1,6 @@ package forge.adventure.util; +import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input; import com.badlogic.gdx.controllers.Controller; import com.badlogic.gdx.controllers.ControllerMapping; @@ -34,6 +35,15 @@ public enum KeyBinding { this.bindings = bindings; } + public boolean isPressed() { + for (int key : bindings) { + if (Gdx.input.isKeyPressed(key)) { + return true; + } + } + return false; + } + public boolean isPressed(int key) { return isPressed(key, null); } @@ -49,10 +59,6 @@ public boolean isPressed(int key, Boolean requiredCondition) { return false; } - public int[] getBindings() { - return bindings; - } - // The controller binding always has index 1. final static String controllerPrefix = "XBox_";