DEADSOFTWARE

Add option for dynamic camera
authorfredboy <fredboy@protonmail.com>
Wed, 8 May 2024 19:47:05 +0000 (02:47 +0700)
committerfredboy <fredboy@protonmail.com>
Wed, 8 May 2024 19:47:05 +0000 (02:47 +0700)
android/assets/json/menu_main_buttons.json
android/assets/json/menu_options_buttons.json [new file with mode: 0644]
core/src/ru/deadsoftware/cavedroid/MainConfig.java
core/src/ru/deadsoftware/cavedroid/game/GameRenderer.java
core/src/ru/deadsoftware/cavedroid/game/input/Joystick.kt
core/src/ru/deadsoftware/cavedroid/menu/MenuProc.java
core/src/ru/deadsoftware/cavedroid/menu/submenus/MenuMain.java
core/src/ru/deadsoftware/cavedroid/menu/submenus/MenuOptions.kt [new file with mode: 0644]
core/src/ru/deadsoftware/cavedroid/menu/submenus/MenusFactory.kt [new file with mode: 0644]

index c52f47ca32db60d012a7b8609b89477d03713a80..97d0938b4bdf4820636d4cf1fdd955b14deafa64 100644 (file)
@@ -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 (file)
index 0000000..ebe1bf7
--- /dev/null
@@ -0,0 +1,8 @@
+{
+  "dyncam": {
+    "label": "Dynamic Camera: %%isUseDynamicCamera%%"
+  },
+  "back": {
+    "label": "Back"
+  }
+}
\ No newline at end of file
index 0219655c9c83f109ec6f862b542517b2ff6d9b50..64950f2d43e17325d3afd348d073c066ae989088 100644 (file)
@@ -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;
+    }
 }
index 423469372609e4c3f53321bf2b00d0f37974519a..302b70586d3b55e0be012b3a380485d8b167848f 100644 (file)
@@ -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<IGameRenderer> 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<IGameRenderer> 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(
index ef4ead15ef574f65f4e0b904bae6ab3e77eb9474..4c04856b61fb84f135871269502c62124d0f2264 100644 (file)
@@ -42,7 +42,6 @@ class Joystick(
         if (!active) {
             return Vector2.Zero
         }
-        println(stickVector)
         return Vector2(
             stickVector.x * value,
             stickVector.y * value
index 6accb5726147700119cb351f1d327d7760df4937..5314809e4d483deb763b266c7158df91487e91a9 100644 (file)
@@ -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
index f71183a0583ce95b4c78fa760cb081e5323188e0..6a40fc534b1a5d04e5fb5d6d80c4ae94b8487777 100644 (file)
@@ -28,6 +28,7 @@ public class MenuMain extends Menu {
         HashMap<String, ButtonEventListener> 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 (file)
index 0000000..2b72bd6
--- /dev/null
@@ -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<String, ButtonEventListener> {
+        val map = HashMap<String, ButtonEventListener>()
+        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 (file)
index 0000000..e31a9ad
--- /dev/null
@@ -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