From 3e4c697350ee888bd4775a8c92ef3dd0f468ea45 Mon Sep 17 00:00:00 2001 From: Samiker <168203446+Samiker69@users.noreply.github.com> Date: Tue, 3 Feb 2026 01:17:00 +0300 Subject: [PATCH] =?UTF-8?q?Fix=20(Client):=20=D0=A2=D0=B5=D0=BF=D0=B5?= =?UTF-8?q?=D1=80=D1=8C=20=D0=B3=D1=83=D0=B8=20=D0=BD=D0=B0=20=D0=B2=D1=81?= =?UTF-8?q?=D0=B5=D1=85=20=D1=83=D1=81=D1=82=D1=80=D0=BE=D0=B9=D1=81=D1=82?= =?UTF-8?q?=D0=B2=D0=B0=D1=85=20=D0=B4=D0=BE=D0=BB=D0=B6=D0=B5=D0=BD=20?= =?UTF-8?q?=D0=B1=D1=8B=D1=82=D1=8C=20=D0=BE=D0=B4=D0=B8=D0=BD=D0=B0=D0=BA?= =?UTF-8?q?=D0=BE=D0=B2=D1=8B=D0=BC=20-=20=D0=B2=D0=B5=D1=80=D0=BE=D1=8F?= =?UTF-8?q?=D1=82=D0=BD=D0=BE,=20=D1=81=D0=B5=D0=B9=D1=87=D0=B0=D1=81=20?= =?UTF-8?q?=D1=8D=D1=82=D0=BE=20=D0=B1=D1=83=D0=B4=D0=B5=D1=82=20=D0=B2?= =?UTF-8?q?=D1=8B=D0=B3=D0=BB=D1=8F=D0=B4=D0=B5=D1=82=D1=8C=20=D0=BA=D0=B0?= =?UTF-8?q?=D0=BA=20=D0=BC=D1=8B=D0=BB=D0=BE.=20=D0=B2=D1=8B=D0=B1=D1=80?= =?UTF-8?q?=D0=B0=D0=BD=D0=BE=20=D1=80=D0=B0=D0=B7=D1=80=D0=B5=D1=89=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=201440=D1=85720=20-=20=D0=B8=D1=81=D0=BF?= =?UTF-8?q?=D1=80=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=BB=D0=BE=D0=B3?= =?UTF-8?q?=D0=B8=D0=BA=D0=B0=20=D0=BA=D0=BE=D0=BB=D0=BB=D0=B8=D0=B7=D0=B8?= =?UTF-8?q?=D0=B9,=20=D1=82=D0=B5=D0=BF=D1=80=D0=B5=D1=8C=20=D0=BE=D0=BD?= =?UTF-8?q?=D0=B0=20=D0=B1=D0=BE=D0=BB=D0=B5=D0=B5=20=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D0=B5=D0=B5=20=D0=B8=D0=B4=D0=B5=D0=B0=D0=BB=D1=8C=D0=BD=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 +- .../xyz/samiker/theendlessweave/Main.java | 12 +- .../custom/ClientConstants.java | 6 + .../theendlessweave/screens/GameScreen.java | 15 +-- .../screens/GenerationScreen.java | 9 +- .../screens/MainMenuScreen.java | 6 +- .../screens/SettingsScreen.java | 112 ++++++++++-------- .../theendlessweave/systems/RenderSystem.java | 4 +- .../systems/MovementSystem.java | 63 ++++++---- 9 files changed, 143 insertions(+), 90 deletions(-) create mode 100644 core/src/main/java/xyz/samiker/theendlessweave/custom/ClientConstants.java diff --git a/README.md b/README.md index 39a7ee5..02e445d 100644 --- a/README.md +++ b/README.md @@ -69,14 +69,14 @@ java -jar filename-client.jar --server - [X] создать ветку и настроить `build.gradle.kts`. - Баги/проблемы (исправить) - ? Из-за написанного кода под javafx, на клиенте могут возникать проблемы с логикой из-за другой системы координат в libgdx, например, при просчёте логики полёта пуль, необходимо домножать скорость на размер тайлов. - - [ ] коллизия/рендер пулек поломались и они могут заходить сквозь стены. + - [x] коллизия/рендер пулек поломались и они могут заходить сквозь стены. - ? вероятно при нестандарных размерах экрана рендер ломается. - [X] сервер не удаляет игрока, если он отключился. - [ ] клиент рендерит других игроков как врагов. - [X] ui не масштабируется как надо при изменении размера окна. - [ ] при очень высоких значениях fps плавное движение камеры менее заметно. - - [ ] при fullscreen размер окна равен разрешению в настройках - - [ ] если на мобильном устройстве поменять разрешение в настройках то игра крашнет + - [x] (?) при fullscreen размер окна равен разрешению в настройках + - [x] если на мобильном устройстве поменять разрешение в настройках то игра крашнет - solution: скрыть для мобильных устройств настройки разрешения. - сделать в Main метод isMobile для проверки среды без и с учётом выбранного управления diff --git a/core/src/main/java/xyz/samiker/theendlessweave/Main.java b/core/src/main/java/xyz/samiker/theendlessweave/Main.java index 675f69b..220b9d8 100644 --- a/core/src/main/java/xyz/samiker/theendlessweave/Main.java +++ b/core/src/main/java/xyz/samiker/theendlessweave/Main.java @@ -16,14 +16,15 @@ public class Main extends Game { public SpriteBatch batch; private ManifestAssetManager assetManager; public static boolean isMobile; - + public static boolean isMobControl; @Override public void create() { batch = new SpriteBatch(); try { assetManager = new ManifestAssetManager(ResourceManifest.load()); - isMobile = (Gdx.app.getType() == Application.ApplicationType.Android || Gdx.app.getType() == Application.ApplicationType.iOS) || SettingsManager.getString(ClientSettings.CONTROL).contains("mobile"); + isMobile = isMobile(false); + isMobControl = isMobile(true); } catch (IOException e) { throw new RuntimeException(e); } @@ -51,6 +52,7 @@ public ManifestAssetManager getAssetManager() { } public void applySettings() { + if (isMobile) return; boolean isFullscreen = SettingsManager.getBoolean(ClientSettings.FULLSCREEN); boolean isBorderless = SettingsManager.getBoolean(ClientSettings.BORDERLESS); @@ -66,4 +68,10 @@ public void applySettings() { } } } + + public static boolean isMobile(boolean byControl) { + return byControl ? + SettingsManager.getString(ClientSettings.CONTROL).contains("mobile") : + (Gdx.app.getType() == Application.ApplicationType.Android || Gdx.app.getType() == Application.ApplicationType.iOS); + } } \ No newline at end of file diff --git a/core/src/main/java/xyz/samiker/theendlessweave/custom/ClientConstants.java b/core/src/main/java/xyz/samiker/theendlessweave/custom/ClientConstants.java new file mode 100644 index 0000000..807386c --- /dev/null +++ b/core/src/main/java/xyz/samiker/theendlessweave/custom/ClientConstants.java @@ -0,0 +1,6 @@ +package xyz.samiker.theendlessweave.custom; + +public class ClientConstants { + public static final float VIRTUAL_WIDTH = 1440; + public static final float VIRTUAL_HEIGHT = 720; +} diff --git a/core/src/main/java/xyz/samiker/theendlessweave/screens/GameScreen.java b/core/src/main/java/xyz/samiker/theendlessweave/screens/GameScreen.java index d77d487..71ba2f3 100644 --- a/core/src/main/java/xyz/samiker/theendlessweave/screens/GameScreen.java +++ b/core/src/main/java/xyz/samiker/theendlessweave/screens/GameScreen.java @@ -16,6 +16,7 @@ import com.badlogic.gdx.utils.viewport.Viewport; import xyz.samiker.theendlessweave.Main; import xyz.samiker.theendlessweave.assetsManager.ManifestAssetManager; +import xyz.samiker.theendlessweave.custom.ClientConstants; import xyz.samiker.theendlessweave.custom.InputManager; import xyz.samiker.theendlessweave.network.GameClient; import xyz.samiker.theendlessweave.settings.ClientSettings; @@ -33,7 +34,6 @@ import java.io.IOException; public class GameScreen implements Screen { - private final Main mainApp; private GameData data; @@ -78,8 +78,9 @@ public GameScreen(Main mainApp) { public void show() { batch = new SpriteBatch(); - float worldWidth = Gdx.graphics.getWidth(); - float worldHeight = Gdx.graphics.getHeight(); + float worldWidth = ClientConstants.VIRTUAL_WIDTH; + float worldHeight = ClientConstants.VIRTUAL_HEIGHT; + gameCamera = new OrthographicCamera(); gameViewport = new ExtendViewport(worldWidth, worldHeight, gameCamera); @@ -131,7 +132,7 @@ private void setupUI() { private void setupMobileControls() { String controlMode = SettingsManager.getString(ClientSettings.CONTROL); if ("auto".equals(controlMode)) { - controlMode = Main.isMobile ? "mobile_aim_joystick" : "pc"; + controlMode = Main.isMobile(true) ? "mobile_aim_joystick" : "pc"; } if ("pc".equals(controlMode)) return; @@ -169,7 +170,7 @@ public void touchUp(InputEvent event, float x, float y, int pointer, int button) private void updateUI() { debugLabel.setPosition(10, Gdx.graphics.getHeight() / 2f); - if (Main.isMobile) { + if (Main.isMobControl) { if (aimStick != null) aimStick.setBounds(Gdx.graphics.getWidth() - 250, 50, 200, 200); if (attackBtn != null) attackBtn.setPosition(Gdx.graphics.getWidth() - 150, Gdx.graphics.getHeight() - 300); } @@ -257,7 +258,7 @@ private void initializeGameSession(PacketLoginResponse serverData) { var map = gameLogic.getGameMap(); var profiler = gameLogic.getProfiler(); InputSystem inputSystem = new InputSystem(client, gameLogic, gameCamera); - inputSystem.setInputMode(Main.isMobile); + inputSystem.setInputMode(Main.isMobControl); gameLogic.addLogicSystem(new ClientNetworkEventSystem(client, gameLogic)); gameLogic.addLogicSystem(inputSystem); @@ -297,7 +298,7 @@ public void render(float delta) { gameCamera.update(); batch.setProjectionMatrix(gameCamera.combined); - if (Main.isMobile) { + if (Main.isMobControl) { double deadzone = 0.3; if (moveStick != null) { InputManager.handleAxis(moveStick.getKnobPercentX(), deadzone, Input.Keys.D, Input.Keys.A); diff --git a/core/src/main/java/xyz/samiker/theendlessweave/screens/GenerationScreen.java b/core/src/main/java/xyz/samiker/theendlessweave/screens/GenerationScreen.java index 9299bdb..e85ab8f 100644 --- a/core/src/main/java/xyz/samiker/theendlessweave/screens/GenerationScreen.java +++ b/core/src/main/java/xyz/samiker/theendlessweave/screens/GenerationScreen.java @@ -10,13 +10,16 @@ import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; import com.badlogic.gdx.utils.ScreenUtils; -import com.badlogic.gdx.utils.viewport.ScreenViewport; +import com.badlogic.gdx.utils.viewport.ExtendViewport; import xyz.samiker.theendlessweave.Main; import xyz.samiker.theendlessweave.GameData; import xyz.samiker.theendlessweave.gamemap.MapGeneratorSettings; import java.util.Random; +import static xyz.samiker.theendlessweave.custom.ClientConstants.VIRTUAL_HEIGHT; +import static xyz.samiker.theendlessweave.custom.ClientConstants.VIRTUAL_WIDTH; + public class GenerationScreen implements Screen { private final Main game; @@ -65,7 +68,7 @@ public GenerationScreen(Main game) { @Override public void show() { - stage = new Stage(new ScreenViewport()); + stage = new Stage(new ExtendViewport(VIRTUAL_WIDTH, VIRTUAL_HEIGHT)); Gdx.input.setInputProcessor(stage); skin = new Skin(Gdx.files.internal("ui/uiskin.json")); @@ -165,7 +168,9 @@ public void changed(ChangeEvent event, Actor actor) { details.defaults().left().pad(5); widthField = createIntField("Width:", details); + widthField.setText("100"); heightField = createIntField("Height:", details); + heightField.setText("100"); details.row(); minRoomSizeField = createIntField("Min Room:", details); diff --git a/core/src/main/java/xyz/samiker/theendlessweave/screens/MainMenuScreen.java b/core/src/main/java/xyz/samiker/theendlessweave/screens/MainMenuScreen.java index 8a5124b..2d5da90 100644 --- a/core/src/main/java/xyz/samiker/theendlessweave/screens/MainMenuScreen.java +++ b/core/src/main/java/xyz/samiker/theendlessweave/screens/MainMenuScreen.java @@ -9,9 +9,13 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextButton; import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; import com.badlogic.gdx.utils.ScreenUtils; +import com.badlogic.gdx.utils.viewport.ExtendViewport; import com.badlogic.gdx.utils.viewport.ScreenViewport; import xyz.samiker.theendlessweave.Main; +import static xyz.samiker.theendlessweave.custom.ClientConstants.VIRTUAL_HEIGHT; +import static xyz.samiker.theendlessweave.custom.ClientConstants.VIRTUAL_WIDTH; + public class MainMenuScreen implements Screen { private final Main game; private Stage stage; @@ -23,7 +27,7 @@ public MainMenuScreen(Main game) { @Override public void show() { - stage = new Stage(new ScreenViewport()); + stage = new Stage(new ExtendViewport(VIRTUAL_WIDTH, VIRTUAL_HEIGHT)); Gdx.input.setInputProcessor(stage); skin = new Skin(Gdx.files.internal("ui/uiskin.json")); diff --git a/core/src/main/java/xyz/samiker/theendlessweave/screens/SettingsScreen.java b/core/src/main/java/xyz/samiker/theendlessweave/screens/SettingsScreen.java index dc4fcfa..4474c4c 100644 --- a/core/src/main/java/xyz/samiker/theendlessweave/screens/SettingsScreen.java +++ b/core/src/main/java/xyz/samiker/theendlessweave/screens/SettingsScreen.java @@ -10,11 +10,15 @@ import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; import com.badlogic.gdx.utils.ScreenUtils; +import com.badlogic.gdx.utils.viewport.ExtendViewport; import com.badlogic.gdx.utils.viewport.ScreenViewport; import xyz.samiker.theendlessweave.Main; import xyz.samiker.theendlessweave.settings.ClientSettings; import xyz.samiker.theendlessweave.settings.SettingsManager; +import static xyz.samiker.theendlessweave.custom.ClientConstants.VIRTUAL_HEIGHT; +import static xyz.samiker.theendlessweave.custom.ClientConstants.VIRTUAL_WIDTH; + public class SettingsScreen implements Screen { private final Main game; @@ -32,7 +36,7 @@ public SettingsScreen(Main game) { @Override public void show() { - stage = new Stage(new ScreenViewport()); + stage = new Stage(new ExtendViewport(VIRTUAL_WIDTH, VIRTUAL_HEIGHT)); Gdx.input.setInputProcessor(stage); skin = new Skin(Gdx.files.internal("ui/uiskin.json")); @@ -49,7 +53,7 @@ private void buildLayout() { stage.addActor(root); Label title = new Label("Settings", skin); - title.setFontScale(1.5f); + title.setFontScale(1.2f); root.add(title).padBottom(20).colspan(2).row(); Table tabsTable = new Table(); @@ -151,45 +155,46 @@ private void showVideoSettings() { table.pad(20); table.defaults().left().pad(5); - table.add(new Label("Resolution:", skin)); - SelectBox resolutionSelect = new SelectBox<>(skin); - resolutionSelect.setItems("1920x1200", "1920x1080", "1600x900", "1366x768", "1280x720", "800x600"); - resolutionSelect.setSelected(SettingsManager.getString(ClientSettings.RESOLUTION)); - table.add(resolutionSelect).width(200).row(); - - boolean fscr = SettingsManager.getBoolean(ClientSettings.FULLSCREEN); - boolean brdr = SettingsManager.getBoolean(ClientSettings.BORDERLESS); - CheckBox fullscreenCheck = new CheckBox(" Fullscreen", skin); - fullscreenCheck.setChecked(fscr && !brdr); - - CheckBox borderlessCheck = new CheckBox(" Borderless Window", skin); - borderlessCheck.setChecked(brdr && !fscr); - - table.add(fullscreenCheck).colspan(2).row(); - table.add(borderlessCheck).colspan(2).row(); - - CheckBox vsyncCheck = new CheckBox(" VSync", skin); - vsyncCheck.setChecked(SettingsManager.getBoolean(ClientSettings.VSYNC)); - table.add(vsyncCheck).colspan(2).row(); - - CheckBox fpsLimitCheck = new CheckBox(" Limit FPS", skin); - fpsLimitCheck.setChecked(SettingsManager.getBoolean(ClientSettings.FPS_LIMIT_ENABLED)); - - TextField fpsField = new TextField(String.valueOf(SettingsManager.getInt(ClientSettings.FPS_LIMIT)), skin); - fpsField.setTextFieldFilter(new TextField.TextFieldFilter.DigitsOnlyFilter()); - fpsField.setDisabled(!fpsLimitCheck.isChecked()); - - fpsLimitCheck.addListener(new ChangeListener() { - @Override - public void changed(ChangeEvent event, Actor actor) { - fpsField.setDisabled(!fpsLimitCheck.isChecked()); - } - }); + final SelectBox resolutionSelect = !Main.isMobile ? new SelectBox<>(skin) : null; + final CheckBox fullscreenCheck = !Main.isMobile ? new CheckBox(" Fullscreen", skin) : null; + final CheckBox borderlessCheck = !Main.isMobile ? new CheckBox(" Borderless Window", skin) : null; + final CheckBox vsyncCheck = !Main.isMobile ? new CheckBox(" VSync", skin) : null; + final CheckBox fpsLimitCheck = !Main.isMobile ? new CheckBox(" Limit FPS", skin) : null; + final TextField fpsField = !Main.isMobile ? new TextField(String.valueOf(SettingsManager.getInt(ClientSettings.FPS_LIMIT)), skin) : null; + + if (!Main.isMobile) { + table.add(new Label("Resolution:", skin)); + resolutionSelect.setItems("1920x1200", "1920x1080", "1600x900", "1366x768", "1280x720", "800x600"); + resolutionSelect.setSelected(SettingsManager.getString(ClientSettings.RESOLUTION)); + table.add(resolutionSelect).width(200).row(); + + boolean fscr = SettingsManager.getBoolean(ClientSettings.FULLSCREEN); + boolean brdr = SettingsManager.getBoolean(ClientSettings.BORDERLESS); + fullscreenCheck.setChecked(fscr && !brdr); + borderlessCheck.setChecked(brdr && !fscr); + + table.add(fullscreenCheck).colspan(2).row(); + table.add(borderlessCheck).colspan(2).row(); + + vsyncCheck.setChecked(SettingsManager.getBoolean(ClientSettings.VSYNC)); + table.add(vsyncCheck).colspan(2).row(); + + fpsLimitCheck.setChecked(SettingsManager.getBoolean(ClientSettings.FPS_LIMIT_ENABLED)); + fpsField.setTextFieldFilter(new TextField.TextFieldFilter.DigitsOnlyFilter()); + fpsField.setDisabled(!fpsLimitCheck.isChecked()); + + fpsLimitCheck.addListener(new ChangeListener() { + @Override + public void changed(ChangeEvent event, Actor actor) { + fpsField.setDisabled(!fpsLimitCheck.isChecked()); + } + }); - Table fpsTable = new Table(); - fpsTable.add(fpsLimitCheck).padRight(10); - fpsTable.add(fpsField).width(60); - table.add(fpsTable).colspan(2).row(); + Table fpsTable = new Table(); + fpsTable.add(fpsLimitCheck).padRight(10); + fpsTable.add(fpsField).width(60); + table.add(fpsTable).colspan(2).row(); + } table.add(new Label("Brightness:", skin)); Slider brightnessSlider = new Slider(0, 100, 1, false, skin); @@ -212,23 +217,26 @@ public void changed(ChangeEvent event, Actor actor) { applyBtn.addListener(new ClickListener() { @Override public void clicked(InputEvent event, float x, float y) { - SettingsManager.set(ClientSettings.RESOLUTION, resolutionSelect.getSelected()); - SettingsManager.set(ClientSettings.FULLSCREEN, fullscreenCheck.isChecked()); - SettingsManager.set(ClientSettings.BORDERLESS, borderlessCheck.isChecked()); - SettingsManager.set(ClientSettings.VSYNC, vsyncCheck.isChecked()); - SettingsManager.set(ClientSettings.FPS_LIMIT_ENABLED, fpsLimitCheck.isChecked()); - try { - SettingsManager.set(ClientSettings.FPS_LIMIT, Integer.parseInt(fpsField.getText())); - } catch (NumberFormatException ignored) {} - SettingsManager.set(ClientSettings.BRIGHTNESS, brightnessSlider.getValue()); - SettingsManager.saveSettings(); + if (!Main.isMobile) { + SettingsManager.set(ClientSettings.RESOLUTION, resolutionSelect.getSelected()); + SettingsManager.set(ClientSettings.FULLSCREEN, fullscreenCheck.isChecked()); + SettingsManager.set(ClientSettings.BORDERLESS, borderlessCheck.isChecked()); + SettingsManager.set(ClientSettings.VSYNC, vsyncCheck.isChecked()); + SettingsManager.set(ClientSettings.FPS_LIMIT_ENABLED, fpsLimitCheck.isChecked()); + try { + SettingsManager.set(ClientSettings.FPS_LIMIT, Integer.parseInt(fpsField.getText())); + } catch (NumberFormatException ignored) {} + + applyGraphicsSettings(); + } - applyGraphicsSettings(); + SettingsManager.set(ClientSettings.BRIGHTNESS, (double) brightnessSlider.getValue()); + SettingsManager.saveSettings(); + System.out.println("Video settings saved."); } }); table.add(applyBtn).padTop(20).colspan(2).center(); - contentContainer.add(table).top(); } diff --git a/core/src/main/java/xyz/samiker/theendlessweave/systems/RenderSystem.java b/core/src/main/java/xyz/samiker/theendlessweave/systems/RenderSystem.java index f2cbddf..8568a2a 100644 --- a/core/src/main/java/xyz/samiker/theendlessweave/systems/RenderSystem.java +++ b/core/src/main/java/xyz/samiker/theendlessweave/systems/RenderSystem.java @@ -47,7 +47,9 @@ public void update(Array entities, double deltaTime) { ProjectileComponent proj = entity.getComponent(ProjectileComponent.class); if (proj != null && proj.timeAlive < proj.spawnDelay) continue; - if (!camera.frustum.boundsInFrustum((float)pos.x + 25, (float)pos.y + 25, 0, 50, 50, 0)) { + float size = ENTITY_SIZE; + + if (!camera.frustum.boundsInFrustum((float)pos.x + size / 2f, (float)pos.y + size / 2f, 0, size / 2f, size / 2f, 0)) { continue; } diff --git a/server/src/main/java/xyz/samiker/theendlessweave/systems/MovementSystem.java b/server/src/main/java/xyz/samiker/theendlessweave/systems/MovementSystem.java index 6e511b0..ed6a16b 100644 --- a/server/src/main/java/xyz/samiker/theendlessweave/systems/MovementSystem.java +++ b/server/src/main/java/xyz/samiker/theendlessweave/systems/MovementSystem.java @@ -3,17 +3,16 @@ import xyz.samiker.theendlessweave.entities.Entity; import xyz.samiker.theendlessweave.entities.components.*; import xyz.samiker.theendlessweave.gamemap.GameMap; -import xyz.samiker.theendlessweave.systems.ISystem; import xyz.samiker.theendlessweave.tile.Tile; import xyz.samiker.theendlessweave.tile.TileType; import xyz.samiker.theendlessweave.utils.Array; -import static xyz.samiker.theendlessweave.utils.Constants.COLLISION_RADIUS; -import static xyz.samiker.theendlessweave.utils.Constants.TILE_SIZE; +import static xyz.samiker.theendlessweave.utils.Constants.*; public class MovementSystem implements ISystem { private final GameMap gameMap; private static final double ARRIVAL_THRESHOLD = 8.0; + private static final double PROJ_HITBOX_SCALE = 0.8; public MovementSystem(GameMap gameMap) { this.gameMap = gameMap; @@ -30,37 +29,40 @@ public void update(Array entities, double deltaTime) { PositionComponent pos = entity.getComponent(PositionComponent.class); VelocityComponent vel = entity.getComponent(VelocityComponent.class); + double size = entity.hasComponent(ProjectileComponent.class) ? PROJECTILE_SIZE : ENTITY_SIZE; + if (entity.hasComponent(PathfindingComponent.class)) { - handleAIMovement(entity, pos, vel, deltaTime); + handleAIMovement(entity, pos, vel, deltaTime, size); } else { - handleDirectMovement(pos, vel, deltaTime, entity); + handleDirectMovement(pos, vel, deltaTime, entity, size); } } } - private void handleDirectMovement(PositionComponent pos, VelocityComponent vel, double deltaTime, Entity entity) { + private void handleDirectMovement(PositionComponent pos, VelocityComponent vel, double deltaTime, Entity entity, double size) { double deltaX = vel.dx * vel.speed * TILE_SIZE * deltaTime; double deltaY = vel.dy * vel.speed * TILE_SIZE * deltaTime; + boolean isProjectile = entity.hasComponent(ProjectileComponent.class); if (deltaX != 0) { double nextX = pos.x + deltaX; - if (!isCollision(nextX, pos.y, gameMap)) { + if (!checkCollision(entity, nextX, pos.y, size)) { pos.x = nextX; - } else if (entity.hasComponent(ProjectileComponent.class)) { - entity.getComponent(ProjectileComponent.class).shouldDestroy = true; + } else if (isProjectile) { + entity.getComponent(ProjectileComponent.class).shouldDestroy = true; } } if (deltaY != 0) { double nextY = pos.y + deltaY; - if (!isCollision(pos.x, nextY, gameMap)) { + if (!checkCollision(entity, pos.x, nextY, size)) { pos.y = nextY; - } else if (entity.hasComponent(ProjectileComponent.class)) { + } else if (isProjectile) { entity.getComponent(ProjectileComponent.class).shouldDestroy = true; } } } - private void handleAIMovement(Entity entity, PositionComponent pos, VelocityComponent vel, double deltaTime) { + private void handleAIMovement(Entity entity, PositionComponent pos, VelocityComponent vel, double deltaTime, double size) { PathfindingComponent pathfinding = entity.getComponent(PathfindingComponent.class); Tile targetTile = pathfinding.getCurrentTarget(); @@ -123,7 +125,7 @@ private void handleAIMovement(Entity entity, PositionComponent pos, VelocityComp if (deltaX != 0) { double nextX = pos.x + deltaX; - if (!isCollision(nextX, pos.y, gameMap)) { + if (!checkCollision(entity, nextX, pos.y, size)) { pos.x = nextX; } else { pathfinding.clearPath(); @@ -131,7 +133,7 @@ private void handleAIMovement(Entity entity, PositionComponent pos, VelocityComp } if (deltaY != 0) { double nextY = pos.y + deltaY; - if (!isCollision(pos.x, nextY, gameMap)) { + if (!checkCollision(entity, pos.x, nextY, size)) { pos.y = nextY; } else { pathfinding.clearPath(); @@ -144,28 +146,45 @@ private void handleAIMovement(Entity entity, PositionComponent pos, VelocityComp } } - private boolean isCollision(double x, double y, GameMap map) { - double minX = x; - double maxX = x + COLLISION_RADIUS; - double minY = y; - double maxY = y + COLLISION_RADIUS; + private boolean checkCollision(Entity entity, double x, double y, double size) { + double minX, maxX, minY, maxY; + + if (entity.hasComponent(ProjectileComponent.class)) { + double extraReach = size * 0.75; + minX = x - size; + maxX = x + size + extraReach; + minY = y - size; + maxY = y + size + extraReach; + } else { + double padding = size * 0.9; + + minX = x; + maxX = x + padding; + minY = y; + maxY = y + padding; + } + + return isWall(minX, maxX, minY, maxY); + } + + private boolean isWall(double minX, double maxX, double minY, double maxY) { int startTileX = (int) (minX / TILE_SIZE); int endTileX = (int) (maxX / TILE_SIZE); int startTileY = (int) (minY / TILE_SIZE); int endTileY = (int) (maxY / TILE_SIZE); - if (startTileX < 0 || startTileY < 0 || endTileX >= map.getWidth() || endTileY >= map.getHeight()) { + if (startTileX < 0 || startTileY < 0 || endTileX >= gameMap.getWidth() || endTileY >= gameMap.getHeight()) { return true; } + for (int tileX = startTileX; tileX <= endTileX; tileX++) { for (int tileY = startTileY; tileY <= endTileY; tileY++) { - if (map.getTile(tileX, tileY).getType() == TileType.WALL) { + if (gameMap.getTile(tileX, tileY).getType() == TileType.WALL) { return true; } } } - return false; } } \ No newline at end of file