DEADSOFTWARE

Add survival inventory
authorfredboy <fredboy@protonmail.com>
Mon, 22 Apr 2024 17:42:10 +0000 (00:42 +0700)
committerfredboy <fredboy@protonmail.com>
Mon, 22 Apr 2024 17:42:10 +0000 (00:42 +0700)
android/assets/inventory.png [new file with mode: 0644]
android/assets/json/texture_regions.json
core/src/ru/deadsoftware/cavedroid/game/GameInput.java
core/src/ru/deadsoftware/cavedroid/game/mobs/Player.java
core/src/ru/deadsoftware/cavedroid/game/render/HudRenderer.kt
core/src/ru/deadsoftware/cavedroid/game/render/WindowsRenderer.kt
core/src/ru/deadsoftware/cavedroid/game/render/windows/AbstractWindowRenderer.kt [new file with mode: 0644]
core/src/ru/deadsoftware/cavedroid/game/render/windows/CreativeWindowRenderer.kt
core/src/ru/deadsoftware/cavedroid/game/render/windows/SurvivalWindowRenderer.kt [new file with mode: 0644]

diff --git a/android/assets/inventory.png b/android/assets/inventory.png
new file mode 100644 (file)
index 0000000..8bc6cf7
Binary files /dev/null and b/android/assets/inventory.png differ
index 01507d46bb75f6686dfa81eb625ab4f0efce6185..2b73d8f127f8f3ae0295ea44fdba01f8d5b12283 100644 (file)
       "h": 15
     }
   },
