From: fredboy Date: Wed, 8 May 2024 17:28:16 +0000 (+0700) Subject: Add joystick touch controls X-Git-Tag: alpha0.8.0~6 X-Git-Url: http://deadsoftware.ru/gitweb?a=commitdiff_plain;h=6b49d51c59f6d639d949d1e9c264f7f144a305ab;p=cavedroid.git Add joystick touch controls --- diff --git a/android/assets/joy_background.png b/android/assets/joy_background.png new file mode 100644 index 0000000..b1ea80b Binary files /dev/null and b/android/assets/joy_background.png differ diff --git a/android/assets/joy_stick.png b/android/assets/joy_stick.png new file mode 100644 index 0000000..0d75f67 Binary files /dev/null and b/android/assets/joy_stick.png differ diff --git a/android/assets/json/touch_buttons.json b/android/assets/json/touch_buttons.json index cddaf53..4d83301 100644 --- a/android/assets/json/touch_buttons.json +++ b/android/assets/json/touch_buttons.json @@ -1,53 +1,9 @@ { - "up": { - "x": 26, - "y": -52, - "w": 26, - "h": 26, - "key": "W" - }, - "down": { - "x": 26, - "y": -26, - "w": 26, - "h": 26, - "key": "S" - }, - "left": { - "x": 0, - "y": -26, - "w": 26, - "h": 26, - "key": "A" - }, - "right": { - "x": 52, - "y": -26, - "w": 26, - "h": 26, - "key": "D" - }, "alt": { - "x": 78, - "y": -26, - "w": 26, - "h": 26, + "x": -32, + "y": -32, + "w": 32, + "h": 32, "key": "L-Alt" - }, - "lmb": { - "x": -52, - "y": -26, - "w": 26, - "h": 26, - "mouse": true, - "key": "Left" - }, - "rmb": { - "x": -26, - "y": -26, - "w": 26, - "h": 26, - "mouse": true, - "key": "Right" } } \ 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 6577f29..0219655 100644 --- a/core/src/ru/deadsoftware/cavedroid/MainConfig.java +++ b/core/src/ru/deadsoftware/cavedroid/MainConfig.java @@ -1,6 +1,7 @@ package ru.deadsoftware.cavedroid; import ru.deadsoftware.cavedroid.game.GameUiWindow; +import ru.deadsoftware.cavedroid.game.input.Joystick; import javax.annotation.CheckForNull; import javax.annotation.Nullable; @@ -15,6 +16,9 @@ public class MainConfig { @CheckForNull private MainComponent mMainComponent; + @CheckForNull + private Joystick mJoystick; + private GameUiWindow mGameUiWindow; private String mGameFolder; @@ -113,4 +117,13 @@ public class MainConfig { public void setAssetsPackPath(@Nullable String assetsPackPath) { mAssetsPackPath = assetsPackPath; } + + @CheckForNull + public Joystick getJoystick() { + return mJoystick; + } + + public void setJoystick(@CheckForNull Joystick joystick) { + mJoystick = joystick; + } } diff --git a/core/src/ru/deadsoftware/cavedroid/game/GameRenderer.java b/core/src/ru/deadsoftware/cavedroid/game/GameRenderer.java index 4b418a7..4234693 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/GameRenderer.java +++ b/core/src/ru/deadsoftware/cavedroid/game/GameRenderer.java @@ -1,15 +1,16 @@ package ru.deadsoftware.cavedroid.game; import com.badlogic.gdx.Gdx; +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.utils.Align; import com.badlogic.gdx.utils.ObjectMap; import ru.deadsoftware.cavedroid.MainConfig; import ru.deadsoftware.cavedroid.game.input.IGameInputHandler; +import ru.deadsoftware.cavedroid.game.input.Joystick; import ru.deadsoftware.cavedroid.game.input.action.KeyboardInputAction; import ru.deadsoftware.cavedroid.game.input.action.MouseInputAction; import ru.deadsoftware.cavedroid.game.input.action.keys.MouseInputActionKey; @@ -24,6 +25,8 @@ import ru.deadsoftware.cavedroid.game.ui.TooltipManager; import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager; import ru.deadsoftware.cavedroid.misc.Assets; import ru.deadsoftware.cavedroid.misc.Renderer; +import ru.deadsoftware.cavedroid.misc.utils.RenderingUtilsKt; +import ru.deadsoftware.cavedroid.misc.utils.SpriteUtilsKt; import javax.annotation.CheckForNull; import javax.inject.Inject; @@ -35,6 +38,7 @@ import java.util.Set; @GameScope public class GameRenderer extends Renderer { + private static final float DRAG_THRESHOLD = 1f; private static final TouchButton nullButton = new TouchButton(null, -1, true); private final MainConfig mMainConfig; @@ -48,6 +52,8 @@ public class GameRenderer extends Renderer { private final GameWindowsManager mGameWindowsManager; private final TooltipManager mTooltipManager; + private final TouchButton mouseLeftTouchButton, mouseRightTouchButton; + @Inject GameRenderer(MainConfig mainConfig, MobsController mobsController, @@ -73,6 +79,11 @@ public class GameRenderer extends Renderer { mGameWindowsManager = gameWindowsManager; mTooltipManager = tooltipManager; + mouseLeftTouchButton = new TouchButton(new Rectangle(getWidth() / 2, 0f, getWidth() / 2, getHeight() / 2), Input.Buttons.LEFT, true); + mouseRightTouchButton = new TouchButton(new Rectangle(getWidth() / 2, getHeight() / 2, getWidth() / 2, getHeight() / 2), Input.Buttons.RIGHT, true); + + mMainConfig.setJoystick(new Joystick(mMobsController.getPlayer().getSpeed())); + Gdx.gl.glClearColor(0f, .6f, .6f, 1f); } @@ -107,14 +118,8 @@ public class GameRenderer extends Renderer { mCursorMouseInputHandler.handle(action); if (!mTooltipManager.getCurrentMouseTooltip().isEmpty()) { - final Label.LabelStyle style = new Label.LabelStyle(Assets.minecraftFont, Color.WHITE); - style.background = new TextureRegionDrawable(Assets.textureRegions.get("background")); - final Label label = new Label(mTooltipManager.getCurrentMouseTooltip(), style); - label.setX(screenX); - label.setY(screenY); -// label.setHeight(10f); -// label.setAlignment(Align.left, Align.top); - label.draw(spriter, 1f); + RenderingUtilsKt.drawString(spriter, mTooltipManager.getCurrentMouseTooltip(), screenX + 1, screenY + 1, Color.BLACK); + RenderingUtilsKt.drawString(spriter, mTooltipManager.getCurrentMouseTooltip(), screenX, screenY, Color.WHITE); } } @@ -137,9 +142,9 @@ public class GameRenderer extends Renderer { return anyProcessed; } - private boolean onMouseActionEvent(int mouseX, int mouseY, int button, boolean touchUp) { + private boolean onMouseActionEvent(int mouseX, int mouseY, int button, boolean touchUp, int pointer) { @CheckForNull MouseInputAction action = mMouseInputActionMapper - .map((float) mouseX, (float) mouseY, getCameraViewport(), button, touchUp); + .map((float) mouseX, (float) mouseY, getCameraViewport(), button, touchUp, pointer); return handleMouseAction(action); } @@ -151,13 +156,13 @@ public class GameRenderer extends Renderer { if (mMainConfig.isTouch()) { TouchButton touchedKey = getTouchedKey(touchX, touchY); if (touchedKey.isMouse()) { - return onMouseActionEvent(screenX, screenY, touchedKey.getCode(), true); + return onMouseActionEvent(screenX, screenY, touchedKey.getCode(), true, pointer); } else { return keyUp(touchedKey.getCode()); } } - return onMouseActionEvent(screenX, screenY, button, true); + return onMouseActionEvent(screenX, screenY, button, true, pointer); } private TouchButton getTouchedKey(float touchX, float touchY) { @@ -170,6 +175,15 @@ public class GameRenderer extends Renderer { return button; } } + + if (mouseLeftTouchButton.getRect().contains(touchX, touchY)) { + return mouseLeftTouchButton; + } + + if (mouseRightTouchButton.getRect().contains(touchX, touchY)) { + return mouseRightTouchButton; + } + return nullButton; } @@ -184,13 +198,13 @@ public class GameRenderer extends Renderer { if (mMainConfig.isTouch()) { TouchButton touchedKey = getTouchedKey(touchX, touchY); if (touchedKey.isMouse()) { - return onMouseActionEvent(screenX, screenY, touchedKey.getCode(), false); + return onMouseActionEvent(screenX, screenY, touchedKey.getCode(), false, pointer); } else { return keyDown(touchedKey.getCode()); } } - return onMouseActionEvent(screenX, screenY, button, false); + return onMouseActionEvent(screenX, screenY, button, false, pointer); } @Override @@ -198,12 +212,12 @@ public class GameRenderer extends Renderer { float touchX = transformScreenX(screenX); float touchY = transformScreenY(screenY); - if (Math.abs(touchX - mTouchDownX) < 16 && Math.abs(touchY - mTouchDownY) < 16) { + if (Math.abs(touchX - mTouchDownX) < 16 && Math.abs(touchY - mTouchDownY) < DRAG_THRESHOLD) { return false; } @CheckForNull MouseInputAction action = - mMouseInputActionMapper.mapDragged(screenX, screenY, getCameraViewport()); + mMouseInputActionMapper.mapDragged(screenX, screenY, getCameraViewport(), pointer); return handleMouseAction(action); } @@ -250,6 +264,13 @@ public class GameRenderer extends Renderer { public void render(float delta) { updateCameraPosition(); + if (mMainConfig.getJoystick() != null && mMainConfig.getJoystick().getActive()) { + mMainConfig.getJoystick().updateState( + transformScreenX(Gdx.input.getX(mMainConfig.getJoystick().getPointer())), + transformScreenY(Gdx.input.getY(mMainConfig.getJoystick().getPointer())) + ); + } + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); spriter.begin(); diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/Joystick.kt b/core/src/ru/deadsoftware/cavedroid/game/input/Joystick.kt new file mode 100644 index 0000000..ef4ead1 --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/input/Joystick.kt @@ -0,0 +1,74 @@ +package ru.deadsoftware.cavedroid.game.input + +import com.badlogic.gdx.math.Vector2 +import com.badlogic.gdx.utils.TimeUtils + +class Joystick( + private val value: Float, +) { + + var active = false + private set + var centerX = 0f + private set + var centerY = 0f + private set + + var activeX = 0f + private set + var activeY = 0f + private set + + var pointer = 0 + private set + + private val stickVector = Vector2() + + private var activateTimeMs = 0L + + fun activate(touchX: Float, touchY: Float, pointer: Int) { + active = true + centerX = touchX + centerY = touchY + activateTimeMs = TimeUtils.millis() + this.pointer = pointer + } + + fun deactivate() { + active = false + } + + fun getVelocityVector(): Vector2 { + if (!active) { + return Vector2.Zero + } + println(stickVector) + return Vector2( + stickVector.x * value, + stickVector.y * value + ) + } + + fun updateState(touchX: Float, touchY: Float) { + if (!active) { + return + } + + stickVector.x = touchX - centerX + stickVector.y = touchY - centerY + stickVector.clamp(0f, RADIUS) + + activeX = centerX + stickVector.x + activeY = centerY + stickVector.y + + stickVector.x /= RADIUS + stickVector.y /= RADIUS + } + + companion object { + const val RADIUS = 24f + const val SIZE = RADIUS * 2 + const val STICK_SIZE = 16f + } + +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/MouseInputHandlersModule.kt b/core/src/ru/deadsoftware/cavedroid/game/input/MouseInputHandlersModule.kt index 937b3e6..3d5f32a 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/MouseInputHandlersModule.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/MouseInputHandlersModule.kt @@ -5,6 +5,7 @@ import dagger.Module import dagger.multibindings.IntoSet import ru.deadsoftware.cavedroid.game.GameScope import ru.deadsoftware.cavedroid.game.input.action.MouseInputAction +import ru.deadsoftware.cavedroid.game.input.handler.touch.JoystickInputHandler import ru.deadsoftware.cavedroid.game.input.handler.mouse.* @Module @@ -72,4 +73,11 @@ object MouseInputHandlersModule { fun bindSelectCraftingInventoryItemMouseInputHandler(handler: SelectCraftingInventoryItemMouseInputHandler): IGameInputHandler { return handler } + + @Binds + @IntoSet + @GameScope + fun bindJoystickInputHandler(handler: JoystickInputHandler): IGameInputHandler { + return handler + } } \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/action/keys/MouseInputActionKey.kt b/core/src/ru/deadsoftware/cavedroid/game/input/action/keys/MouseInputActionKey.kt index 5822760..3b2744f 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/action/keys/MouseInputActionKey.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/action/keys/MouseInputActionKey.kt @@ -4,12 +4,18 @@ sealed interface MouseInputActionKey { val touchUp: Boolean + sealed interface Touch : MouseInputActionKey { + val pointer: Int + } + data object None : MouseInputActionKey { override val touchUp: Boolean get() = throw IllegalAccessException("not applicable for mouse move action") } - data object Dragged : MouseInputActionKey { + data class Dragged( + override val pointer: Int + ) : Touch { override val touchUp: Boolean get() = throw IllegalAccessException("not applicable for mouse dragged action") } @@ -26,9 +32,10 @@ sealed interface MouseInputActionKey { override val touchUp: Boolean ) : MouseInputActionKey - data class Touch( - override val touchUp: Boolean - ) : MouseInputActionKey + data class Screen( + override val touchUp: Boolean, + override val pointer: Int, + ) : Touch data class Scroll( val amountX: Float, diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/MoveCursorControlsModeKeyboardInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/MoveCursorControlsModeKeyboardInputHandler.kt index e6d0053..0cb74d7 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/MoveCursorControlsModeKeyboardInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/MoveCursorControlsModeKeyboardInputHandler.kt @@ -1,6 +1,5 @@ package ru.deadsoftware.cavedroid.game.input.handler.keyboard -import com.badlogic.gdx.math.MathUtils import ru.deadsoftware.cavedroid.MainConfig import ru.deadsoftware.cavedroid.game.GameScope import ru.deadsoftware.cavedroid.game.input.IGameInputHandler @@ -27,21 +26,6 @@ class MoveCursorControlsModeKeyboardInputHandler @Inject constructor( action.actionKey is KeyboardInputActionKey.Down) } - private fun checkCursorBounds() { - val player = mobsController.player - if (player.gameMode == 0) { - val minCursorX = player.mapX - SURVIVAL_CURSOR_RANGE - val maxCursorX = player.mapX + SURVIVAL_CURSOR_RANGE - val minCursorY = player.middleMapY - SURVIVAL_CURSOR_RANGE - val maxCursorY = player.middleMapY + SURVIVAL_CURSOR_RANGE - - player.cursorX = MathUtils.clamp(player.cursorX, minCursorX, maxCursorX) - player.cursorY = MathUtils.clamp(player.cursorY, minCursorY, maxCursorY) - } - - player.cursorY = MathUtils.clamp(player.cursorY, 0, gameWorld.height - 1) - } - override fun handle(action: KeyboardInputAction) { val player = mobsController.player @@ -53,7 +37,7 @@ class MoveCursorControlsModeKeyboardInputHandler @Inject constructor( else -> return } - checkCursorBounds() + player.checkCursorBounds(gameWorld); } companion object { diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/CloseGameWindowMouseInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/CloseGameWindowMouseInputHandler.kt index bee22dc..8a7fdb4 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/CloseGameWindowMouseInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/CloseGameWindowMouseInputHandler.kt @@ -26,7 +26,7 @@ class CloseGameWindowMouseInputHandler @Inject constructor( override fun checkConditions(action: MouseInputAction): Boolean { return gameWindowsManager.getCurrentWindow() != GameUiWindow.NONE && - (action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Touch) && + (action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Screen) && !action.actionKey.touchUp && !isInsideWindow(action, getCurrentWindowTexture()) } diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/CreativeInventoryScrollMouseInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/CreativeInventoryScrollMouseInputHandler.kt index 352d04b..11f76e9 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/CreativeInventoryScrollMouseInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/CreativeInventoryScrollMouseInputHandler.kt @@ -34,12 +34,12 @@ class CreativeInventoryScrollMouseInputHandler @Inject constructor( } private fun checkStartDragConditions(action: MouseInputAction): Boolean { - return (action.actionKey is MouseInputActionKey.Touch) && + return (action.actionKey is MouseInputActionKey.Screen) && !action.actionKey.touchUp && !gameWindowsManager.isDragging } private fun checkEndDragConditions(action: MouseInputAction): Boolean { - return action.actionKey is MouseInputActionKey.Touch && + return action.actionKey is MouseInputActionKey.Screen && action.actionKey.touchUp && gameWindowsManager.isDragging } @@ -75,7 +75,7 @@ class CreativeInventoryScrollMouseInputHandler @Inject constructor( override fun handle(action: MouseInputAction) { when (action.actionKey) { - is MouseInputActionKey.Touch -> handleStartOrEndDrag(action) + is MouseInputActionKey.Screen -> handleStartOrEndDrag(action) is MouseInputActionKey.Dragged -> handleDrag(action) is MouseInputActionKey.Scroll -> handleScroll(action) else -> return diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/CursorMouseInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/CursorMouseInputHandler.kt index 6a4b5a4..9093680 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/CursorMouseInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/CursorMouseInputHandler.kt @@ -41,20 +41,6 @@ class CursorMouseInputHandler @Inject constructor( private fun GameWorld.isCurrentBlockAutoselectable() = getForeMap(player.cursorX, player.cursorY).isAutoselectable - private fun checkCursorBounds() { - if (player.gameMode == 0) { - val minCursorX = player.mapX - SURVIVAL_CURSOR_RANGE - val maxCursorX = player.mapX + SURVIVAL_CURSOR_RANGE - val minCursorY = player.middleMapY - SURVIVAL_CURSOR_RANGE - val maxCursorY = player.middleMapY + SURVIVAL_CURSOR_RANGE - - player.cursorX = MathUtils.clamp(player.cursorX, minCursorX, maxCursorX) - player.cursorY = MathUtils.clamp(player.cursorY, minCursorY, maxCursorY) - } - - player.cursorY = MathUtils.clamp(player.cursorY, 0, gameWorld.height - 1) - } - private fun setPlayerDirectionToCursor() { if (player.controlMode != Player.ControlMode.CURSOR) { return @@ -137,7 +123,7 @@ class CursorMouseInputHandler @Inject constructor( !mainConfig.isTouch -> handleMouse(action) } - checkCursorBounds() + player.checkCursorBounds(gameWorld) setPlayerDirectionToCursor() if (player.cursorX != pastCursorX || player.cursorY != pastCursorY) { diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/HotbarMouseInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/HotbarMouseInputHandler.kt index 0725abe..92f6a5a 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/HotbarMouseInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/HotbarMouseInputHandler.kt @@ -25,7 +25,7 @@ class HotbarMouseInputHandler @Inject constructor( override fun checkConditions(action: MouseInputAction): Boolean { return buttonHoldTask?.isScheduled == true || - ((action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Touch) + ((action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Screen) && isInsideHotbar(action) || action.actionKey is MouseInputActionKey.Scroll) && gameWindowsManager.getCurrentWindow() == GameUiWindow.NONE @@ -75,7 +75,7 @@ class HotbarMouseInputHandler @Inject constructor( cancelHold() } - if (action.actionKey !is MouseInputActionKey.Left && action.actionKey !is MouseInputActionKey.Touch ) { + if (action.actionKey !is MouseInputActionKey.Left && action.actionKey !is MouseInputActionKey.Screen ) { if (action.actionKey is MouseInputActionKey.Scroll) { handleScroll(action) } diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectCraftingInventoryItemMouseInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectCraftingInventoryItemMouseInputHandler.kt index 89c0ce1..4898150 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectCraftingInventoryItemMouseInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectCraftingInventoryItemMouseInputHandler.kt @@ -28,7 +28,7 @@ class SelectCraftingInventoryItemMouseInputHandler @Inject constructor( override fun checkConditions(action: MouseInputAction): Boolean { return gameWindowsManager.getCurrentWindow() == GameUiWindow.CRAFTING_TABLE && isInsideWindow(action, survivalWindowTexture) && - (action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Right || action.actionKey is MouseInputActionKey.Touch) + (action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Right || action.actionKey is MouseInputActionKey.Screen) && action.actionKey.touchUp } @@ -73,7 +73,7 @@ class SelectCraftingInventoryItemMouseInputHandler @Inject constructor( itemIndex -= 36 } - if (action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Touch) { + if (action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Screen) { onLeftCLick(mobsController.player.inventory.items as MutableList, window, itemIndex) } else { onRightClick(mobsController.player.inventory.items as MutableList, window, itemIndex) @@ -89,7 +89,7 @@ class SelectCraftingInventoryItemMouseInputHandler @Inject constructor( val window = gameWindowsManager.currentWindow as CraftingInventoryWindow val index = xOnCraft + yOnCraft * GameWindowsConfigs.Crafting.craftGridSize - if (action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Touch) { + if (action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Screen) { onLeftCLick(window.craftingItems, window, index) } else { onRightClick(window.craftingItems, window, index) diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectCreativeInventoryItemMouseInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectCreativeInventoryItemMouseInputHandler.kt index 9ccbf6e..272a178 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectCreativeInventoryItemMouseInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectCreativeInventoryItemMouseInputHandler.kt @@ -25,7 +25,7 @@ class SelectCreativeInventoryItemMouseInputHandler @Inject constructor( override fun checkConditions(action: MouseInputAction): Boolean { return gameWindowsManager.getCurrentWindow() == GameUiWindow.CREATIVE_INVENTORY && !gameWindowsManager.isDragging && - (action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Touch) && + (action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Screen) && action.actionKey.touchUp && isInsideWindow(action, creativeInventoryTexture) } diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectSurvivalInventoryItemMouseInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectSurvivalInventoryItemMouseInputHandler.kt index ab65fb8..0d0a647 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectSurvivalInventoryItemMouseInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectSurvivalInventoryItemMouseInputHandler.kt @@ -28,7 +28,7 @@ class SelectSurvivalInventoryItemMouseInputHandler @Inject constructor( override fun checkConditions(action: MouseInputAction): Boolean { return gameWindowsManager.getCurrentWindow() == GameUiWindow.SURVIVAL_INVENTORY && isInsideWindow(action, survivalWindowTexture) && - (action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Right || action.actionKey is MouseInputActionKey.Touch) + (action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Right || action.actionKey is MouseInputActionKey.Screen) && action.actionKey.touchUp } @@ -73,7 +73,7 @@ class SelectSurvivalInventoryItemMouseInputHandler @Inject constructor( itemIndex -= 36 } - if (action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Touch) { + if (action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Screen) { onLeftCLick(mobsController.player.inventory.items as MutableList, window, itemIndex) } else { onRightClick(mobsController.player.inventory.items as MutableList, window, itemIndex) @@ -89,7 +89,7 @@ class SelectSurvivalInventoryItemMouseInputHandler @Inject constructor( val window = gameWindowsManager.currentWindow as SurvivalInventoryWindow val index = xOnCraft + yOnCraft * GameWindowsConfigs.Crafting.craftGridSize // this is crafting on purpose!! - if (action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Touch) { + if (action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Screen) { onLeftCLick(window.craftingItems, window, index) } else { onRightClick(window.craftingItems, window, index) diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/touch/JoystickInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/touch/JoystickInputHandler.kt new file mode 100644 index 0000000..c175f31 --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/touch/JoystickInputHandler.kt @@ -0,0 +1,134 @@ +package ru.deadsoftware.cavedroid.game.input.handler.touch + +import com.badlogic.gdx.math.Vector2 +import com.badlogic.gdx.utils.TimeUtils +import ru.deadsoftware.cavedroid.MainConfig +import ru.deadsoftware.cavedroid.game.GameScope +import ru.deadsoftware.cavedroid.game.GameUiWindow +import ru.deadsoftware.cavedroid.game.input.IGameInputHandler +import ru.deadsoftware.cavedroid.game.input.Joystick +import ru.deadsoftware.cavedroid.game.input.action.MouseInputAction +import ru.deadsoftware.cavedroid.game.input.action.keys.MouseInputActionKey +import ru.deadsoftware.cavedroid.game.input.isInsideHotbar +import ru.deadsoftware.cavedroid.game.mobs.Mob +import ru.deadsoftware.cavedroid.game.mobs.MobsController +import ru.deadsoftware.cavedroid.game.mobs.player.Player +import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager +import ru.deadsoftware.cavedroid.game.world.GameWorld +import javax.inject.Inject + +@GameScope +class JoystickInputHandler @Inject constructor( + private val mainConfig: MainConfig, + private val mobsController: MobsController, + private val gameWindowsManager: GameWindowsManager, + private val gameWorld: GameWorld, +) : IGameInputHandler { + + private var activateTimeMs = 0L + private var cursorTimeoutMs = 100L + + private var active = false + set(value) { + if (!value) { + resetVelocity() + if (TimeUtils.timeSinceMillis(activateTimeMs) < 100L && + mobsController.player.controlMode != Player.ControlMode.CURSOR) { + mobsController.player.jump() + } + } else { + activateTimeMs = TimeUtils.millis() + } + field = value + } + + private fun resetVelocity() { + mobsController.player.velocity.x = 0f + + if (mobsController.player.isFlyMode) { + mobsController.player.velocity.y = 0f + } + } + + override fun checkConditions(action: MouseInputAction): Boolean { + return gameWindowsManager.getCurrentWindow() == GameUiWindow.NONE && + mainConfig.isTouch && +// mobsController.player.controlMode == Player.ControlMode.WALK && + mainConfig.joystick != null && + (action.actionKey is MouseInputActionKey.Touch) && + (action.actionKey.pointer == mainConfig.joystick?.pointer || !active) && + ((action.actionKey is MouseInputActionKey.Dragged) || + (action.screenX < action.cameraViewport.width / 2 && !action.actionKey.touchUp || active)) && + !(action.actionKey is MouseInputActionKey.Screen && isInsideHotbar(action)) + + } + + private fun handleTouchDown(action: MouseInputAction) { + val key = action.actionKey as MouseInputActionKey.Screen + mainConfig.joystick?.activate(action.screenX, action.screenY, key.pointer) ?: return + active = true + } + + private fun handleTouchUp(action: MouseInputAction) { + mainConfig.joystick?.deactivate() + active = false + } + + private fun handleCursor() { + val joystick = mainConfig.joystick ?: return + + if (TimeUtils.timeSinceMillis(cursorTimeoutMs) < 200L) { + return + } + + if (Math.abs(joystick.activeX - joystick.centerX) >= Joystick.RADIUS / 2) { + mobsController.player.cursorX += if (joystick.activeX > joystick.centerX) 1 else -1 + cursorTimeoutMs = TimeUtils.millis() + } + + if (Math.abs(joystick.activeY - joystick.centerY) >= Joystick.RADIUS / 2) { + mobsController.player.cursorY += if (joystick.activeY > joystick.centerY) 1 else -1 + cursorTimeoutMs = TimeUtils.millis() + } + + mobsController.player.checkCursorBounds(gameWorld) + } + + private fun handleDragged() { + if (mobsController.player.controlMode == Player.ControlMode.CURSOR) { + handleCursor() + return + } + + val joystick = mainConfig.joystick ?: return + val joyVector = joystick.getVelocityVector() + + mobsController.player.velocity.x = joyVector.x + + mobsController.player.setDir( + if (joyVector.x < 0) { + Mob.Direction.LEFT + } else { + Mob.Direction.RIGHT + } + ) + + if (mobsController.player.isFlyMode) { + mobsController.player.velocity.y = joyVector.y + } + } + + override fun handle(action: MouseInputAction) { + when (action.actionKey) { + is MouseInputActionKey.Dragged -> handleDragged() + else -> { + if (action.actionKey.touchUp) { + handleTouchUp(action) + } else { + handleTouchDown(action) + } + } + } + } + +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/mapper/MouseInputActionMapper.kt b/core/src/ru/deadsoftware/cavedroid/game/input/mapper/MouseInputActionMapper.kt index 254cee2..5ef450a 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/mapper/MouseInputActionMapper.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/mapper/MouseInputActionMapper.kt @@ -19,9 +19,10 @@ class MouseInputActionMapper @Inject constructor( mouseY: Float, cameraViewport: Rectangle, button: Int, - touchUp: Boolean + touchUp: Boolean, + pointer: Int, ): MouseInputAction? { - val actionKey = mapActionKey(button, touchUp) ?: return null + val actionKey = mapActionKey(button, touchUp, pointer) ?: return null return MouseInputAction( screenX = getScreenX(mouseX), @@ -35,11 +36,12 @@ class MouseInputActionMapper @Inject constructor( mouseX: Float, mouseY: Float, cameraViewport: Rectangle, + pointer: Int, ): MouseInputAction { return MouseInputAction( screenX = getScreenX(mouseX), screenY = getScreenY(mouseY), - actionKey = MouseInputActionKey.Dragged, + actionKey = MouseInputActionKey.Dragged(pointer), cameraViewport = cameraViewport, ) } @@ -59,12 +61,12 @@ class MouseInputActionMapper @Inject constructor( ) } - private fun mapActionKey(button: Int, touchUp: Boolean): MouseInputActionKey? { + private fun mapActionKey(button: Int, touchUp: Boolean, pointer: Int): MouseInputActionKey? { return when (button) { Input.Buttons.LEFT -> MouseInputActionKey.Left(touchUp) Input.Buttons.RIGHT -> MouseInputActionKey.Right(touchUp) Input.Buttons.MIDDLE -> MouseInputActionKey.Middle(touchUp) - -1 -> MouseInputActionKey.Touch(touchUp) + -1 -> MouseInputActionKey.Screen(touchUp, pointer) else -> null } } diff --git a/core/src/ru/deadsoftware/cavedroid/game/mobs/Mob.java b/core/src/ru/deadsoftware/cavedroid/game/mobs/Mob.java index 415ef30..fc9d61b 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/mobs/Mob.java +++ b/core/src/ru/deadsoftware/cavedroid/game/mobs/Mob.java @@ -99,17 +99,21 @@ public abstract class Mob extends Rectangle implements Serializable { } protected final void updateAnimation(float delta) { - if (mVelocity.x != 0f || Math.abs(mAnim) > mAnimDelta * delta) { - mAnim += mAnimDelta * delta; + final float velocityMultiplier = (Math.abs(getVelocity().x) / getSpeed()); + final float animMultiplier = (velocityMultiplier == 0f ? 1f : velocityMultiplier) * delta; + final float maxAnim = 60f * (velocityMultiplier == 0f ? 1f : velocityMultiplier); + + if (mVelocity.x != 0f || Math.abs(mAnim) > mAnimDelta * animMultiplier) { + mAnim += mAnimDelta * animMultiplier; } else { mAnim = 0; } - if (mAnim > 60f) { - mAnim = 60f; + if (mAnim > maxAnim) { + mAnim = maxAnim; mAnimDelta = -ANIMATION_SPEED; - } else if (mAnim < -60f) { - mAnim = -60f; + } else if (mAnim < -maxAnim) { + mAnim = -maxAnim; mAnimDelta = ANIMATION_SPEED; } diff --git a/core/src/ru/deadsoftware/cavedroid/game/mobs/player/Player.java b/core/src/ru/deadsoftware/cavedroid/game/mobs/player/Player.java index 241714a..58ddc02 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/mobs/player/Player.java +++ b/core/src/ru/deadsoftware/cavedroid/game/mobs/player/Player.java @@ -22,6 +22,7 @@ public class Player extends Mob { private static final float SPEED = 69.072f; private static final float JUMP_VELOCITY = -133.332f; + private static final int SURVIVAL_CURSOR_RANGE = 4; public static final int MAX_HEALTH = 20; public static final int INVENTORY_SIZE = 36; @@ -126,6 +127,17 @@ public class Player extends Mob { @Override public void jump() { + if (!canJump()) { + if (gameMode == 1) { + if (isFlyMode()) { + setFlyMode(false); + } else { + getVelocity().y = 0f; + setFlyMode(true); + } + } + return; + } mVelocity.y = JUMP_VELOCITY; } @@ -234,6 +246,20 @@ public class Player extends Mob { super.heal(heal); } + public void checkCursorBounds(GameWorld gameWorld) { + if (gameMode == 0) { + int minCursorX = getMapX() - SURVIVAL_CURSOR_RANGE; + int maxCursorX = getMapX() + SURVIVAL_CURSOR_RANGE; + int minCursorY = getMiddleMapY() - SURVIVAL_CURSOR_RANGE; + int maxCursorY = getMiddleMapY() + SURVIVAL_CURSOR_RANGE; + + cursorX = MathUtils.clamp(cursorX, minCursorX, maxCursorX); + cursorY = MathUtils.clamp(cursorY, minCursorY, maxCursorY); + } + + cursorY = MathUtils.clamp(cursorY, 0, gameWorld.getHeight() - 1); + } + private void drawItem(SpriteBatch spriteBatch, float x, float y, float anim) { final Item item = inventory.getActiveItem().getItem(); diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/TouchControlsRenderer.kt b/core/src/ru/deadsoftware/cavedroid/game/render/TouchControlsRenderer.kt index ad68bce..63aa09f 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/render/TouchControlsRenderer.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/render/TouchControlsRenderer.kt @@ -6,12 +6,14 @@ import com.badlogic.gdx.math.Rectangle import ru.deadsoftware.cavedroid.MainConfig import ru.deadsoftware.cavedroid.game.GameScope import ru.deadsoftware.cavedroid.game.GameUiWindow +import ru.deadsoftware.cavedroid.game.input.Joystick import ru.deadsoftware.cavedroid.game.mobs.MobsController import ru.deadsoftware.cavedroid.game.mobs.player.Player.ControlMode import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager import ru.deadsoftware.cavedroid.misc.Assets import ru.deadsoftware.cavedroid.misc.utils.ArrayMapExtensions.component1 import ru.deadsoftware.cavedroid.misc.utils.ArrayMapExtensions.component2 +import ru.deadsoftware.cavedroid.misc.utils.drawSprite import javax.inject.Inject @GameScope @@ -25,6 +27,26 @@ class TouchControlsRenderer @Inject constructor( private val shadeTexture get() = Assets.textureRegions[SHADE_KEY] + private fun drawJoystick(spriteBatch: SpriteBatch) { + val joystick = mainConfig.joystick?.takeIf { it.active } ?: return + + spriteBatch.drawSprite( + sprite = Assets.joyBackground, + x = joystick.centerX - Joystick.RADIUS, + y = joystick.centerY - Joystick.RADIUS, + width = Joystick.SIZE, + height = Joystick.SIZE + ) + + spriteBatch.drawSprite( + sprite = Assets.joyStick, + x = joystick.activeX - Joystick.STICK_SIZE / 2, + y = joystick.activeY - Joystick.STICK_SIZE / 2, + width = Joystick.STICK_SIZE, + height = Joystick.STICK_SIZE + ) + } + override fun draw(spriteBatch: SpriteBatch, shapeRenderer: ShapeRenderer, viewport: Rectangle, delta: Float) { if (!mainConfig.isTouch || gameWindowsManager.getCurrentWindow() != GameUiWindow.NONE) { return @@ -48,6 +70,8 @@ class TouchControlsRenderer @Inject constructor( val altKeyRect = touchControlsMap.get("alt").rect spriteBatch.draw(shadeTexture, altKeyRect.x, altKeyRect.y, altKeyRect.width, altKeyRect.height) } + + drawJoystick(spriteBatch) } companion object { diff --git a/core/src/ru/deadsoftware/cavedroid/misc/Assets.java b/core/src/ru/deadsoftware/cavedroid/misc/Assets.java index 029c59f..329207f 100644 --- a/core/src/ru/deadsoftware/cavedroid/misc/Assets.java +++ b/core/src/ru/deadsoftware/cavedroid/misc/Assets.java @@ -41,6 +41,9 @@ public class Assets { public static Map blockTextures = new HashMap<>(); public static Map itemTextures = new HashMap<>(); + public static Sprite joyBackground; + public static Sprite joyStick; + public static void dispose() { minecraftFont.dispose(); loadedTextures.forEach(Texture::dispose); @@ -188,6 +191,11 @@ public class Assets { loadAllPngsFromDirInto(blocksDir, blockTextures); } + private static void loadJoystick(AssetLoader assetLoader) { + joyStick = new Sprite(loadTexture(assetLoader.getAssetHandle("joy_stick.png"))); + joyBackground = new Sprite(loadTexture(assetLoader.getAssetHandle("joy_background.png"))); + } + public static void load(final AssetLoader assetLoader) { loadMob(assetLoader, playerSprite, "char"); loadMob(assetLoader, pigSprite, "pig"); @@ -196,6 +204,7 @@ public class Assets { loadBlocks(assetLoader); loadItems(assetLoader); loadTouchButtonsFromJSON(assetLoader); + loadJoystick(assetLoader); setPlayerHeadOrigin(); minecraftFont = new BitmapFont(assetLoader.getAssetHandle("font.fnt"), true); minecraftFont.getData().setScale(.375f);