From 48eae821233a2dc51446a17684464f760bb34b04 Mon Sep 17 00:00:00 2001 From: fredboy Date: Thu, 9 May 2024 02:47:05 +0700 Subject: [PATCH] Add option for dynamic camera --- android/assets/json/menu_main_buttons.json | 3 + android/assets/json/menu_options_buttons.json | 8 ++ .../ru/deadsoftware/cavedroid/MainConfig.java | 10 +++ .../cavedroid/game/GameRenderer.java | 88 +++++++++++++++++-- .../cavedroid/game/input/Joystick.kt | 1 - .../deadsoftware/cavedroid/menu/MenuProc.java | 56 +++++++++--- .../cavedroid/menu/submenus/MenuMain.java | 1 + .../cavedroid/menu/submenus/MenuOptions.kt | 28 ++++++ .../cavedroid/menu/submenus/MenusFactory.kt | 43 +++++++++ 9 files changed, 222 insertions(+), 16 deletions(-) create mode 100644 android/assets/json/menu_options_buttons.json create mode 100644 core/src/ru/deadsoftware/cavedroid/menu/submenus/MenuOptions.kt create mode 100644 core/src/ru/deadsoftware/cavedroid/menu/submenus/MenusFactory.kt diff --git a/android/assets/json/menu_main_buttons.json b/android/assets/json/menu_main_buttons.json index c52f47c..97d0938 100644 --- a/android/assets/json/menu_main_buttons.json +++ b/android/assets/json/menu_main_buttons.json @@ -6,6 +6,9 @@ "label": "Load Game", "type": 0 }, + "options": { + "label": "Settings" + }, "quit": { "label": "Quit" } diff --git a/android/assets/json/menu_options_buttons.json b/android/assets/json/menu_options_buttons.json new file mode 100644 index 0000000..ebe1bf7 --- /dev/null +++ b/android/assets/json/menu_options_buttons.json @@ -0,0 +1,8 @@ +{ + "dyncam": { + "label": "Dynamic Camera: %%isUseDynamicCamera%%" + }, + "back": { + "label": "Back" + } +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/MainConfig.java b/core/src/ru/deadsoftware/cavedroid/MainConfig.java index 0219655..64950f2 100644 --- a/core/src/ru/deadsoftware/cavedroid/MainConfig.java +++ b/core/src/ru/deadsoftware/cavedroid/MainConfig.java @@ -29,6 +29,8 @@ public class MainConfig { private float mWidth; private float mHeight; + private boolean mUseDynamicCamera = true; + @Nullable private String mAssetsPackPath = null; @@ -126,4 +128,12 @@ public class MainConfig { public void setJoystick(@CheckForNull Joystick joystick) { mJoystick = joystick; } + + public boolean isUseDynamicCamera() { + return mUseDynamicCamera; + } + + public void setUseDynamicCamera(boolean useDynamicCamera) { + mUseDynamicCamera = useDynamicCamera; + } } diff --git a/core/src/ru/deadsoftware/cavedroid/game/GameRenderer.java b/core/src/ru/deadsoftware/cavedroid/game/GameRenderer.java index 4234693..302b705 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/GameRenderer.java +++ b/core/src/ru/deadsoftware/cavedroid/game/GameRenderer.java @@ -5,8 +5,7 @@ import com.badlogic.gdx.Input; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.math.Rectangle; -import com.badlogic.gdx.scenes.scene2d.ui.Label; -import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable; +import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.ObjectMap; import ru.deadsoftware.cavedroid.MainConfig; import ru.deadsoftware.cavedroid.game.input.IGameInputHandler; @@ -23,10 +22,11 @@ import ru.deadsoftware.cavedroid.game.objects.TouchButton; import ru.deadsoftware.cavedroid.game.render.IGameRenderer; import ru.deadsoftware.cavedroid.game.ui.TooltipManager; import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager; +import ru.deadsoftware.cavedroid.game.world.GameWorld; import ru.deadsoftware.cavedroid.misc.Assets; import ru.deadsoftware.cavedroid.misc.Renderer; +import ru.deadsoftware.cavedroid.misc.utils.MeasureUnitsUtilsKt; import ru.deadsoftware.cavedroid.misc.utils.RenderingUtilsKt; -import ru.deadsoftware.cavedroid.misc.utils.SpriteUtilsKt; import javax.annotation.CheckForNull; import javax.inject.Inject; @@ -38,11 +38,14 @@ import java.util.Set; @GameScope public class GameRenderer extends Renderer { + private static final float CAMERA_SPEED = 72f; + private static final float MAX_CAM_DISTANCE_FROM_PLAYER = 64f; private static final float DRAG_THRESHOLD = 1f; private static final TouchButton nullButton = new TouchButton(null, -1, true); private final MainConfig mMainConfig; private final MobsController mMobsController; + private final GameWorld mGameWorld; private final List mRenderers; private final CursorMouseInputHandler mCursorMouseInputHandler; private final MouseInputActionMapper mMouseInputActionMapper; @@ -57,6 +60,7 @@ public class GameRenderer extends Renderer { @Inject GameRenderer(MainConfig mainConfig, MobsController mobsController, + GameWorld gameWorld, Set renderers, CursorMouseInputHandler cursorMouseInputHandler, MouseInputActionMapper mouseInputActionMapper, @@ -69,6 +73,7 @@ public class GameRenderer extends Renderer { mMainConfig = mainConfig; mMobsController = mobsController; + mGameWorld = gameWorld; mRenderers = new ArrayList<>(renderers); mRenderers.sort(Comparator.comparingInt(IGameRenderer::getRenderLayer)); mCursorMouseInputHandler = cursorMouseInputHandler; @@ -89,12 +94,79 @@ public class GameRenderer extends Renderer { private float mTouchDownX, mTouchDownY; - private void updateCameraPosition() { + private void updateDynamicCameraPosition(float delta) { Player player = mMobsController.getPlayer(); + + float plTargetX = player.getX() + player.getWidth() / 2; + float plTargetY = player.getY() + player.getHeight() / 2; + + float camTargetX, camTargetY; + + if (player.controlMode == Player.ControlMode.WALK) { + camTargetX = plTargetX + Math.min(player.getVelocity().x * 2, getWidth() / 2); + camTargetY = plTargetY + player.getVelocity().y; + } else { + camTargetX = MeasureUnitsUtilsKt.getPx(player.cursorX) + MeasureUnitsUtilsKt.getPx(1) / 2; + camTargetY = MeasureUnitsUtilsKt.getPx(player.cursorY) + MeasureUnitsUtilsKt.getPx(1) / 2; + } + + float camCenterX = getCamX() + getWidth() / 2; + float camCenterY = getCamY() + getHeight() / 2; + + Vector2 moveVector = new Vector2(camTargetX - camCenterX, camTargetY - camCenterY); + + float camX = getCamX(); + float camY = getCamY(); + float worldWidth = MeasureUnitsUtilsKt.getPx(mGameWorld.getWidth()) - getWidth() / 2; + + if (moveVector.x >= worldWidth) { + camX += mGameWorld.getWidthPx(); + moveVector.x -= mGameWorld.getWidthPx(); + } else if (moveVector.x <= -worldWidth) { + camX -= mGameWorld.getWidthPx(); + moveVector.x += mGameWorld.getWidthPx(); + } + + setCamPos(camX + moveVector.x * delta * 2, camY + moveVector.y * delta * 2); + + + camX = getCamX(); + camY = getCamY(); + + if (camX + getWidth() / 2 > plTargetX + MAX_CAM_DISTANCE_FROM_PLAYER) { + camX = plTargetX + MAX_CAM_DISTANCE_FROM_PLAYER - getWidth() / 2; + } + + if (camY + getHeight() / 2 > plTargetY + MAX_CAM_DISTANCE_FROM_PLAYER) { + camY = plTargetY + MAX_CAM_DISTANCE_FROM_PLAYER - getHeight() / 2; + } + + if (camX + getWidth() / 2 < plTargetX - MAX_CAM_DISTANCE_FROM_PLAYER) { + camX = plTargetX - MAX_CAM_DISTANCE_FROM_PLAYER - getWidth() / 2; + } + + if (camY + getHeight() / 2 < plTargetY - MAX_CAM_DISTANCE_FROM_PLAYER) { + camY = plTargetY - MAX_CAM_DISTANCE_FROM_PLAYER - getHeight() / 2; + } + + setCamPos(camX, camY); + } + + private void updateStaticCameraPosition() { + Player player = mMobsController.getPlayer(); + setCamPos(player.getX() + player.getWidth() / 2 - getWidth() / 2, player.getY() + player.getHeight() / 2 - getHeight() / 2); } + private void updateCameraPosition(float delta) { + if (mMainConfig.isUseDynamicCamera()) { + updateDynamicCameraPosition(delta); + } else { + updateStaticCameraPosition(); + } + } + private float transformScreenX(int screenX) { return getWidth() / Gdx.graphics.getWidth() * screenX; } @@ -153,7 +225,13 @@ public class GameRenderer extends Renderer { float touchX = transformScreenX(screenX); float touchY = transformScreenY(screenY); + final Joystick joy = mMainConfig.getJoystick(); + if (mMainConfig.isTouch()) { + if (joy != null && joy.getActive() && joy.getPointer() == pointer) { + return onMouseActionEvent(screenX, screenY, nullButton.getCode(), true, pointer); + } + TouchButton touchedKey = getTouchedKey(touchX, touchY); if (touchedKey.isMouse()) { return onMouseActionEvent(screenX, screenY, touchedKey.getCode(), true, pointer); @@ -262,7 +340,7 @@ public class GameRenderer extends Renderer { @Override public void render(float delta) { - updateCameraPosition(); + updateCameraPosition(delta); if (mMainConfig.getJoystick() != null && mMainConfig.getJoystick().getActive()) { mMainConfig.getJoystick().updateState( diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/Joystick.kt b/core/src/ru/deadsoftware/cavedroid/game/input/Joystick.kt index ef4ead1..4c04856 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/Joystick.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/Joystick.kt @@ -42,7 +42,6 @@ class Joystick( if (!active) { return Vector2.Zero } - println(stickVector) return Vector2( stickVector.x * value, stickVector.y * value diff --git a/core/src/ru/deadsoftware/cavedroid/menu/MenuProc.java b/core/src/ru/deadsoftware/cavedroid/menu/MenuProc.java index 6accb57..5314809 100644 --- a/core/src/ru/deadsoftware/cavedroid/menu/MenuProc.java +++ b/core/src/ru/deadsoftware/cavedroid/menu/MenuProc.java @@ -5,13 +5,17 @@ import com.badlogic.gdx.utils.ObjectMap; import ru.deadsoftware.cavedroid.CaveGame; import ru.deadsoftware.cavedroid.MainConfig; import ru.deadsoftware.cavedroid.menu.objects.Button; -import ru.deadsoftware.cavedroid.menu.submenus.Menu; -import ru.deadsoftware.cavedroid.menu.submenus.MenuMain; -import ru.deadsoftware.cavedroid.menu.submenus.MenuNewGame; +import ru.deadsoftware.cavedroid.menu.submenus.*; import ru.deadsoftware.cavedroid.misc.Renderer; import javax.inject.Inject; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import static ru.deadsoftware.cavedroid.misc.Assets.*; @MenuScope @@ -30,6 +34,10 @@ public class MenuProc extends Renderer { mMainConfig.getCaveGame().loadGame(); } + public void optionsClicked() { + mCurrentMenu = mMenuOptions; + } + public void quitClicked() { Gdx.app.exit(); } @@ -45,20 +53,24 @@ public class MenuProc extends Renderer { public void backClicked() { mCurrentMenu = mMenuMain; } + + public void toggleDynamicCamera() { + mMainConfig.setUseDynamicCamera(!mMainConfig.isUseDynamicCamera()); + } } private final MainConfig mMainConfig; private final MenuMain mMenuMain; private final MenuNewGame mMenuNewGame; + private final MenuOptions mMenuOptions; private Menu mCurrentMenu; @Inject public MenuProc( MainConfig mainConfig, - MenuMain.Factory menuMainFactory, - MenuNewGame.Factory menuNewGameFactory + MenusFactory menusFactory ) { super(mainConfig.getWidth(), mainConfig.getHeight()); @@ -66,18 +78,42 @@ public class MenuProc extends Renderer { Input menuInput = new Input(); - mMenuMain = menuMainFactory.get(getWidth(), getHeight(), this::drawButton, menuInput); - mMenuNewGame = menuNewGameFactory.get(getWidth(), getHeight(), this::drawButton, menuInput); + mMenuMain = menusFactory.getMainMenu(getWidth(), getHeight(), this::drawButton, menuInput); + mMenuNewGame = menusFactory.getMenuNewGame(getWidth(), getHeight(), this::drawButton, menuInput); + mMenuOptions = menusFactory.getMenuOptions(getWidth(), getHeight(), this::drawButton, menuInput); mCurrentMenu = mMenuMain; } + private String processVariables(String raw) { + final Pattern pattern = Pattern.compile("%%([A-Za-z]+)%%", Pattern.CASE_INSENSITIVE); + final Matcher matcher = pattern.matcher(raw); + while (matcher.find()) { + for (int i = 0; i < matcher.groupCount(); i++) { + try { + final String group = matcher.group(i); + final String name = group.replaceAll("%%", ""); + final Method method = mMainConfig.getClass().getMethod(name); + final String value = method.invoke(mMainConfig).toString(); + raw = raw.replace(group, value); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + + return raw; + } + private void drawButton(Button button) { spriter.draw(textureRegions.get("button_" + button.getType()), button.getX(), button.getY()); setFontColor(255, 255, 255); - drawString(button.getLabel(), - (button.getX() + button.getWidth() / 2) - (float) getStringWidth(button.getLabel()) / 2, - (button.getY() + button.getHeight() / 2) - (float) getStringHeight(button.getLabel()) / 2); + + String label = processVariables(button.getLabel()); + + drawString(label, + (button.getX() + button.getWidth() / 2) - (float) getStringWidth(label) / 2, + (button.getY() + button.getHeight() / 2) - (float) getStringHeight(label) / 2); } @Override diff --git a/core/src/ru/deadsoftware/cavedroid/menu/submenus/MenuMain.java b/core/src/ru/deadsoftware/cavedroid/menu/submenus/MenuMain.java index f71183a..6a40fc5 100644 --- a/core/src/ru/deadsoftware/cavedroid/menu/submenus/MenuMain.java +++ b/core/src/ru/deadsoftware/cavedroid/menu/submenus/MenuMain.java @@ -28,6 +28,7 @@ public class MenuMain extends Menu { HashMap map = new HashMap<>(); map.put("new_game", mMenuInput::newGameClicked); map.put("load_game", mMenuInput::loadGameClicked); + map.put("options", mMenuInput::optionsClicked); map.put("quit", mMenuInput::quitClicked); return map; } diff --git a/core/src/ru/deadsoftware/cavedroid/menu/submenus/MenuOptions.kt b/core/src/ru/deadsoftware/cavedroid/menu/submenus/MenuOptions.kt new file mode 100644 index 0000000..2b72bd6 --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/menu/submenus/MenuOptions.kt @@ -0,0 +1,28 @@ +package ru.deadsoftware.cavedroid.menu.submenus + +import ru.deadsoftware.cavedroid.MainConfig +import ru.deadsoftware.cavedroid.menu.MenuProc +import ru.deadsoftware.cavedroid.menu.objects.ButtonEventListener +import ru.deadsoftware.cavedroid.menu.objects.ButtonRenderer +import ru.deadsoftware.cavedroid.misc.utils.AssetLoader + +class MenuOptions( + width: Float, + height: Float, + buttonRenderer: ButtonRenderer, + mainConfig: MainConfig, + menuInput: MenuProc.Input, + assetLoader: AssetLoader, +) : Menu(width, height, buttonRenderer, mainConfig, menuInput, assetLoader) { + + override fun getButtonEventListeners(): HashMap { + val map = HashMap() + map["dyncam"] = ButtonEventListener { mMenuInput.toggleDynamicCamera() } + map["back"] = ButtonEventListener { mMenuInput.backClicked() } + return map + } + + override fun initButtons() { + loadButtonsFromJson(mAssetLoader.getAssetHandle("json/menu_options_buttons.json")) + } +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/menu/submenus/MenusFactory.kt b/core/src/ru/deadsoftware/cavedroid/menu/submenus/MenusFactory.kt new file mode 100644 index 0000000..e31a9ad --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/menu/submenus/MenusFactory.kt @@ -0,0 +1,43 @@ +package ru.deadsoftware.cavedroid.menu.submenus + +import ru.deadsoftware.cavedroid.MainConfig +import ru.deadsoftware.cavedroid.menu.MenuProc +import ru.deadsoftware.cavedroid.menu.MenuScope +import ru.deadsoftware.cavedroid.menu.objects.ButtonRenderer +import ru.deadsoftware.cavedroid.misc.utils.AssetLoader +import javax.inject.Inject + +@MenuScope +class MenusFactory @Inject constructor( + private val mainConfig: MainConfig, + private val assetLoader: AssetLoader, +) { + + fun getMainMenu( + width: Float, + height: Float, + buttonRenderer: ButtonRenderer, + menuInput: MenuProc.Input, + ): MenuMain { + return MenuMain(width, height, buttonRenderer, mainConfig, menuInput, assetLoader) + } + + fun getMenuNewGame( + width: Float, + height: Float, + buttonRenderer: ButtonRenderer, + menuInput: MenuProc.Input, + ): MenuNewGame { + return MenuNewGame(width, height, buttonRenderer, mainConfig, menuInput, assetLoader) + } + + fun getMenuOptions( + width: Float, + height: Float, + buttonRenderer: ButtonRenderer, + menuInput: MenuProc.Input, + ): MenuOptions { + return MenuOptions(width, height, buttonRenderer, mainConfig, menuInput, assetLoader) + } + +} \ No newline at end of file -- 2.29.2