+  "inventory": {
+    "survival": {
+      "w": 176,
+      "h": 166
+    }
+  },
   "buttons": {
     "button_0": {
       "w": 200,
index a45e7045446eb51feef1afb024dc211a54b3da5a..85fd63bcba6f6b615ce654aed624c9109784b7a1 100644 (file)
@@ -282,13 +282,24 @@ public class GameInput {
                         mMainConfig.getWidth() / 2 + (float) hotbar.getRegionWidth() / 2).contains(x);
     }
 
+    private void openInventory() {
+        switch (mPlayer.gameMode) {
+            case 0:
+                mMainConfig.setGameUiWindow(GameUiWindow.SURVIVAL_INVENTORY);
+                break;
+            case 1:
+                mMainConfig.setGameUiWindow(GameUiWindow.CREATIVE_INVENTORY);
+                break;
+        }
+    }
+
     private void holdMB() {
         if (mTouchDownBtn == Input.Buttons.RIGHT) {
             useItem(mPlayer.cursorX, mPlayer.cursorY, mPlayer.inventory[mPlayer.slot].getItem(), true);
             mTouchedDown = false;
         } else {
             if (insideHotbar(mTouchDownX, mTouchDownY)) {
-                mMainConfig.setGameUiWindow(GameUiWindow.CREATIVE_INVENTORY);
+                openInventory();
                 mTouchedDown = false;
             }
         }
@@ -315,14 +326,7 @@ public class GameInput {
 
             case Input.Keys.E:
                 if (mMainConfig.checkGameUiWindow(GameUiWindow.NONE)) {
-                    switch (mPlayer.gameMode) {
-                        case 0:
-                            //TODO survival inv
-                            break;
-                        case 1:
-                            mMainConfig.setGameUiWindow(GameUiWindow.CREATIVE_INVENTORY);
-                            break;
-                    }
+                    openInventory();
                 } else {
                     mMainConfig.setGameUiWindow(GameUiWindow.NONE);
                 }
index b1896e4fdb8f858a3f32fd3c91bd7d36e9e4ba1c..a93141ad6cbcc221044129ecb1cc883fd5a06219 100644 (file)
@@ -38,8 +38,8 @@ public class Player extends Mob {
 
     public Player(GameItemsHolder gameItemsHolder) {
         super(0, 0, 4, 30, randomDir(), Type.MOB, MAX_HEALTH);
-        inventory = new InventoryItem[9];
-        for (int i = 0; i < 9; i++) {
+        inventory = new InventoryItem[36];
+        for (int i = 0; i < inventory.length; i++) {
             inventory[i] = gameItemsHolder.getFallbackItem().toInventoryItem();
         }
         swim = false;
@@ -136,6 +136,8 @@ public class Player extends Mob {
 
     @Override
     public void ai(GameWorld gameWorld, GameItemsHolder gameItemsHolder, float delta) {
+        updateAnimation(delta);
+
         if (gameMode == 1) {
             return;
         }
@@ -285,8 +287,6 @@ public class Player extends Mob {
 
     @Override
     public void draw(SpriteBatch spriteBatch, float x, float y, float delta) {
-        updateAnimation(delta);
-
         final Sprite backHand = Assets.playerSprite[1][2];
         final Sprite backLeg = Assets.playerSprite[1][3];
         final Sprite frontLeg = Assets.playerSprite[0][3];
index 7bbb87689d7b6adb77742385a8ae2f2c454355ab..b6319020a2cf2b770e3b7129670753886b2e9bc2 100644 (file)
@@ -60,7 +60,7 @@ class HudRenderer @Inject constructor(
     }
 
     private fun drawHotbarItems(spriteBatch: SpriteBatch, shapeRenderer: ShapeRenderer,  hotbarX: Float) {
-        mobsController.player.inventory
+        mobsController.player.inventory.asSequence().take(HotbarConfig.hotbarCells)
             .forEachIndexed { index, item ->
                 if (item.item.isNone()) {
                     return@forEachIndexed
@@ -114,6 +114,7 @@ class HudRenderer @Inject constructor(
             const val verticalMargin = 3f
             const val itemSeparatorWidth = 4f
             const val itemSlotSpace = 16f
+            const val hotbarCells = 9
         }
 
         private data object HotbarSelectorConfig {
index 12fcd39e62a0c01c335802cbe973ba5e98abaf2e..10c211a5ce801577d6b3d14cc513e942200de977 100644 (file)
@@ -8,12 +8,14 @@ import ru.deadsoftware.cavedroid.MainConfig
 import ru.deadsoftware.cavedroid.game.GameScope
 import ru.deadsoftware.cavedroid.game.GameUiWindow
 import ru.deadsoftware.cavedroid.game.render.windows.CreativeWindowRenderer
+import ru.deadsoftware.cavedroid.game.render.windows.SurvivalWindowRenderer
 import javax.inject.Inject
 
 @GameScope
 class WindowsRenderer @Inject constructor(
     private val mainConfig: MainConfig,
     private val creativeWindowRenderer: CreativeWindowRenderer,
+    private val survivalWindowRenderer: SurvivalWindowRenderer,
 ) : IGameRenderer {
 
     override val renderLayer get() = RENDER_LAYER
@@ -21,6 +23,7 @@ class WindowsRenderer @Inject constructor(
     override fun draw(spriteBatch: SpriteBatch, shapeRenderer: ShapeRenderer, viewport: Rectangle, delta: Float) {
         when (mainConfig.gameUiWindow) {
             GameUiWindow.CREATIVE_INVENTORY -> creativeWindowRenderer.draw(spriteBatch, shapeRenderer, viewport, delta)
+            GameUiWindow.SURVIVAL_INVENTORY -> survivalWindowRenderer.draw(spriteBatch, shapeRenderer, viewport, delta)
             GameUiWindow.NONE -> return
             else -> Gdx.app.error(TAG, "Cannot draw window: ${mainConfig.gameUiWindow.name}")
         }
diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/windows/AbstractWindowRenderer.kt b/core/src/ru/deadsoftware/cavedroid/game/render/windows/AbstractWindowRenderer.kt
new file mode 100644 (file)
index 0000000..52935fe
--- /dev/null
@@ -0,0 +1,50 @@
+package ru.deadsoftware.cavedroid.game.render.windows
+
+import com.badlogic.gdx.Gdx
+import com.badlogic.gdx.graphics.g2d.SpriteBatch
+import com.badlogic.gdx.graphics.glutils.ShapeRenderer
+import ru.deadsoftware.cavedroid.game.model.item.InventoryItem
+import ru.deadsoftware.cavedroid.game.model.item.Item
+
+abstract class AbstractWindowRenderer {
+
+    protected inline fun <reified T> drawItemsGrid(
+        spriteBatch: SpriteBatch,
+        shapeRenderer: ShapeRenderer,
+        gridX: Float,
+        gridY: Float,
+        items: Iterable<T>,
+        itemsInRow: Int,
+        cellWidth: Float,
+        cellHeight: Float
+    ) {
+        if (T::class != Item::class && T::class != InventoryItem::class) {
+            Gdx.app.log(_TAG, "Trying to draw items grid of not items")
+            return
+        }
+
+        items.forEachIndexed { index, element ->
+            val item = element as? Item
+            val inventoryItem = element as? InventoryItem
+
+            if (item == null && inventoryItem == null) {
+                throw IllegalStateException("This should be unreachable")
+            }
+
+            if (item?.isNone() == true || inventoryItem?.item?.isNone() == true) {
+                return@forEachIndexed
+            }
+
+            val itemX = gridX + (index % itemsInRow) * cellWidth
+            val itemY = gridY + (index / itemsInRow) * cellHeight
+
+            inventoryItem?.draw(spriteBatch, shapeRenderer, itemX, itemY)
+                ?: item?.let { spriteBatch.draw(it.sprite, itemX, itemY) }
+        }
+    }
+
+    companion object {
+        protected const val _TAG = "AbstractWindowRenderer"
+    }
+
+}
\ No newline at end of file
index d9423ff2ce8c5381c379e5bc8e4813ed6e13a5be..ef62996199b0a36c6a5d9e6c86a2258a7ffd368b 100644 (file)
@@ -13,6 +13,7 @@ import ru.deadsoftware.cavedroid.game.render.IGameRenderer
 import ru.deadsoftware.cavedroid.game.render.WindowsRenderer
 import ru.deadsoftware.cavedroid.misc.Assets
 import javax.inject.Inject
+import kotlin.math.min
 
 @GameScope
 class CreativeWindowRenderer @Inject constructor(
@@ -20,56 +21,15 @@ class CreativeWindowRenderer @Inject constructor(
     private val gameInput: GameInput,
     private val gameItemsHolder: GameItemsHolder,
     private val mobsController: MobsController,
-) : IGameRenderer {
+) : AbstractWindowRenderer(), IGameRenderer {
 
     override val renderLayer get() = WindowsRenderer.RENDER_LAYER
 
     private val creativeWindowTexture get() = requireNotNull(Assets.textureRegions[CREATIVE_WINDOW_KEY])
     private val scrollIndicatorTexture get() = requireNotNull(Assets.textureRegions[SCROLL_INDICATOR_KEY])
 
-    private fun drawItemsGrid(spriteBatch: SpriteBatch, gridX: Float, gridY: Float) {
-        val allItems = gameItemsHolder.getAllItems()
-        val startIndex = gameInput.creativeScroll * CreativeWindowConfig.itemsInRow
-        val endIndex = startIndex + CreativeWindowConfig.itemsOnPage
-
-        for (i in startIndex..<endIndex) {
-            if (i !in allItems.indices) {
-                break
-            }
-            val item = allItems.elementAt(i)
-
-            if (item.isNone()) {
-                continue
-            }
-
-            val gridIndex = i - startIndex
-
-            val itemX = gridX + (gridIndex % CreativeWindowConfig.itemsInRow) * CreativeWindowConfig.itemsGridColWidth
-            val itemY = gridY + (gridIndex / CreativeWindowConfig.itemsInRow) * CreativeWindowConfig.itemsGridRowHeight
-
-            spriteBatch.draw(item.sprite, itemX, itemY)
-        }
-    }
-
-    private fun drawPlayerInventory(
-        spriteBatch: SpriteBatch,
-        shapeRenderer: ShapeRenderer,
-        inventoryX: Float,
-        inventoryY: Float
-    ) {
-        mobsController.player.inventory.asSequence()
-            .forEachIndexed { index, item ->
-                if (item.item.isNone()) {
-                    return@forEachIndexed
-                }
-
-                val itemX = inventoryX + index * CreativeWindowConfig.itemsGridColWidth
-
-                item.draw(spriteBatch, shapeRenderer, itemX, inventoryY)
-            }
-    }
 
-    private fun drawCreative(spriteBatch: SpriteBatch, shapeRenderer: ShapeRenderer, viewport: Rectangle) {
+    override fun draw(spriteBatch: SpriteBatch, shapeRenderer: ShapeRenderer, viewport: Rectangle, delta: Float) {
         val creativeWindow = creativeWindowTexture
 
         val windowX = viewport.width / 2 - creativeWindow.regionWidth / 2
@@ -84,24 +44,38 @@ class CreativeWindowRenderer @Inject constructor(
                     + (gameInput.creativeScroll * oneScrollAmount)
         )
 
+        val allItems = gameItemsHolder.getAllItems()
+        val startIndex = gameInput.creativeScroll * CreativeWindowConfig.itemsInRow
+        val endIndex = min(startIndex + CreativeWindowConfig.itemsOnPage, allItems.size)
+        val items = sequence {
+            for (i in startIndex..<endIndex) {
+                yield(allItems.elementAt(i))
+            }
+        }
+
         drawItemsGrid(
             spriteBatch = spriteBatch,
+            shapeRenderer = shapeRenderer,
             gridX = windowX + CreativeWindowConfig.itemsGridMarginLeft,
-            gridY = windowY + CreativeWindowConfig.itemsGridMarginTop
+            gridY = windowY + CreativeWindowConfig.itemsGridMarginTop,
+            items = items.asIterable(),
+            itemsInRow = CreativeWindowConfig.itemsInRow,
+            cellWidth = CreativeWindowConfig.itemsGridColWidth,
+            cellHeight = CreativeWindowConfig.itemsGridRowHeight,
         )
 
-        drawPlayerInventory(
+        drawItemsGrid(
             spriteBatch = spriteBatch,
             shapeRenderer = shapeRenderer,
-            inventoryX = windowX + CreativeWindowConfig.itemsGridMarginLeft,
-            inventoryY = windowY + creativeWindow.regionHeight - CreativeWindowConfig.playerInventoryOffsetFromBottom
+            gridX = windowX + CreativeWindowConfig.itemsGridMarginLeft,
+            gridY = windowY + creativeWindow.regionHeight - CreativeWindowConfig.playerInventoryOffsetFromBottom,
+            items = mobsController.player.inventory.asSequence().take(CreativeWindowConfig.invItems).asIterable(),
+            itemsInRow = CreativeWindowConfig.invItems,
+            cellWidth = CreativeWindowConfig.itemsGridColWidth,
+            cellHeight = CreativeWindowConfig.itemsGridRowHeight,
         )
     }
 
-    override fun draw(spriteBatch: SpriteBatch, shapeRenderer: ShapeRenderer, viewport: Rectangle, delta: Float) {
-        drawCreative(spriteBatch, shapeRenderer, viewport)
-    }
-
     companion object {
         private const val CREATIVE_WINDOW_KEY = "creative"
         private const val SCROLL_INDICATOR_KEY = "handle"
@@ -120,6 +94,8 @@ class CreativeWindowRenderer @Inject constructor(
             const val itemsInRow = 8
             const val itemsInCol = 5
 
+            const val invItems = 9
+
             const val playerInventoryOffsetFromBottom = 24f
 
             val itemsOnPage get() = itemsInCol * itemsInRow
diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/windows/SurvivalWindowRenderer.kt b/core/src/ru/deadsoftware/cavedroid/game/render/windows/SurvivalWindowRenderer.kt
new file mode 100644 (file)
index 0000000..f8a6ac0
--- /dev/null
@@ -0,0 +1,119 @@
+package ru.deadsoftware.cavedroid.game.render.windows
+
+import com.badlogic.gdx.Gdx
+import com.badlogic.gdx.graphics.g2d.SpriteBatch
+import com.badlogic.gdx.graphics.glutils.ShapeRenderer
+import com.badlogic.gdx.math.MathUtils
+import com.badlogic.gdx.math.Rectangle
+import ru.deadsoftware.cavedroid.MainConfig
+import ru.deadsoftware.cavedroid.game.GameScope
+import ru.deadsoftware.cavedroid.game.mobs.Mob
+import ru.deadsoftware.cavedroid.game.mobs.MobsController
+import ru.deadsoftware.cavedroid.game.render.IGameRenderer
+import ru.deadsoftware.cavedroid.game.render.WindowsRenderer
+import ru.deadsoftware.cavedroid.misc.Assets
+import javax.inject.Inject
+import kotlin.math.atan
+
+@GameScope
+class SurvivalWindowRenderer @Inject constructor(
+    private val mainConfig: MainConfig,
+    private val mobsController: MobsController,
+) : AbstractWindowRenderer(), IGameRenderer {
+
+    override val renderLayer get() = WindowsRenderer.RENDER_LAYER
+
+    private val survivalWindowTexture get() = requireNotNull(Assets.textureRegions[SURVIVAL_WINDOW_KEY])
+
+    private fun setPortraitHeadRotation(portraitX: Float, portraitY: Float) {
+        if (mainConfig.isTouch) {
+            return
+        }
+
+        val mouseX = Gdx.input.x * (mainConfig.width / Gdx.graphics.width)
+        val mouseY = Gdx.input.y * (mainConfig.height / Gdx.graphics.height)
+
+        val h = mouseX.toDouble() - portraitX.toDouble()
+        val v = mouseY.toDouble() - portraitY.toDouble()
+
+        mobsController.player.setDir(
+            if (mouseX < portraitX + mobsController.player.width / 2)
+                Mob.Direction.LEFT
+            else
+                Mob.Direction.RIGHT
+        )
+
+        mobsController.player.headRotation = atan(v / h).toFloat() * MathUtils.radDeg
+    }
+
+    private fun drawPlayerPortrait(spriteBatch: SpriteBatch, windowX: Float, windowY: Float, delta: Float) {
+        val portraitX = windowX + Config.portraitMarginLeft +
+                (Config.portraitWidth / 2 - mobsController.player.width / 2)
+        val portraitY = windowY + Config.portraitMarginTop +
+                (Config.portraitHeight / 2 - mobsController.player.height / 2)
+
+        setPortraitHeadRotation(portraitX, portraitY)
+        mobsController.player.draw(spriteBatch, portraitX, portraitY, delta)
+    }
+
+    override fun draw(spriteBatch: SpriteBatch, shapeRenderer: ShapeRenderer, viewport: Rectangle, delta: Float) {
+        val survivalWindow = survivalWindowTexture
+
+        val windowX = viewport.width / 2 - survivalWindow.regionWidth / 2
+        val windowY = viewport.height / 2 - survivalWindow.regionHeight / 2
+
+        spriteBatch.draw(survivalWindow, windowX, windowY)
+
+        drawPlayerPortrait(spriteBatch, windowX, windowY, delta)
+
+        drawItemsGrid(
+            spriteBatch = spriteBatch,
+            shapeRenderer = shapeRenderer,
+            gridX = windowX + Config.itemsGridMarginLeft,
+            gridY = windowY + Config.itemsGridMarginTop,
+            items = mobsController.player.inventory.asSequence()
+                .drop(Config.hotbarCells)
+                .take(Config.itemsInCol * Config.itemsInRow)
+                .asIterable(),
+            itemsInRow = Config.itemsInRow,
+            cellWidth = Config.itemsGridColWidth,
+            cellHeight = Config.itemsGridRowHeight,
+        )
+
+        drawItemsGrid(
+            spriteBatch = spriteBatch,
+            shapeRenderer = shapeRenderer,
+            gridX = windowX + Config.itemsGridMarginLeft,
+            gridY = windowY + survivalWindow.regionHeight - Config.hotbarOffsetFromBottom,
+            items = mobsController.player.inventory.asSequence()
+                .take(Config.hotbarCells)
+                .asIterable(),
+            itemsInRow = Config.hotbarCells,
+            cellWidth = Config.itemsGridColWidth,
+            cellHeight = Config.itemsGridRowHeight,
+        )
+    }
+
+    companion object {
+        private const val SURVIVAL_WINDOW_KEY = "survival"
+
+        private data object Config {
+            const val itemsGridMarginLeft = 8f
+            const val itemsGridMarginTop = 84f
+
+            const val itemsGridRowHeight = 18f
+            const val itemsGridColWidth = 18f
+
+            const val itemsInRow = 8
+            const val itemsInCol = 5
+
+            const val hotbarOffsetFromBottom = 24f
+            const val hotbarCells = 9
+
+            const val portraitMarginLeft = 24f
+            const val portraitMarginTop = 8f
+            const val portraitWidth = 48f
+            const val portraitHeight = 68f
+        }
+    }
+}
\ No newline at end of file