From: fredboy <fredboy@protonmail.com> Date: Mon, 22 Apr 2024 17:42:10 +0000 (+0700) Subject: Add survival inventory X-Git-Tag: alpha0.6.2~8 X-Git-Url: http://deadsoftware.ru/gitweb?a=commitdiff_plain;h=060595c8f929b1eba81653c5154f948fb12190ff;p=cavedroid.git Add survival inventory --- diff --git a/android/assets/inventory.png b/android/assets/inventory.png new file mode 100644 index 0000000..8bc6cf7 Binary files /dev/null and b/android/assets/inventory.png differ diff --git a/android/assets/json/texture_regions.json b/android/assets/json/texture_regions.json index 01507d4..2b73d8f 100644 --- a/android/assets/json/texture_regions.json +++ b/android/assets/json/texture_regions.json @@ -49,6 +49,12 @@ "h": 15 } }, + "inventory": { + "survival": { + "w": 176, + "h": 166 + } + }, "buttons": { "button_0": { "w": 200, diff --git a/core/src/ru/deadsoftware/cavedroid/game/GameInput.java b/core/src/ru/deadsoftware/cavedroid/game/GameInput.java index a45e704..85fd63b 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/GameInput.java +++ b/core/src/ru/deadsoftware/cavedroid/game/GameInput.java @@ -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); } diff --git a/core/src/ru/deadsoftware/cavedroid/game/mobs/Player.java b/core/src/ru/deadsoftware/cavedroid/game/mobs/Player.java index b1896e4..a93141a 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/mobs/Player.java +++ b/core/src/ru/deadsoftware/cavedroid/game/mobs/Player.java @@ -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]; diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/HudRenderer.kt b/core/src/ru/deadsoftware/cavedroid/game/render/HudRenderer.kt index 7bbb876..b631902 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/render/HudRenderer.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/render/HudRenderer.kt @@ -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 { diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/WindowsRenderer.kt b/core/src/ru/deadsoftware/cavedroid/game/render/WindowsRenderer.kt index 12fcd39..10c211a 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/render/WindowsRenderer.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/render/WindowsRenderer.kt @@ -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 index 0000000..52935fe --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/render/windows/AbstractWindowRenderer.kt @@ -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 diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/windows/CreativeWindowRenderer.kt b/core/src/ru/deadsoftware/cavedroid/game/render/windows/CreativeWindowRenderer.kt index d9423ff..ef62996 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/render/windows/CreativeWindowRenderer.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/render/windows/CreativeWindowRenderer.kt @@ -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 index 0000000..f8a6ac0 --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/render/windows/SurvivalWindowRenderer.kt @@ -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