add controller support (keyboard)

This commit is contained in:
Quillraven
2025-05-29 01:00:16 +02:00
parent 26e663e245
commit a8d0f8cf36
10 changed files with 201 additions and 53 deletions

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.1-99-gec89c545" orientation="orthogonal" renderorder="right-down" width="18" height="16" tilewidth="32" tileheight="32" infinite="0" nextlayerid="7" nextobjectid="4">
<map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="18" height="16" tilewidth="32" tileheight="32" infinite="0" nextlayerid="7" nextobjectid="4">
<tileset firstgid="1" source="tileset.tsx"/>
<tileset firstgid="99" source="objects.tsx"/>
<layer id="1" name="ground" width="18" height="16">
@@ -26,7 +26,11 @@
<object id="3" x="57.4441" y="351.747" width="38.9518" height="37.378"/>
</objectgroup>
<objectgroup id="5" name="objects">
<object id="1" gid="99" x="50.0586" y="458.934" width="32" height="32"/>
<object id="1" gid="99" x="50.0586" y="458.934" width="32" height="32">
<properties>
<property name="controller" type="bool" value="true"/>
</properties>
</object>
<object id="2" gid="99" x="112.269" y="470.818" width="64" height="64"/>
</objectgroup>
</map>

View File

@@ -3,6 +3,7 @@ package io.github.com.quillraven;
import com.badlogic.gdx.Application;
import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputMultiplexer;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.assets.loaders.resolvers.InternalFileHandleResolver;
import com.badlogic.gdx.graphics.GL20;
@@ -28,12 +29,15 @@ public class GdxGame extends Game {
private OrthographicCamera camera;
private Viewport viewport;
private GLProfiler glProfiler;
private InputMultiplexer inputMultiplexer;
private final HashMap<Class<? extends Screen>, Screen> screenCache = new HashMap<>();
@Override
public void create() {
Gdx.app.setLogLevel(Application.LOG_DEBUG);
inputMultiplexer = new InputMultiplexer();
Gdx.input.setInputProcessor(inputMultiplexer);
batch = new SpriteBatch();
assetService = new AssetService(new InternalFileHandleResolver());
@@ -108,4 +112,8 @@ public class GdxGame extends Game {
public Viewport getViewport() {
return viewport;
}
public InputMultiplexer getInputMultiplexer() {
return inputMultiplexer;
}
}

View File

@@ -0,0 +1,6 @@
package io.github.com.quillraven.component;
import com.badlogic.ashley.core.Component;
public class Controller implements Component {
}

View File

@@ -0,0 +1,8 @@
package io.github.com.quillraven.input;
public enum Command {
LEFT,
RIGHT,
DOWN,
UP
}

View File

@@ -0,0 +1,7 @@
package io.github.com.quillraven.input;
public interface ControllerState {
void keyDown(Command command);
void keyUp(Command command);
}

View File

@@ -0,0 +1,92 @@
package io.github.com.quillraven.input;
import com.badlogic.ashley.core.Entity;
import com.badlogic.ashley.utils.ImmutableArray;
import io.github.com.quillraven.component.Move;
public class GameControllerState implements ControllerState {
private final ImmutableArray<Entity> controllerEntities;
public GameControllerState(ImmutableArray<Entity> controllerEntities) {
this.controllerEntities = controllerEntities;
}
@Override
public void keyDown(Command command) {
switch (command) {
case UP:
for (Entity entity : controllerEntities) {
Move move = Move.MAPPER.get(entity);
if (move != null) {
move.getDirection().y += 1f;
}
}
break;
case DOWN:
for (Entity entity : controllerEntities) {
Move move = Move.MAPPER.get(entity);
if (move != null) {
move.getDirection().y -= 1f;
}
}
break;
case LEFT:
for (Entity entity : controllerEntities) {
Move move = Move.MAPPER.get(entity);
if (move != null) {
move.getDirection().x -= 1f;
}
}
break;
case RIGHT:
for (Entity entity : controllerEntities) {
Move move = Move.MAPPER.get(entity);
if (move != null) {
move.getDirection().x += 1f;
}
}
break;
default:
}
}
@Override
public void keyUp(Command command) {
switch (command) {
case UP:
for (Entity entity : controllerEntities) {
Move move = Move.MAPPER.get(entity);
if (move != null) {
move.getDirection().y -= 1f;
}
}
break;
case DOWN:
for (Entity entity : controllerEntities) {
Move move = Move.MAPPER.get(entity);
if (move != null) {
move.getDirection().y += 1f;
}
}
break;
case LEFT:
for (Entity entity : controllerEntities) {
Move move = Move.MAPPER.get(entity);
if (move != null) {
move.getDirection().x += 1f;
}
}
break;
case RIGHT:
for (Entity entity : controllerEntities) {
Move move = Move.MAPPER.get(entity);
if (move != null) {
move.getDirection().x -= 1f;
}
}
break;
default:
}
}
}

View File

@@ -0,0 +1,52 @@
package io.github.com.quillraven.input;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.InputAdapter;
import java.util.Map;
public class KeyboardController extends InputAdapter {
private static final Map<Integer, Command> KEY_MAPPING = Map.ofEntries(
Map.entry(Input.Keys.W, Command.UP),
Map.entry(Input.Keys.S, Command.DOWN),
Map.entry(Input.Keys.A, Command.LEFT),
Map.entry(Input.Keys.D, Command.RIGHT)
);
private final boolean[] commandState;
private ControllerState activeState;
public KeyboardController(ControllerState initialState) {
this.commandState = new boolean[Command.values().length];
setActiveState(initialState);
}
public void setActiveState(ControllerState controllerState) {
for (Command command : Command.values()) {
this.commandState[command.ordinal()] = false;
}
this.activeState = controllerState;
}
@Override
public boolean keyDown(int keycode) {
Command command = KEY_MAPPING.get(keycode);
if (command == null) return false;
this.commandState[command.ordinal()] = true;
this.activeState.keyDown(command);
return true;
}
@Override
public boolean keyUp(int keycode) {
Command command = KEY_MAPPING.get(keycode);
if (command == null) return false;
// if a button was not pressed before, ignore it
if (!this.commandState[command.ordinal()]) return false;
this.commandState[command.ordinal()] = false;
this.activeState.keyUp(command);
return true;
}
}

View File

@@ -1,7 +1,10 @@
package io.github.com.quillraven.screen;
import com.badlogic.ashley.core.Engine;
import com.badlogic.ashley.core.Entity;
import com.badlogic.ashley.core.EntitySystem;
import com.badlogic.ashley.core.Family;
import com.badlogic.ashley.utils.ImmutableArray;
import com.badlogic.gdx.ScreenAdapter;
import com.badlogic.gdx.maps.tiled.TiledMap;
import com.badlogic.gdx.math.Vector2;
@@ -9,6 +12,9 @@ import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.utils.Disposable;
import io.github.com.quillraven.GdxGame;
import io.github.com.quillraven.asset.MapAsset;
import io.github.com.quillraven.component.Controller;
import io.github.com.quillraven.input.GameControllerState;
import io.github.com.quillraven.input.KeyboardController;
import io.github.com.quillraven.system.AnimationSystem;
import io.github.com.quillraven.system.FacingSystem;
import io.github.com.quillraven.system.FsmSystem;
@@ -16,19 +22,20 @@ import io.github.com.quillraven.system.PhysicDebugRenderSystem;
import io.github.com.quillraven.system.PhysicMoveSystem;
import io.github.com.quillraven.system.PhysicSystem;
import io.github.com.quillraven.system.RenderSystem;
import io.github.com.quillraven.system.TestSystem;
import io.github.com.quillraven.tiled.TiledAshleySpawner;
import io.github.com.quillraven.tiled.TiledService;
import java.util.function.Consumer;
public class GameScreen extends ScreenAdapter {
private final GdxGame game;
private final TiledService tiledService;
private final Engine engine;
private final TiledAshleySpawner tiledAshleySpawner;
private final World physicWorld;
public GameScreen(GdxGame game) {
this.game = game;
this.tiledService = new TiledService(game.getAssetService());
this.physicWorld = new World(Vector2.Zero, true);
this.physicWorld.setAutoClearForces(false);
@@ -42,12 +49,16 @@ public class GameScreen extends ScreenAdapter {
this.engine.addSystem(new FsmSystem());
this.engine.addSystem(new AnimationSystem(game.getAssetService()));
this.engine.addSystem(new RenderSystem(game.getBatch(), game.getViewport(), game.getCamera()));
this.engine.addSystem(new TestSystem(this.tiledService));
this.engine.addSystem(new PhysicDebugRenderSystem(this.physicWorld, game.getCamera()));
}
@Override
public void show() {
this.game.getInputMultiplexer().clear();
ImmutableArray<Entity> controllerEntities = this.engine.getEntitiesFor(Family.all(Controller.class).get());
GameControllerState gameControllerState = new GameControllerState(controllerEntities);
this.game.getInputMultiplexer().addProcessor(new KeyboardController(gameControllerState));
Consumer<TiledMap> renderConsumer = this.engine.getSystem(RenderSystem.class)::setMap;
Consumer<TiledMap> ashleySpawnerConsumer = this.tiledAshleySpawner::loadMapObjects;
this.tiledService.setMapChangeConsumer(renderConsumer.andThen(ashleySpawnerConsumer));

View File

@@ -1,49 +0,0 @@
package io.github.com.quillraven.system;
import com.badlogic.ashley.core.Entity;
import com.badlogic.ashley.core.EntitySystem;
import com.badlogic.ashley.core.Family;
import com.badlogic.ashley.utils.ImmutableArray;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import io.github.com.quillraven.component.Move;
import io.github.com.quillraven.tiled.TiledService;
public class TestSystem extends EntitySystem {
private final TiledService tiledService;
public TestSystem(TiledService tiledService) {
super();
this.tiledService = tiledService;
}
@Override
public void update(float deltaTime) {
if (Gdx.input.isKeyJustPressed(Input.Keys.W)) {
ImmutableArray<Entity> entities = getEngine().getEntitiesFor(Family.all(Move.class).get());
for (Entity entity : entities) {
Move.MAPPER.get(entity).getDirection().set(0f, 1f);
}
} else if (Gdx.input.isKeyJustPressed(Input.Keys.S)) {
ImmutableArray<Entity> entities = getEngine().getEntitiesFor(Family.all(Move.class).get());
for (Entity entity : entities) {
Move.MAPPER.get(entity).getDirection().set(0f, -1f);
}
} else if (Gdx.input.isKeyJustPressed(Input.Keys.A)) {
ImmutableArray<Entity> entities = getEngine().getEntitiesFor(Family.all(Move.class).get());
for (Entity entity : entities) {
Move.MAPPER.get(entity).getDirection().set(-1f, 0f);
}
} else if (Gdx.input.isKeyJustPressed(Input.Keys.D)) {
ImmutableArray<Entity> entities = getEngine().getEntitiesFor(Family.all(Move.class).get());
for (Entity entity : entities) {
Move.MAPPER.get(entity).getDirection().set(1f, 0f);
}
} else if (Gdx.input.isKeyJustPressed(Input.Keys.Q)) {
ImmutableArray<Entity> entities = getEngine().getEntitiesFor(Family.all(Move.class).get());
for (Entity entity : entities) {
Move.MAPPER.get(entity).getDirection().setZero();
}
}
}
}

View File

@@ -26,6 +26,7 @@ import io.github.com.quillraven.GdxGame;
import io.github.com.quillraven.asset.AtlasAsset;
import io.github.com.quillraven.component.Animation2D;
import io.github.com.quillraven.component.Animation2D.AnimationType;
import io.github.com.quillraven.component.Controller;
import io.github.com.quillraven.component.Facing;
import io.github.com.quillraven.component.Facing.FacingDirection;
import io.github.com.quillraven.component.Fsm;
@@ -127,6 +128,7 @@ public class TiledAshleySpawner {
entity);
addEntityAnimation(tile, entity);
addEntityMove(tile, entity);
addEntityController(tileMapObject, entity);
entity.add(new Facing(FacingDirection.DOWN));
entity.add(new Fsm(entity));
entity.add(new Graphic(textureRegion, Color.WHITE.cpy()));
@@ -134,6 +136,13 @@ public class TiledAshleySpawner {
this.engine.addEntity(entity);
}
private void addEntityController(TiledMapTileMapObject tileMapObject, Entity entity) {
boolean controller = tileMapObject.getProperties().get("controller", false, Boolean.class);
if (!controller) return;
entity.add(new Controller());
}
private void addEntityMove(TiledMapTile tile, Entity entity) {
float speed = tile.getProperties().get("speed", 0f, Float.class);
if (speed == 0f) return;