summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: d555e8c)
raw | patch | inline | side by side (parent: d555e8c)
author | fredboy <fredboy@protonmail.com> | |
Sun, 21 Apr 2024 12:46:44 +0000 (19:46 +0700) | ||
committer | fredboy <fredboy@protonmail.com> | |
Sun, 21 Apr 2024 12:46:44 +0000 (19:46 +0700) |
34 files changed:
index 01d66ff111ed5981f43a24193ceccf84cdbaadeb..5600fb258485c876e5c08d0bae897eb9873b396f 100644 (file)
"collision": false,
"transparent": true,
"drop": "none",
- "texture": "none"
+ "texture": "none",
+ "meta": "none"
},
"stone": {
"id": 1,
"none": {
"id": 0,
"name": "",
- "type": "block",
+ "type": "none",
"texture": "none"
},
"stone": {
diff --git a/core/src/ru/deadsoftware/cavedroid/game/GameComponent.java b/core/src/ru/deadsoftware/cavedroid/game/GameComponent.java
index 0bf5c2d4acf38a18bc33dd99af0b105fe1925f6a..058c8b27a18863d475d0c8c04c3630d386da1ec7 100644 (file)
import ru.deadsoftware.cavedroid.game.actions.PlaceBlockActionsModule;
import ru.deadsoftware.cavedroid.game.actions.UpdateBlockActionsModule;
import ru.deadsoftware.cavedroid.game.actions.UseItemActionsModule;
+import ru.deadsoftware.cavedroid.game.render.RenderModule;
@GameScope
-@Component(dependencies = MainComponent.class, modules = {GameModule.class, UseItemActionsModule.class, UpdateBlockActionsModule.class, PlaceBlockActionsModule.class})
+@Component(dependencies = MainComponent.class,
+ modules = {GameModule.class,
+ UseItemActionsModule.class,
+ UpdateBlockActionsModule.class,
+ PlaceBlockActionsModule.class,
+ RenderModule.class})
public interface GameComponent {
GameProc getGameProc();
diff --git a/core/src/ru/deadsoftware/cavedroid/game/GameInput.java b/core/src/ru/deadsoftware/cavedroid/game/GameInput.java
index fb20d8fb0520ff9fe125d29ce1de5a4645f1161c..e5b08381fbd10d0ad9285c4805dfe3a5bea00179 100644 (file)
return mKeyDown;
}
- int getBlockDamage() {
+ public int getBlockDamage() {
return mBlockDamage;
}
- int getCurX() {
+ public int getCurX() {
return mCurX;
}
- int getCurY() {
+ public int getCurY() {
return mCurY;
}
- int getCreativeScroll() {
+ public int getCreativeScroll() {
return mCreativeScroll;
}
diff --git a/core/src/ru/deadsoftware/cavedroid/game/GameItemsHolder.kt b/core/src/ru/deadsoftware/cavedroid/game/GameItemsHolder.kt
index 23fe4fbe4104977b0f47e1b1523417e7fae2cfc2..075af6f4f39cf707ad9bd48f78c6f21f8fc66b06 100644 (file)
return itemsMap.values
}
- fun getItemFromCreativeInventory(position: Int): Item? {
+ fun getItemFromCreativeInventory(position: Int): Item {
return if (position in itemsMap.values.indices) {
itemsMap.values.elementAt(position)
} else {
- null
+ fallbackItem
}
}
diff --git a/core/src/ru/deadsoftware/cavedroid/game/GameProc.java b/core/src/ru/deadsoftware/cavedroid/game/GameProc.java
index 1a0a0448aba0889f6bf85284f6a6b9d88de36458..184e376cba5c448991c67c303e73f132c613cb3a 100644 (file)
import ru.deadsoftware.cavedroid.game.mobs.MobsController;
import ru.deadsoftware.cavedroid.game.world.GameWorldBlocksLogicControllerTask;
import ru.deadsoftware.cavedroid.game.world.GameWorldFluidsLogicControllerTask;
-import ru.deadsoftware.cavedroid.misc.utils.AssetLoader;
import javax.inject.Inject;
private final MobsController mMobsController;
private final GameWorldFluidsLogicControllerTask mGameWorldFluidsLogicControllerTask;
private final GameWorldBlocksLogicControllerTask mGameWorldBlocksLogicControllerTask;
- private final GameItemsHolder mGameItemsHolder;
private final Timer mWorldLogicTimer = new Timer();
GameRenderer gameRenderer,
MobsController mobsController,
GameWorldFluidsLogicControllerTask gameWorldFluidsLogicControllerTask,
- GameWorldBlocksLogicControllerTask gameWorldBlocksLogicControllerTask,
- GameItemsHolder gameItemsHolder
+ GameWorldBlocksLogicControllerTask gameWorldBlocksLogicControllerTask
) {
mGamePhysics = gamePhysics;
mGameInput = gameInput;
mMobsController = mobsController;
mGameWorldFluidsLogicControllerTask = gameWorldFluidsLogicControllerTask;
mGameWorldBlocksLogicControllerTask = gameWorldBlocksLogicControllerTask;
- mGameItemsHolder = gameItemsHolder;
- mGameItemsHolder.initialize();
+
mWorldLogicTimer.scheduleTask(gameWorldFluidsLogicControllerTask, 0,
GameWorldFluidsLogicControllerTask.FLUID_UPDATE_INTERVAL_SEC);
diff --git a/core/src/ru/deadsoftware/cavedroid/game/GameRenderer.java b/core/src/ru/deadsoftware/cavedroid/game/GameRenderer.java
index a3a9f015fb92b00a2f5fb0019a44af1650e7b3da..c0af140bbf3b64dfc7bcc1bddd906087dce92e1c 100644 (file)
package ru.deadsoftware.cavedroid.game;
import com.badlogic.gdx.Gdx;
-import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
-import com.badlogic.gdx.graphics.g2d.Sprite;
-import com.badlogic.gdx.graphics.g2d.TextureRegion;
-import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
-import com.badlogic.gdx.math.Intersector;
-import com.badlogic.gdx.math.MathUtils;
-import com.badlogic.gdx.math.Rectangle;
-import kotlin.collections.CollectionsKt;
import ru.deadsoftware.cavedroid.MainConfig;
-import ru.deadsoftware.cavedroid.game.mobs.Mob;
import ru.deadsoftware.cavedroid.game.mobs.MobsController;
import ru.deadsoftware.cavedroid.game.mobs.Player;
-import ru.deadsoftware.cavedroid.game.model.block.Block;
-import ru.deadsoftware.cavedroid.game.model.item.Item;
-import ru.deadsoftware.cavedroid.game.objects.Drop;
-import ru.deadsoftware.cavedroid.game.objects.DropController;
-import ru.deadsoftware.cavedroid.game.world.GameWorld;
-import ru.deadsoftware.cavedroid.misc.ControlMode;
+import ru.deadsoftware.cavedroid.game.render.IGameRenderer;
import ru.deadsoftware.cavedroid.misc.Renderer;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
import javax.inject.Inject;
-
-import java.util.Collection;
-
-import static ru.deadsoftware.cavedroid.misc.Assets.*;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Set;
@GameScope
public class GameRenderer extends Renderer {
- private static final String TAG = "GameRenderer";
-
- private final MainConfig mMainConfig;
private final GameInput mGameInput;
- private final GameWorld mGameWorld;
private final MobsController mMobsController;
- private final DropController mDropController;
- private final GameItemsHolder mGameItemsHolder;
+ private final List<IGameRenderer> mRenderers;
@Inject
GameRenderer(MainConfig mainConfig,
GameInput gameInput,
- GameWorld gameWorld,
MobsController mobsController,
- DropController dropController,
- GameItemsHolder gameItemsHolder) {
+ Set<IGameRenderer> renderers) {
super(mainConfig.getWidth(), mainConfig.getHeight());
- mMainConfig = mainConfig;
mGameInput = gameInput;
- mGameWorld = gameWorld;
mMobsController = mobsController;
- mDropController = dropController;
- mGameItemsHolder = gameItemsHolder;
+ mRenderers = new ArrayList<>(renderers);
+ mRenderers.sort(Comparator.comparingInt(IGameRenderer::getRenderLayer));
Gdx.gl.glClearColor(0f, .6f, .6f, 1f);
}
- private float drawX(int x) {
- return x * 16 - getCamX();
- }
-
- private float drawY(int y) {
- return y * 16 - getCamY();
- }
-
- private void drawWreck(Block bl) {
- if (mGameInput.getBlockDamage() > 0) {
- int index = 10 * mGameInput.getBlockDamage() / bl.getHp();
- String key = "break_" + index;
-
- if (index > 10 || index < 0) {
- return;
- }
-
- spriter.draw(textureRegions.get(key), mGameInput.getCurX() * 16 - getCamX(),
- mGameInput.getCurY() * 16 - getCamY());
- }
- }
-
- private void drawBlock(int x, int y, boolean drawBG) {
- if (drawBG) {
- if ((!mGameWorld.hasForeAt(x, y) || mGameWorld.getForeMap(x, y).isTransparent())
- && mGameWorld.hasBackAt(x, y)) {
- mGameWorld.getBackMap(x, y).draw(spriter, drawX(x), drawY(y));
- if (!mGameWorld.hasForeAt(x, y) && x == mGameInput.getCurX() && y == mGameInput.getCurY()) {
- drawWreck(mGameWorld.getBackMap(mGameInput.getCurX(), mGameInput.getCurY()));
- }
- }
- }
- if (mGameWorld.hasForeAt(x, y) && mGameWorld.getForeMap(x, y).isBackground() == drawBG) {
- mGameWorld.getForeMap(x, y).draw(spriter, drawX(x), drawY(y));
- if (x == mGameInput.getCurX() && y == mGameInput.getCurY()) {
- drawWreck(mGameWorld.getForeMap(mGameInput.getCurX(), mGameInput.getCurY()));
- }
- }
- }
-
- private void drawWorld(boolean bg) {
- int minX = (int) (getCamX() / 16) - 1;
- int minY = (int) (getCamY() / 16) - 1;
- int maxX = (int) ((getCamX() + getWidth()) / 16) + 1;
- int maxY = (int) ((getCamY() + getHeight()) / 16) + 1;
- if (minY < 0) {
- minY = 0;
- }
- if (maxY > mGameWorld.getHeight()) {
- maxY = mGameWorld.getHeight();
- }
- for (int y = minY; y < maxY; y++) {
- for (int x = minX; x < maxX; x++) {
- drawBlock(x, y, bg);
- }
- }
- if (bg) {
- spriter.end();
- Gdx.gl.glEnable(GL20.GL_BLEND);
- Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
- shaper.begin(ShapeRenderer.ShapeType.Filled);
- shaper.setColor(0f, 0f, 0f, .5f);
- for (int y = minY; y < maxY; y++) {
- for (int x = minX; x < maxX; x++) {
- if ((!mGameWorld.hasForeAt(x, y) || mGameWorld.getForeMap(x, y).isTransparent())
- && mGameWorld.hasBackAt(x, y)) {
- shaper.rect(drawX(x), drawY(y), 16, 16);
- }
- }
- }
- shaper.end();
- Gdx.gl.glDisable(GL20.GL_BLEND);
- spriter.begin();
- }
- }
-
- private Rectangle getShiftedRectRespectfulToViewPort(final Rectangle rect, final float shift) {
- return new Rectangle(rect.x + shift - getCamX(), rect.y - getCamY(), rect.width, rect.height);
- }
-
- @CheckForNull
- private Rectangle getDrawingRectIfInsideViewport(final Rectangle rectangle) {
- final Rectangle viewportRect = new Rectangle(0, 0, getWidth(), getHeight());
-
- final Rectangle notShifted = getShiftedRectRespectfulToViewPort(rectangle, 0);
- if (Intersector.overlaps(viewportRect, notShifted)) {
- return notShifted;
- }
-
- final Rectangle shiftedLeft = getShiftedRectRespectfulToViewPort(rectangle, -mGameWorld.getWidthPx());
- if (Intersector.overlaps(viewportRect, shiftedLeft)) {
- return shiftedLeft;
- }
-
- final Rectangle shiftedRight = getShiftedRectRespectfulToViewPort(rectangle, mGameWorld.getWidthPx());
- if (Intersector.overlaps(viewportRect, shiftedRight)) {
- return shiftedRight;
- }
-
- return null;
- }
-
- private void drawMob(Mob mob, float delta) {
- float mobDrawX = mob.getX() - getCamX();
- float mobDrawY = mob.getY() - getCamY();
-
- if (mobDrawX + mob.getWidth() < 0 && mobDrawX + mGameWorld.getWidthPx() > 0) {
- mobDrawX += mGameWorld.getWidthPx();
- } else if (mobDrawX > getWidth() && mobDrawX + mob.getWidth() - mGameWorld.getWidthPx() > 0) {
- mobDrawX -= mGameWorld.getWidthPx();
- } else if (mobDrawX + mob.getWidth() < 0 && mobDrawX > getWidth()) {
- return;
- }
-
- mob.draw(spriter, mobDrawX, mobDrawY, delta);
- }
-
- private void drawDrop(Drop drop) {
- @CheckForNull final Rectangle drawingRect = getDrawingRectIfInsideViewport(drop);
-
- if (drawingRect == null) {
- return;
- }
-
- final Sprite sprite = drop.getItem().getSprite();
-
- sprite.setPosition(drawingRect.x, drawingRect.y);
- sprite.setSize(drawingRect.width, drawingRect.height);
- sprite.draw(spriter);
- }
-
- @SuppressWarnings("IntegerDivisionInFloatingPointContext")
- private void drawCreative() {
- TextureRegion creative = textureRegions.get("creative");
- float x = getWidth() / 2 - (float) creative.getRegionWidth() / 2;
- float y = getHeight() / 2 - (float) creative.getRegionHeight() / 2;
- spriter.draw(creative, x, y);
- spriter.draw(textureRegions.get("handle"), x + 156,
- y + 18 + (mGameInput.getCreativeScroll() * (72f / mGameItemsHolder.getCreativeScrollAmount())));
- final Collection<Item> items = mGameItemsHolder.getAllItems();
- for (int i = mGameInput.getCreativeScroll() * 8; i < mGameInput.getCreativeScroll() * 8 + 40; i++) {
- if (i > 0 && i < items.size()) {
- Item item = CollectionsKt.elementAt(items, i);
- if (item != mGameItemsHolder.getFallbackItem()) {
- spriter.draw(CollectionsKt.elementAt(items, i).getSprite(),
- x + 8 + ((i - mGameInput.getCreativeScroll() * 8) % 8) * 18,
- y + 18 + ((i - mGameInput.getCreativeScroll() * 8) / 8) * 18);
- }
- }
- }
- for (int i = 0; i < 9; i++) {
- if (mMobsController.getPlayer().inventory[i] != null && mMobsController.getPlayer().inventory[i].getItem() != mGameItemsHolder.getFallbackItem()) {
- spriter.draw(mMobsController.getPlayer().inventory[i].getItem().getSprite(),
- x + 8 + i * 18, y + creative.getRegionHeight() - 24);
- }
- }
-
- }
-
- private void drawHealth(float x, float y) {
- Player player = mMobsController.getPlayer();
-
- if (player.gameMode == 1) {
- return;
- }
-
- TextureRegion wholeHeart = textureRegions.get("heart_whole");
- TextureRegion halfHeart = textureRegions.get("heart_half");
-
- int wholeHearts = player.getHealth() / 2;
-
- for (int i = 0; i < wholeHearts; i++) {
- spriter.draw(wholeHeart, x + i * wholeHeart.getRegionWidth(), y);
- }
-
- if (player.getHealth() % 2 == 1) {
- spriter.draw(halfHeart, x + wholeHearts * wholeHeart.getRegionWidth(), y);
- }
- }
-
- private void drawGUI() {
- TextureRegion cursor = textureRegions.get("cursor");
- TextureRegion hotbar = textureRegions.get("hotbar");
- TextureRegion hotbarSelector = textureRegions.get("hotbar_selector");
-
- if (mGameWorld.hasForeAt(mGameInput.getCurX(), mGameInput.getCurY()) ||
- mGameWorld.hasBackAt(mGameInput.getCurX(), mGameInput.getCurY()) ||
- mGameInput.getControlMode() == ControlMode.CURSOR || mMainConfig.isTouch()) {
- spriter.draw(cursor, mGameInput.getCurX() * 16 - getCamX(), mGameInput.getCurY() * 16 - getCamY());
- }
-
- float hotbarX = getWidth() / 2 - (float) hotbar.getRegionWidth() / 2;
- spriter.draw(hotbar, hotbarX, 0);
- drawHealth(hotbarX, hotbar.getRegionHeight());
-
- for (int i = 0; i < 9; i++) {
- if (mMobsController.getPlayer().inventory[i] != null && mMobsController.getPlayer().inventory[i].getItem() != mGameItemsHolder.getFallbackItem()) {
- spriter.draw(mMobsController.getPlayer().inventory[i].getItem().getSprite(),
- getWidth() / 2 - (float) hotbar.getRegionWidth() / 2 + 3 + i * 20,
- 3);
- }
- }
- spriter.draw(hotbarSelector,
- getWidth() / 2 - (float) hotbar.getRegionWidth() / 2 - 1 + 20 * mMobsController.getPlayer().slot,
- -1);
- }
-
- private void drawTouchGui() {
- for (int i = 0; i < guiMap.size; i++) {
- Rectangle touchKey = guiMap.getValueAt(i).getRect();
- spriter.draw(textureRegions.get(guiMap.getKeyAt(i)),
- touchKey.x, touchKey.y, touchKey.width, touchKey.height);
- }
- if (mGameInput.getControlMode() == ControlMode.CURSOR) {
- spriter.draw(textureRegions.get("shade"), 83, getHeight() - 21);
- }
- }
-
- private void drawGamePlay(float delta) {
- Player player = mMobsController.getPlayer();
-
- drawWorld(true);
- player.draw(spriter, player.getX() - getCamX() - player.getWidth() / 2, player.getY() - getCamY(), delta);
- mMobsController.getMobs().forEach((mob) -> {
- drawMob(mob, delta);
- });
- mDropController.forEach(this::drawDrop);
- drawWorld(false);
- drawGUI();
- }
-
private void updateCameraPosition() {
Player player = mMobsController.getPlayer();
setCamPos(player.getX() + player.getWidth() / 2 - getWidth() / 2,
player.getY() + player.getHeight() / 2 - getHeight() / 2);
}
- @Nullable
- private Color getMinimapColor(int x, int y) {
- @Nullable Color result = null;
-
- final boolean hasForeMap = mGameWorld.hasForeAt(x, y);
- final boolean hasBackMap = mGameWorld.hasBackAt(x, y);
-
- if (hasForeMap) {
- final Block block = mGameWorld.getForeMap(x, y);
-
- if (block.isWater()) {
- result = Color.BLUE;
- } else if (block.isLava()) {
- result = Color.RED;
- } else {
- result = Color.BLACK;
- }
- } else if (hasBackMap) {
- result = Color.DARK_GRAY;
- }
-
- return result;
- }
-
- private void drawMiniMap(float miniMapX, float miniMapY, float size) {
- shaper.begin(ShapeRenderer.ShapeType.Filled);
-
- shaper.setColor(Color.LIGHT_GRAY);
- shaper.rect(miniMapX, miniMapY, size, size);
-
- for (int x = 0; x < size; x++) {
- for (int y = 0; y < size; y++) {
-
- final int worldX = (int) (mMobsController.getPlayer().getMapX() - size / 2 + x);
- final int worldY = (int) (mMobsController.getPlayer().getUpperMapY() - size / 2 + y);
-
- @Nullable final Color color = getMinimapColor(worldX, worldY);
-
- if (color != null) {
- shaper.setColor(color);
- shaper.rect(miniMapX + x, miniMapY + y, 1, 1);
- }
- }
- }
-
- shaper.setColor(Color.OLIVE);
- shaper.rect(miniMapX + size / 2, miniMapY + size / 2, 1, 2);
- shaper.end();
- }
@Override
public void render(float delta) {
- int fps = MathUtils.ceil(1 / delta);
updateCameraPosition();
mGameInput.moveCursor(this);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
spriter.begin();
-
- drawGamePlay(delta);
-
- switch (mMainConfig.getGameUiWindow()) {
- case CREATIVE_INVENTORY:
- drawCreative();
- break;
- //TODO draw other ui windows
- }
-
-
- if (mMainConfig.isTouch()) {
- drawTouchGui();
- }
-
+ mRenderers.forEach(iGameRenderer -> iGameRenderer.draw(spriter, shaper, getCameraViewport(), delta));
spriter.end();
-
- if (mMainConfig.isShowMap()) {
- drawMiniMap(getWidth() - 64f - 24f, 24f, 64f);
- }
-
- if (mMainConfig.isShowInfo()) {
- spriter.begin();
- Player player = mMobsController.getPlayer();
- drawString("FPS: " + fps, 0, 0);
- drawString("X: " + player.getMapX(), 0, 10);
- drawString("Y: " + player.getUpperMapY(), 0, 20);
- drawString("CurX: " + mGameInput.getCurX(), 0, 30);
- drawString("CurY: " + mGameInput.getCurY(), 0, 40);
- drawString("Velocity: " + player.getVelocity(), 0, 50);
- drawString("Swim: " + player.swim, 0, 60);
- drawString("Mobs: " + mMobsController.getMobs().size(), 0, 70);
- drawString("Drops: " + mDropController.getSize(), 0, 80);
- drawString("Block: " + mGameWorld.getForeMap(mGameInput.getCurX(), mGameInput.getCurY()).getParams().getKey(), 0, 90);
- drawString("Hand: " + mMobsController.getPlayer().inventory[mMobsController.getPlayer().slot].getItem().getParams().getKey(), 0, 100);
- drawString("Game mode: " + player.gameMode, 0, 110);
- spriter.end();
- }
-
}
}
diff --git a/core/src/ru/deadsoftware/cavedroid/game/GameSaver.java b/core/src/ru/deadsoftware/cavedroid/game/GameSaver.java
index 53d147228f96a334a31ce9cd2e575c14b154e55e..cb52b3c76b126812e355c43d9ce076c7d5749140 100644 (file)
BufferedOutputStream out = new BufferedOutputStream(file.write(false));
- out.write(intToBytes(SAVE_VERSION));
+ out.write(SAVE_VERSION);
out.write(intToBytes(width));
out.write(intToBytes(height));
run = 0;
for (Block[] blocks : map) {
int newValue = dict.get(blocks[y].getParams().getKey());
- if (newValue != block) {
- out.write(intToBytes(run));
- out.write(intToBytes(block));
+ if (run >= 0xFF || newValue != block) {
+ out.write(run);
+ out.write(block);
run = 0;
block = dict.get(blocks[y].getParams().getKey());
}
run++;
}
- out.write(intToBytes(run));
- out.write(intToBytes(block));
+ out.write(run);
+ out.write(block);
}
out.flush();
DataInputStream in = new DataInputStream(file.read());
- version = in.readInt();
+ version = in.readByte();
if (SAVE_VERSION == version) {
width = in.readInt();
map = new Block[width][height];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x += run) {
- run = in.readInt();
- block = in.readInt();
+ run = in.readUnsignedByte();
+ block = in.readUnsignedByte();
for (int i = x; i < x + run; i++) {
map[i][y] = gameItemsHolder.getBlock(dict[block]);
}
diff --git a/core/src/ru/deadsoftware/cavedroid/game/debug/DebugInfoStringsProvider.kt b/core/src/ru/deadsoftware/cavedroid/game/debug/DebugInfoStringsProvider.kt
--- /dev/null
@@ -0,0 +1,37 @@
+package ru.deadsoftware.cavedroid.game.debug
+
+import com.badlogic.gdx.Gdx
+import ru.deadsoftware.cavedroid.game.GameInput
+import ru.deadsoftware.cavedroid.game.GameScope
+import ru.deadsoftware.cavedroid.game.mobs.MobsController
+import ru.deadsoftware.cavedroid.game.objects.DropController
+import ru.deadsoftware.cavedroid.game.world.GameWorld
+import javax.inject.Inject
+
+@GameScope
+class DebugInfoStringsProvider @Inject constructor(
+ private val mobsController: MobsController,
+ private val gameInput: GameInput,
+ private val dropController: DropController,
+ private val gameWorld: GameWorld
+) {
+
+ fun getDebugStrings(): List<String> {
+ val player = mobsController.player
+
+ return listOf(
+ "FPS: ${Gdx.graphics.framesPerSecond}",
+ "X: ${player.mapX}",
+ "Y: ${player.upperMapY}",
+ "CurX: ${gameInput.curX}",
+ "CurY: ${gameInput.curY}",
+ "Velocity: ${player.velocity}",
+ "Swim: ${player.swim}",
+ "Mobs: ${mobsController.mobs.size}",
+ "Drops: ${dropController.size}",
+ "Block: ${gameWorld.getForeMap(gameInput.curX, gameInput.curY).params.key}",
+ "Hand: ${player.inventory[player.slot].item.params.key}",
+ "Game mode: ${player.gameMode}"
+ )
+ }
+}
\ No newline at end of file
diff --git a/core/src/ru/deadsoftware/cavedroid/game/mobs/Player.java b/core/src/ru/deadsoftware/cavedroid/game/mobs/Player.java
index bce9a2c435a0da4e2d81c794af791f95f55d9a49..9972617b5364156afb13e4b35736be8c56251868 100644 (file)
private void drawItem(SpriteBatch spriteBatch, float x, float y, float anim) {
final Item item = inventory(slot);
- if (item == null || item.getParams().getKey().equals(GameItemsHolder.FALLBACK_ITEM_KEY)) {
+ if (item == null || item.isNone()) {
return;
}
diff --git a/core/src/ru/deadsoftware/cavedroid/game/model/block/Block.kt b/core/src/ru/deadsoftware/cavedroid/game/model/block/Block.kt
index 2411a6352d963823bb921f1a8a741172150fddfb..4a0c31a4a4fa7e7038284aa5b3b9776412c99c03 100644 (file)
return this is Slab
}
+ fun isNone(): Boolean {
+ contract { returns(true) implies (this@Block is None) }
+ return this is None
+ }
+
fun getRectangle(x: Int, y: Int): Rectangle {
return Rectangle(
/* x = */ x * 16f + params.collisionMargins.left,
)
}
-
+ data class None(
+ override val params: CommonBlockParams
+ ) : Block()
data class Normal(
override val params: CommonBlockParams,
@Deprecated(LEGACY_ACCESSOR_DEPRECATION) fun isTransparent() = params.isTransparent
@Deprecated(LEGACY_ACCESSOR_DEPRECATION) fun getTexture() = sprite
-
companion object {
private const val LEGACY_ACCESSOR_DEPRECATION = "legacy accessors will be removed"
private const val ANIMATION_FRAME_DURATION_MS = 100L
diff --git a/core/src/ru/deadsoftware/cavedroid/game/model/item/Item.kt b/core/src/ru/deadsoftware/cavedroid/game/model/item/Item.kt
index fe2bc46bad46030cd43eb0a74f284fa4bd8f4629..80a96251442ebd6bafb924b22044d4b24df703eb 100644 (file)
package ru.deadsoftware.cavedroid.game.model.item
+import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.g2d.Sprite
import ru.deadsoftware.cavedroid.game.model.block.Block
import kotlin.contracts.ExperimentalContracts
return params.key == (other as Item).params.key
}
+ fun isNone(): Boolean {
+ contract { returns(true) implies (this@Item is None) }
+ return this is None
+ }
+
fun isPlaceable(): Boolean {
contract { returns(true) implies (this@Item is Placeable) }
return this is Placeable
sealed class Usable : Item() {
abstract val useActionKey: String
}
-
+
+ data class None(
+ override val params: CommonItemParams,
+ ): Item() {
+ override val sprite: Sprite
+ get() = throw IllegalAccessException("Trying to get sprite of None")
+ }
+
data class Placeable(
override val params: CommonItemParams,
val block: Block
diff --git a/core/src/ru/deadsoftware/cavedroid/game/model/mapper/BlockMapper.kt b/core/src/ru/deadsoftware/cavedroid/game/model/mapper/BlockMapper.kt
index eb3080fd876233630c269753582beacca3ce9df6..cae219f00c053b679141776e2ec8a67b40395bf1 100644 (file)
"water" -> Water(commonBlockParams, requireNotNull(dto.state))
"lava" -> Lava(commonBlockParams, requireNotNull(dto.state))
"slab" -> Slab(commonBlockParams, requireNotNull(dto.fullBlock))
+ "none" -> None(commonBlockParams)
else -> Normal(commonBlockParams)
}
}
diff --git a/core/src/ru/deadsoftware/cavedroid/game/model/mapper/ItemMapper.kt b/core/src/ru/deadsoftware/cavedroid/game/model/mapper/ItemMapper.kt
index 311c10c838b3fe33b6d92d3af93cb68b9b12d138..ad79cbd824e01f6b0308f3d04e190f9952f16f29 100644 (file)
"shovel" -> Shovel(params, requireNotNull(loadSprite(dto)), dto.mobDamageMultiplier, dto.blockDamageMultiplier)
"sword" -> Sword(params, requireNotNull(loadSprite(dto)), dto.mobDamageMultiplier, dto.blockDamageMultiplier)
"block" -> Placeable(params, requireNotNull(block))
+ "none" -> None(params)
else -> throw IllegalArgumentException("Unknown item type ${dto.type}")
}
}
}
private fun loadSprite(dto: ItemDto): Sprite? {
- if (dto.type == "block" || dto.texture == GameItemsHolder.FALLBACK_ITEM_KEY) {
+ if (dto.type == "none" || dto.type == "block" || dto.texture == GameItemsHolder.FALLBACK_ITEM_KEY) {
return null
}
diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/BackgroundBlocksRenderer.kt b/core/src/ru/deadsoftware/cavedroid/game/render/BackgroundBlocksRenderer.kt
--- /dev/null
@@ -0,0 +1,51 @@
+package ru.deadsoftware.cavedroid.game.render
+
+import com.badlogic.gdx.Gdx
+import com.badlogic.gdx.graphics.GL20
+import com.badlogic.gdx.graphics.g2d.SpriteBatch
+import com.badlogic.gdx.graphics.glutils.ShapeRenderer
+import com.badlogic.gdx.math.Rectangle
+import ru.deadsoftware.cavedroid.game.GameInput
+import ru.deadsoftware.cavedroid.game.GameScope
+import ru.deadsoftware.cavedroid.game.world.GameWorld
+import ru.deadsoftware.cavedroid.misc.utils.forEachBlockInArea
+import javax.inject.Inject
+
+@GameScope
+class BackgroundBlocksRenderer @Inject constructor(
+ gameWorld: GameWorld,
+ gameInput: GameInput
+) : BlocksRenderer(gameWorld, gameInput) {
+
+ override val renderLayer get() = RENDER_LAYER
+
+ override val background = true
+
+ override fun draw(spriteBatch: SpriteBatch, shapeRenderer: ShapeRenderer, viewport: Rectangle, delta: Float) {
+ forEachBlockInArea(viewport) { x, y ->
+ drawBackMap(spriteBatch, viewport, x, y)
+ }
+
+ spriteBatch.end()
+ Gdx.gl.glEnable(GL20.GL_BLEND)
+ Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA)
+ shapeRenderer.begin(ShapeRenderer.ShapeType.Filled)
+ shapeRenderer.setColor(0f, 0f, 0f, .5f)
+
+ forEachBlockInArea(viewport) { x, y ->
+ shadeBackMap(shapeRenderer, viewport, x, y)
+ }
+
+ shapeRenderer.end()
+ Gdx.gl.glDisable(GL20.GL_BLEND)
+ spriteBatch.begin()
+
+ forEachBlockInArea(viewport) { x, y ->
+ drawForeMap(spriteBatch, viewport, x, y)
+ }
+ }
+
+ companion object {
+ private const val RENDER_LAYER = 100000
+ }
+}
\ No newline at end of file
diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/BlocksRenderer.kt b/core/src/ru/deadsoftware/cavedroid/game/render/BlocksRenderer.kt
--- /dev/null
@@ -0,0 +1,101 @@
+package ru.deadsoftware.cavedroid.game.render
+
+import com.badlogic.gdx.graphics.g2d.SpriteBatch
+import com.badlogic.gdx.graphics.g2d.TextureRegion
+import com.badlogic.gdx.graphics.glutils.ShapeRenderer
+import com.badlogic.gdx.math.Rectangle
+import ru.deadsoftware.cavedroid.game.GameInput
+import ru.deadsoftware.cavedroid.game.model.block.Block
+import ru.deadsoftware.cavedroid.game.world.GameWorld
+import ru.deadsoftware.cavedroid.misc.Assets
+import ru.deadsoftware.cavedroid.misc.utils.px
+
+abstract class BlocksRenderer(
+ protected val gameWorld: GameWorld,
+ protected val gameInput: GameInput,
+) : IGameRenderer {
+
+ protected abstract val background: Boolean
+
+ private val Block.canSeeThrough
+ get() = isNone() || params.isTransparent
+
+ private fun blockDamageTexture(index: Int): TextureRegion? {
+ if (index !in 0..MAX_BLOCK_DAMAGE_INDEX) {
+ return null
+ }
+ val textureKey = "$BLOCK_DAMAGE_TEXTURE_PREFIX$index"
+ return Assets.textureRegions[textureKey]
+ }
+
+ private fun drawBlockDamage(spriteBatch: SpriteBatch, block: Block, x: Float, y: Float) {
+ val blockDamage = gameInput.blockDamage
+ if (blockDamage <= 0) {
+ return
+ }
+
+ val index = MAX_BLOCK_DAMAGE_INDEX * (blockDamage / block.params.hitPoints)
+ val texture = blockDamageTexture(index) ?: return
+
+ spriteBatch.draw(texture, x, y)
+ }
+
+ protected fun shadeBackMap(
+ shapeRenderer: ShapeRenderer,
+ viewport: Rectangle,
+ x: Int,
+ y: Int
+ ) {
+ val foregroundBlock = gameWorld.getForeMap(x, y)
+ val backgroundBlock = gameWorld.getBackMap(x, y)
+
+ if (foregroundBlock.canSeeThrough && !backgroundBlock.isNone()) {
+ val drawX = x.px - viewport.x
+ val drawY = y.px - viewport.y
+ val marginLeft = backgroundBlock.params.spriteMargins.left
+ val marginTop = backgroundBlock.params.spriteMargins.top
+
+ shapeRenderer.rect(
+ /* x = */ drawX + marginLeft,
+ /* y = */ drawY + marginTop,
+ /* width = */ backgroundBlock.width,
+ /* height = */ backgroundBlock.height
+ )
+ }
+ }
+
+ protected fun drawBackMap(spriteBatch: SpriteBatch, viewport: Rectangle, x: Int, y: Int) {
+ val foregroundBlock = gameWorld.getForeMap(x, y)
+ val backgroundBlock = gameWorld.getBackMap(x, y)
+
+ if (foregroundBlock.canSeeThrough && !backgroundBlock.isNone()) {
+ val drawX = x.px - viewport.x
+ val drawY = y.px - viewport.y
+ backgroundBlock.draw(spriteBatch, drawX, drawY)
+
+ if (foregroundBlock.isNone()) {
+ drawBlockDamage(spriteBatch, backgroundBlock, drawX, drawY)
+ }
+ }
+ }
+
+ protected fun drawForeMap(spriteBatch: SpriteBatch, viewport: Rectangle, x: Int, y: Int) {
+ val foregroundBlock = gameWorld.getForeMap(x, y)
+
+ if (!foregroundBlock.isNone() && foregroundBlock.params.isBackground == background) {
+ val drawX = x.px - viewport.x
+ val drawY = y.px - viewport.y
+ foregroundBlock.draw(spriteBatch, drawX, drawY)
+
+ if (!foregroundBlock.isNone()) {
+ drawBlockDamage(spriteBatch, foregroundBlock, drawX, drawY)
+ }
+ }
+ }
+
+ companion object {
+ private const val BLOCK_DAMAGE_TEXTURE_PREFIX = "break_"
+ private const val MAX_BLOCK_DAMAGE_INDEX = 10
+ }
+
+}
\ No newline at end of file
diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/DebugRenderer.kt b/core/src/ru/deadsoftware/cavedroid/game/render/DebugRenderer.kt
--- /dev/null
@@ -0,0 +1,117 @@
+package ru.deadsoftware.cavedroid.game.render
+
+import com.badlogic.gdx.graphics.Color
+import com.badlogic.gdx.graphics.g2d.SpriteBatch
+import com.badlogic.gdx.graphics.glutils.ShapeRenderer
+import com.badlogic.gdx.math.Rectangle
+import ru.deadsoftware.cavedroid.MainConfig
+import ru.deadsoftware.cavedroid.game.GameScope
+import ru.deadsoftware.cavedroid.game.debug.DebugInfoStringsProvider
+import ru.deadsoftware.cavedroid.game.mobs.MobsController
+import ru.deadsoftware.cavedroid.game.model.block.Block
+import ru.deadsoftware.cavedroid.game.world.GameWorld
+import ru.deadsoftware.cavedroid.misc.Assets
+import ru.deadsoftware.cavedroid.misc.utils.bl
+import ru.deadsoftware.cavedroid.misc.utils.forEachBlockInArea
+import ru.deadsoftware.cavedroid.misc.utils.px
+import javax.inject.Inject
+
+@GameScope
+class DebugRenderer @Inject constructor(
+ private val mainConfig: MainConfig,
+ private val gameWorld: GameWorld,
+ private val mobsController: MobsController,
+ private val debugInfoStringsProvider: DebugInfoStringsProvider,
+) : IGameRenderer {
+
+ override val renderLayer get() = RENDER_LAYER
+
+ private fun SpriteBatch.drawString(str: String, x: Float, y: Float) {
+ Assets.minecraftFont.draw(this, str, x, y)
+ }
+
+ private fun getMinimapColor(x: Int, y: Int): Color? {
+ val foregroundBlock = gameWorld.getForeMap(x, y)
+
+ return if (!foregroundBlock.isNone()) {
+ when (foregroundBlock) {
+ is Block.Water -> Color.BLUE
+ is Block.Lava -> Color.RED
+ else -> Color.BLACK
+ }
+ } else if (gameWorld.hasBackAt(x, y)) {
+ Color.DARK_GRAY
+ } else {
+ null
+ }
+ }
+
+ private fun drawMinimap(
+ spriteBatch: SpriteBatch,
+ shapeRenderer: ShapeRenderer,
+ minimapX: Float,
+ minimapY: Float,
+ minimapSize: Float
+ ) {
+ val mapArea = Rectangle(
+ /* x = */ mobsController.player.x - (minimapSize.px / 2),
+ /* y = */ mobsController.player.y - (minimapSize.px / 2),
+ /* width = */ minimapSize.px,
+ /* height = */ minimapSize.px
+ )
+
+ spriteBatch.end()
+ shapeRenderer.begin(ShapeRenderer.ShapeType.Filled)
+ shapeRenderer.color = Color.LIGHT_GRAY
+ shapeRenderer.rect(minimapX, minimapY, minimapSize, minimapSize)
+
+ forEachBlockInArea(mapArea) { x, y ->
+ getMinimapColor(x, y)?.let { color ->
+ shapeRenderer.setColor(color)
+ shapeRenderer.rect(
+ /* x = */ minimapX + (x - mapArea.x.bl),
+ /* y = */ minimapY + (y - mapArea.y.bl),
+ /* width = */ 1f,
+ /* height = */ 1f
+ )
+ }
+ }
+
+ shapeRenderer.color = Color.OLIVE
+ shapeRenderer.rect(minimapX + minimapSize / 2, minimapY + minimapSize / 2, 1f, 2f)
+ shapeRenderer.end()
+ spriteBatch.begin()
+ }
+
+ private fun drawDebugInfo(spriteBatch: SpriteBatch) {
+ debugInfoStringsProvider.getDebugStrings().forEachIndexed { index, str ->
+ spriteBatch.drawString(str, 0f, index * 10f)
+ }
+ }
+
+ override fun draw(spriteBatch: SpriteBatch, shapeRenderer: ShapeRenderer, viewport: Rectangle, delta: Float) {
+ if (mainConfig.isShowInfo) {
+ drawDebugInfo(spriteBatch)
+ }
+
+ if (mainConfig.isShowMap) {
+ drawMinimap(
+ spriteBatch = spriteBatch,
+ shapeRenderer = shapeRenderer,
+ minimapX = viewport.width - MinimapConfig.margin - MinimapConfig.size,
+ minimapY = MinimapConfig.margin,
+ minimapSize = MinimapConfig.size
+ )
+ }
+
+ }
+
+ companion object {
+ private const val RENDER_LAYER = Int.MAX_VALUE
+
+ private data object MinimapConfig {
+ const val margin = 24f
+ const val size = 64f
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/DropsRenderer.kt b/core/src/ru/deadsoftware/cavedroid/game/render/DropsRenderer.kt
--- /dev/null
@@ -0,0 +1,39 @@
+package ru.deadsoftware.cavedroid.game.render
+
+import com.badlogic.gdx.graphics.g2d.SpriteBatch
+import com.badlogic.gdx.graphics.glutils.ShapeRenderer
+import com.badlogic.gdx.math.Rectangle
+import ru.deadsoftware.cavedroid.game.GameScope
+import ru.deadsoftware.cavedroid.game.objects.DropController
+import ru.deadsoftware.cavedroid.game.world.GameWorld
+import ru.deadsoftware.cavedroid.misc.utils.cycledInsideWorld
+import ru.deadsoftware.cavedroid.misc.utils.drawSprite
+import ru.deadsoftware.cavedroid.misc.utils.px
+import javax.inject.Inject
+
+@GameScope
+class DropsRenderer @Inject constructor(
+ private val dropController: DropController,
+ private val gameWorld: GameWorld,
+) : IGameRenderer {
+
+ override val renderLayer = RENDER_LAYER
+
+ override fun draw(spriteBatch: SpriteBatch, shapeRenderer: ShapeRenderer, viewport: Rectangle, delta: Float) {
+ dropController.forEach { drop ->
+ drop.cycledInsideWorld(viewport, gameWorld.width.px)?.let { dropRect ->
+ drop.item.sprite.setSize(dropRect.width, dropRect.height)
+ spriteBatch.drawSprite(
+ sprite = drop.item.sprite,
+ x = dropRect.x - viewport.x,
+ y = dropRect.y - viewport.y,
+ )
+ }
+ }
+ }
+
+ companion object {
+ private const val RENDER_LAYER = 100200
+ }
+
+}
\ No newline at end of file
diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/ForegroundBlocksRenderer.kt b/core/src/ru/deadsoftware/cavedroid/game/render/ForegroundBlocksRenderer.kt
--- /dev/null
@@ -0,0 +1,31 @@
+package ru.deadsoftware.cavedroid.game.render
+
+import com.badlogic.gdx.graphics.g2d.SpriteBatch
+import com.badlogic.gdx.graphics.glutils.ShapeRenderer
+import com.badlogic.gdx.math.Rectangle
+import ru.deadsoftware.cavedroid.game.GameInput
+import ru.deadsoftware.cavedroid.game.GameScope
+import ru.deadsoftware.cavedroid.game.world.GameWorld
+import ru.deadsoftware.cavedroid.misc.utils.forEachBlockInArea
+import javax.inject.Inject
+
+@GameScope
+class ForegroundBlocksRenderer @Inject constructor(
+ gameWorld: GameWorld,
+ gameInput: GameInput
+) : BlocksRenderer(gameWorld, gameInput) {
+
+ override val renderLayer get() = RENDER_LAYER
+
+ override val background = false
+
+ override fun draw(spriteBatch: SpriteBatch, shapeRenderer: ShapeRenderer, viewport: Rectangle, delta: Float) {
+ forEachBlockInArea(viewport) { x, y ->
+ drawForeMap(spriteBatch, viewport, x, y)
+ }
+ }
+
+ companion object {
+ private const val RENDER_LAYER = 100400
+ }
+}
\ No newline at end of file
diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/HudRenderer.kt b/core/src/ru/deadsoftware/cavedroid/game/render/HudRenderer.kt
--- /dev/null
@@ -0,0 +1,121 @@
+package ru.deadsoftware.cavedroid.game.render
+
+import com.badlogic.gdx.graphics.g2d.SpriteBatch
+import com.badlogic.gdx.graphics.glutils.ShapeRenderer
+import com.badlogic.gdx.math.Rectangle
+import ru.deadsoftware.cavedroid.game.GameInput
+import ru.deadsoftware.cavedroid.game.GameScope
+import ru.deadsoftware.cavedroid.game.mobs.MobsController
+import ru.deadsoftware.cavedroid.game.model.item.InventoryItem
+import ru.deadsoftware.cavedroid.game.world.GameWorld
+import ru.deadsoftware.cavedroid.misc.Assets
+import ru.deadsoftware.cavedroid.misc.ControlMode
+import ru.deadsoftware.cavedroid.misc.utils.px
+import javax.inject.Inject
+
+@GameScope
+class HudRenderer @Inject constructor(
+ private val gameInput: GameInput,
+ private val gameWorld: GameWorld,
+ private val mobsController: MobsController,
+) : IGameRenderer {
+
+ override val renderLayer = RENDER_LAYER
+
+ private val cursorTexture get() = requireNotNull(Assets.textureRegions[CURSOR_KEY])
+ private val hotbarTexture get() = requireNotNull(Assets.textureRegions[HOTBAR_KEY])
+ private val hotbarSelectorTexture get() = requireNotNull(Assets.textureRegions[HOTBAR_SELECTOR_KEY])
+ private val wholeHeartTexture get() = requireNotNull(Assets.textureRegions[WHOLE_HEART_KEY])
+ private val halfHeartTexture get() = requireNotNull(Assets.textureRegions[HALF_HEART_KEY])
+
+ private fun drawCursor(spriteBatch: SpriteBatch, viewport: Rectangle) {
+ if (gameWorld.hasForeAt(gameInput.curX, gameInput.curY) ||
+ gameWorld.hasBackAt(gameInput.curX, gameInput.curY) ||
+ gameInput.controlMode == ControlMode.CURSOR
+ ) {
+ spriteBatch.draw(cursorTexture, gameInput.curX.px - viewport.x, gameInput.curY.px - viewport.y)
+ }
+ }
+
+ private fun drawHealth(spriteBatch: SpriteBatch, x: Float, y: Float) {
+ val player = mobsController.player
+
+ if (player.gameMode == 1) {
+ return
+ }
+
+ val wholeHeart = wholeHeartTexture
+ val wholeHearts = player.health / 2
+
+ for (i in 0..<wholeHearts) {
+ spriteBatch.draw(wholeHeart, x + i * wholeHeart.regionWidth, y)
+ }
+
+ if (player.health % 2 == 1) {
+ spriteBatch.draw(halfHeartTexture, x + wholeHearts * wholeHeart.regionWidth, y)
+ }
+ }
+
+ private fun drawHotbarItems(spriteBatch: SpriteBatch, hotbarX: Float) {
+ mobsController.player.inventory.asSequence()
+ .map(InventoryItem::item)
+ .forEachIndexed { index, item ->
+ if (item.isNone()) {
+ return@forEachIndexed
+ }
+
+ spriteBatch.draw(
+ /* region = */ item.sprite,
+ /* x = */ hotbarX + HotbarConfig.horizontalMargin
+ + index * (HotbarConfig.itemSeparatorWidth + HotbarConfig.itemSlotSpace),
+ /* y = */ HotbarConfig.verticalMargin,
+ )
+ }
+ }
+
+ private fun drawHotbarSelector(spriteBatch: SpriteBatch, hotbarX: Float) {
+ spriteBatch.draw(
+ /* region = */ hotbarSelectorTexture,
+ /* x = */ hotbarX - HotbarSelectorConfig.horizontalPadding
+ + mobsController.player.slot * (HotbarConfig.itemSeparatorWidth + HotbarConfig.itemSlotSpace),
+ /* y = */ -HotbarSelectorConfig.verticalPadding
+ )
+ }
+
+ private fun drawHotbar(spriteBatch: SpriteBatch, viewport: Rectangle) {
+ val hotbar = hotbarTexture
+ val hotbarX = viewport.width / 2 - hotbar.regionWidth / 2
+
+ spriteBatch.draw(hotbar, hotbarX, 0f)
+ drawHealth(spriteBatch, hotbarX, hotbarTexture.regionHeight.toFloat())
+ drawHotbarItems(spriteBatch, hotbarX)
+ drawHotbarSelector(spriteBatch, hotbarX)
+ }
+
+ override fun draw(spriteBatch: SpriteBatch, shapeRenderer: ShapeRenderer, viewport: Rectangle, delta: Float) {
+ drawCursor(spriteBatch, viewport)
+ drawHotbar(spriteBatch, viewport)
+ }
+
+ companion object {
+ private const val RENDER_LAYER = 100500
+
+ private const val CURSOR_KEY = "cursor"
+ private const val HOTBAR_KEY = "hotbar"
+ private const val HOTBAR_SELECTOR_KEY = "hotbar_selector"
+ private const val WHOLE_HEART_KEY = "heart_whole"
+ private const val HALF_HEART_KEY = "heart_half"
+
+ private data object HotbarConfig {
+ const val horizontalMargin = 3f
+ const val verticalMargin = 3f
+ const val itemSeparatorWidth = 4f
+ const val itemSlotSpace = 16f
+ }
+
+ private data object HotbarSelectorConfig {
+ const val horizontalPadding = 1f
+ const val verticalPadding = 1f
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/IGameRenderer.kt b/core/src/ru/deadsoftware/cavedroid/game/render/IGameRenderer.kt
--- /dev/null
@@ -0,0 +1,20 @@
+package ru.deadsoftware.cavedroid.game.render
+
+import com.badlogic.gdx.graphics.g2d.SpriteBatch
+import com.badlogic.gdx.graphics.glutils.ShapeRenderer
+import com.badlogic.gdx.math.Rectangle
+
+interface IGameRenderer {
+
+ val renderLayer: Int
+
+ /**
+ * When called, [spriteBatch] is beginned!
+ */
+ fun draw(
+ spriteBatch: SpriteBatch,
+ shapeRenderer: ShapeRenderer,
+ viewport: Rectangle,
+ delta: Float
+ )
+}
\ No newline at end of file
diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/MobsRenderer.kt b/core/src/ru/deadsoftware/cavedroid/game/render/MobsRenderer.kt
--- /dev/null
@@ -0,0 +1,45 @@
+package ru.deadsoftware.cavedroid.game.render
+
+import com.badlogic.gdx.graphics.g2d.SpriteBatch
+import com.badlogic.gdx.graphics.glutils.ShapeRenderer
+import com.badlogic.gdx.math.Rectangle
+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.world.GameWorld
+import ru.deadsoftware.cavedroid.misc.utils.cycledInsideWorld
+import ru.deadsoftware.cavedroid.misc.utils.px
+import javax.inject.Inject
+
+@GameScope
+class MobsRenderer @Inject constructor(
+ private val mobsController: MobsController,
+ private val gameWorld: GameWorld,
+) : IGameRenderer {
+
+ override val renderLayer get() = RENDER_LAYER
+
+ private fun drawMob(spriteBatch: SpriteBatch, viewport: Rectangle, mob: Mob, delta: Float) {
+ mob.cycledInsideWorld(viewport, gameWorld.width.px)?.let { mobRect ->
+ mob.draw(spriteBatch, mobRect.x - viewport.x, mobRect.y - viewport.y, delta)
+ }
+ }
+
+ override fun draw(spriteBatch: SpriteBatch, shapeRenderer: ShapeRenderer, viewport: Rectangle, delta: Float) {
+ val player = mobsController.player
+ player.draw(
+ /* spriteBatch = */ spriteBatch,
+ /* x = */ player.x - viewport.x - player.width / 2,
+ /* y = */ player.y - viewport.y,
+ /* delta = */ delta
+ )
+
+ mobsController.mobs.forEach { mob ->
+ drawMob(spriteBatch, viewport, mob, delta)
+ }
+ }
+
+ companion object {
+ private const val RENDER_LAYER = 100100
+ }
+}
\ No newline at end of file
diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/RenderModule.kt b/core/src/ru/deadsoftware/cavedroid/game/render/RenderModule.kt
--- /dev/null
@@ -0,0 +1,54 @@
+package ru.deadsoftware.cavedroid.game.render
+
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.IntoSet
+import ru.deadsoftware.cavedroid.game.GameScope
+
+@Module
+object RenderModule {
+
+ @Binds
+ @IntoSet
+ @GameScope
+ fun bindBackGroundBlocksRenderer(renderer: BackgroundBlocksRenderer): IGameRenderer = renderer
+
+ @Binds
+ @IntoSet
+ @GameScope
+ fun bindForegroundBlocksRenderer(renderer: ForegroundBlocksRenderer): IGameRenderer = renderer
+
+ @Binds
+ @IntoSet
+ @GameScope
+ fun bindMobsRenderer(renderer: MobsRenderer): IGameRenderer = renderer
+
+ @Binds
+ @IntoSet
+ @GameScope
+ fun bindDropsRenderer(renderer: DropsRenderer): IGameRenderer = renderer
+
+ @Binds
+ @IntoSet
+ @GameScope
+ fun bindHudRenderer(renderer: HudRenderer): IGameRenderer = renderer
+
+ @Binds
+ @IntoSet
+ @GameScope
+ fun bindWindowsRenderer(renderer: WindowsRenderer): IGameRenderer = renderer
+
+ @Binds
+ @IntoSet
+ @GameScope
+ fun bindDebugRenderer(renderer: DebugRenderer): IGameRenderer = renderer
+
+// @Provides
+// @GameScope
+// fun provideGameRenderers(renderers: Set<@JvmSuppressWildcards IGameRenderer>): List<IGameRenderer> {
+// return renderers.asSequence()
+// .sortedWith(Comparator.comparingInt(IGameRenderer::renderLayer))
+// .toList()
+// }
+
+}
diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/TouchControlsRenderer.kt b/core/src/ru/deadsoftware/cavedroid/game/render/TouchControlsRenderer.kt
--- /dev/null
@@ -0,0 +1,50 @@
+package ru.deadsoftware.cavedroid.game.render
+
+import com.badlogic.gdx.graphics.g2d.SpriteBatch
+import com.badlogic.gdx.graphics.glutils.ShapeRenderer
+import com.badlogic.gdx.math.Rectangle
+import ru.deadsoftware.cavedroid.game.GameInput
+import ru.deadsoftware.cavedroid.game.GameScope
+import ru.deadsoftware.cavedroid.misc.Assets
+import ru.deadsoftware.cavedroid.misc.ControlMode
+import ru.deadsoftware.cavedroid.misc.utils.ArrayMapExtensions.component1
+import ru.deadsoftware.cavedroid.misc.utils.ArrayMapExtensions.component2
+import javax.inject.Inject
+
+@GameScope
+class TouchControlsRenderer @Inject constructor(
+ private val gameInput: GameInput
+) : IGameRenderer {
+
+ override val renderLayer get() = RENDER_LAYER
+
+ private val shadeTexture get() = Assets.textureRegions[SHADE_KEY]
+
+ override fun draw(spriteBatch: SpriteBatch, shapeRenderer: ShapeRenderer, viewport: Rectangle, delta: Float) {
+ val touchControlsMap = Assets.guiMap
+
+ touchControlsMap.forEach { (key, value) ->
+ val touchKey = value.rect
+ spriteBatch.draw(
+ /* region = */ Assets.textureRegions[key],
+ /* x = */ touchKey.x,
+ /* y = */ touchKey.y,
+ /* width = */ touchKey.width,
+ /* height = */ touchKey.height
+ )
+ }
+
+ // FIXME: Add pressed state for buttons
+ if (gameInput.controlMode == ControlMode.CURSOR) {
+ val altKeyRect = touchControlsMap.get("alt").rect
+ spriteBatch.draw(shadeTexture, altKeyRect.x, altKeyRect.y, altKeyRect.width, altKeyRect.height)
+ }
+ }
+
+ companion object {
+ private const val RENDER_LAYER = 100700
+
+ private const val SHADE_KEY = "shade"
+ }
+
+}
\ No newline at end of file
diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/WindowsRenderer.kt b/core/src/ru/deadsoftware/cavedroid/game/render/WindowsRenderer.kt
--- /dev/null
@@ -0,0 +1,34 @@
+package ru.deadsoftware.cavedroid.game.render
+
+import com.badlogic.gdx.Gdx
+import com.badlogic.gdx.graphics.g2d.SpriteBatch
+import com.badlogic.gdx.graphics.glutils.ShapeRenderer
+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.render.windows.CreativeWindowRenderer
+import javax.inject.Inject
+
+@GameScope
+class WindowsRenderer @Inject constructor(
+ private val mainConfig: MainConfig,
+ private val creativeWindowRenderer: CreativeWindowRenderer,
+) : IGameRenderer {
+
+ override val renderLayer get() = RENDER_LAYER
+
+ override fun draw(spriteBatch: SpriteBatch, shapeRenderer: ShapeRenderer, viewport: Rectangle, delta: Float) {
+ when (mainConfig.gameUiWindow) {
+ GameUiWindow.CREATIVE_INVENTORY -> creativeWindowRenderer.draw(spriteBatch, shapeRenderer, viewport, delta)
+ GameUiWindow.NONE -> return
+ else -> Gdx.app.error(TAG, "Cannot draw window: ${mainConfig.gameUiWindow.name}")
+ }
+ }
+
+ companion object {
+ private const val TAG = "WindowsRenderer"
+
+ const val RENDER_LAYER = 100600
+ }
+}
\ 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
--- /dev/null
@@ -0,0 +1,123 @@
+package ru.deadsoftware.cavedroid.game.render.windows
+
+import com.badlogic.gdx.graphics.g2d.SpriteBatch
+import com.badlogic.gdx.graphics.glutils.ShapeRenderer
+import com.badlogic.gdx.math.Rectangle
+import ru.deadsoftware.cavedroid.MainConfig
+import ru.deadsoftware.cavedroid.game.GameInput
+import ru.deadsoftware.cavedroid.game.GameItemsHolder
+import ru.deadsoftware.cavedroid.game.GameScope
+import ru.deadsoftware.cavedroid.game.mobs.MobsController
+import ru.deadsoftware.cavedroid.game.model.item.InventoryItem
+import ru.deadsoftware.cavedroid.game.render.IGameRenderer
+import ru.deadsoftware.cavedroid.game.render.WindowsRenderer
+import ru.deadsoftware.cavedroid.misc.Assets
+import javax.inject.Inject
+
+@GameScope
+class CreativeWindowRenderer @Inject constructor(
+ private val mainConfig: MainConfig,
+ private val gameInput: GameInput,
+ private val gameItemsHolder: GameItemsHolder,
+ private val mobsController: MobsController,
+) : 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, inventoryX: Float, inventoryY: Float) {
+ mobsController.player.inventory.asSequence()
+ .map(InventoryItem::item)
+ .forEachIndexed { index, item ->
+ if (item.isNone()) {
+ return@forEachIndexed
+ }
+
+ val itemX = inventoryX + index * CreativeWindowConfig.itemsGridColWidth
+
+ spriteBatch.draw(item.sprite, itemX, inventoryY)
+ }
+ }
+
+ private fun drawCreative(spriteBatch: SpriteBatch, viewport: Rectangle) {
+ val creativeWindow = creativeWindowTexture
+
+ val windowX = viewport.width / 2 - creativeWindow.regionWidth / 2
+ val windowY = viewport.height / 2 - creativeWindow.regionHeight / 2
+ val oneScrollAmount = CreativeWindowConfig.scrollIndicatorFullHeight / gameItemsHolder.getCreativeScrollAmount()
+
+ spriteBatch.draw(creativeWindow, windowX, windowY)
+ spriteBatch.draw(
+ /* region = */ scrollIndicatorTexture,
+ /* x = */ windowX + CreativeWindowConfig.scrollIndicatorMarginLeft,
+ /* y = */ windowY + CreativeWindowConfig.scrollIndicatorMarginTop
+ + (gameInput.creativeScroll * oneScrollAmount)
+ )
+
+ drawItemsGrid(
+ spriteBatch = spriteBatch,
+ gridX = windowX + CreativeWindowConfig.itemsGridMarginLeft,
+ gridY = windowY + CreativeWindowConfig.itemsGridMarginTop
+ )
+
+ drawPlayerInventory(
+ spriteBatch = spriteBatch,
+ inventoryX = windowX + CreativeWindowConfig.itemsGridMarginLeft,
+ inventoryY = windowY + creativeWindow.regionHeight - CreativeWindowConfig.playerInventoryOffsetFromBottom
+ )
+ }
+
+ override fun draw(spriteBatch: SpriteBatch, shapeRenderer: ShapeRenderer, viewport: Rectangle, delta: Float) {
+ drawCreative(spriteBatch, viewport)
+ }
+
+ companion object {
+ private const val CREATIVE_WINDOW_KEY = "creative"
+ private const val SCROLL_INDICATOR_KEY = "handle"
+
+ private data object CreativeWindowConfig {
+ const val scrollIndicatorMarginLeft = 156f
+ const val scrollIndicatorMarginTop = 18f
+ const val scrollIndicatorFullHeight = 72f
+
+ const val itemsGridMarginLeft = 8f
+ const val itemsGridMarginTop = 18f
+
+ const val itemsGridRowHeight = 18f
+ const val itemsGridColWidth = 18f
+
+ const val itemsInRow = 8
+ const val itemsInCol = 5
+
+ const val playerInventoryOffsetFromBottom = 24f
+
+ val itemsOnPage get() = itemsInCol * itemsInRow
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/src/ru/deadsoftware/cavedroid/game/world/GameWorld.java b/core/src/ru/deadsoftware/cavedroid/game/world/GameWorld.java
index 449c958da450fa3bb68901df527b0ebf473f7221..91793c845a23406745876c1fc0cad8ffb013a615 100644 (file)
import ru.deadsoftware.cavedroid.game.model.block.Block;
import ru.deadsoftware.cavedroid.game.model.world.generator.WorldGeneratorConfig;
import ru.deadsoftware.cavedroid.game.objects.DropController;
+import ru.deadsoftware.cavedroid.misc.utils.MeasureUnitsUtilsKt;
import javax.annotation.CheckForNull;
import javax.inject.Inject;
return mHeight;
}
+ /**
+ * @deprecated for kotlin use {@link MeasureUnitsUtilsKt#getPx } extension val
+ */
+ @Deprecated
public float getWidthPx() {
- return mWidth * 16f;
+ return MeasureUnitsUtilsKt.getPx(mWidth);
}
+ /**
+ * @deprecated for kotlin use {@link MeasureUnitsUtilsKt#getPx } extension val
+ */
+ @Deprecated
public float getHeightPx() {
- return mHeight * 16f;
+ return MeasureUnitsUtilsKt.getPx(mHeight);
}
public Block[][] getFullForeMap() {
diff --git a/core/src/ru/deadsoftware/cavedroid/game/world/GameWorldBlocksLogicControllerTask.kt b/core/src/ru/deadsoftware/cavedroid/game/world/GameWorldBlocksLogicControllerTask.kt
index f0f4af907499745719466741018db1abbc53f12a..387407a841e482fc85dd50a7ff8ab7af1c0f280c 100644 (file)
private fun updateBlock(x: Int, y: Int) {
val block = gameWorld.getForeMap(x, y)
+
+ if (block.isNone()) {
+ return
+ }
+
val blockKey = block.params.key
val action = updateBlockActions[blockKey]
?: updateBlockActions.getRequiresBlockAction().takeIf { block.params.requiresBlock }
diff --git a/core/src/ru/deadsoftware/cavedroid/misc/Assets.java b/core/src/ru/deadsoftware/cavedroid/misc/Assets.java
index d4f7a46936df1d249caa5d7b20adef9af150765b..cf87a0859cd666f3adda10c11ab57ec10c247ea1 100644 (file)
import ru.deadsoftware.cavedroid.game.objects.TouchButton;
import ru.deadsoftware.cavedroid.misc.utils.AssetLoader;
-import java.io.File;
-import java.io.FilenameFilter;
import java.util.HashMap;
import java.util.Map;
public static final HashMap<String, TextureRegion> textureRegions = new HashMap<>();
public static final ArrayMap<String, TouchButton> guiMap = new ArrayMap<>();
private static final GlyphLayout glyphLayout = new GlyphLayout();
- static BitmapFont minecraftFont;
+ public static BitmapFont minecraftFont;
public static Map<String, Texture> blockTextures = new HashMap<>();
public static Map<String, Texture> itemTextures = new HashMap<>();
diff --git a/core/src/ru/deadsoftware/cavedroid/misc/Renderer.java b/core/src/ru/deadsoftware/cavedroid/misc/Renderer.java
index 290f7ce266539045df9cd352d76dac273719cfc2..c2577d36e4940a996468b3dbb382369b19eb000d 100644 (file)
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
+import com.badlogic.gdx.math.Rectangle;
public abstract class Renderer implements InputProcessor {
protected final ShapeRenderer shaper;
protected final SpriteBatch spriter;
private final OrthographicCamera camera;
+ private final Rectangle mCameraViewport;
protected Renderer() {
this(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
shaper.setProjectionMatrix(camera.combined);
spriter = new SpriteBatch();
spriter.setProjectionMatrix(camera.combined);
+
+ mCameraViewport =
+ new Rectangle(camera.position.x, camera.position.y, camera.viewportWidth, camera.viewportHeight);
}
public float getWidth() {
public void setCamPos(float x, float y) {
camera.position.set(x, y, 0);
+ mCameraViewport.x = x;
+ mCameraViewport.y = y;
+ }
+
+ public Rectangle getCameraViewport() {
+ return mCameraViewport;
}
public void setFontScale(float scale) {
diff --git a/core/src/ru/deadsoftware/cavedroid/misc/utils/ArrayMapExtensions.kt b/core/src/ru/deadsoftware/cavedroid/misc/utils/ArrayMapExtensions.kt
--- /dev/null
@@ -0,0 +1,9 @@
+package ru.deadsoftware.cavedroid.misc.utils
+
+import com.badlogic.gdx.utils.ObjectMap
+
+object ArrayMapExtensions {
+ operator fun <K, V> ObjectMap.Entry<K, V>.component1(): K = this.key
+
+ operator fun <K, V> ObjectMap.Entry<K, V>.component2(): V = this.value
+}
diff --git a/core/src/ru/deadsoftware/cavedroid/misc/utils/MeasureUnitsUtils.kt b/core/src/ru/deadsoftware/cavedroid/misc/utils/MeasureUnitsUtils.kt
--- /dev/null
@@ -0,0 +1,18 @@
+package ru.deadsoftware.cavedroid.misc.utils
+
+import com.badlogic.gdx.math.MathUtils
+
+/**
+ * Converts this value in BLOCKS into pixels
+ */
+val Float.px get() = this * 16f
+
+/**
+ * Converts this value in BLOCKS into pixels
+ */
+val Int.px get() = this * 16f
+
+/**
+ * Converts this value in PIXELS into blocks
+ */
+val Float.bl get() = MathUtils.floor(this / 16)
\ No newline at end of file
diff --git a/core/src/ru/deadsoftware/cavedroid/misc/utils/RenderingUtils.kt b/core/src/ru/deadsoftware/cavedroid/misc/utils/RenderingUtils.kt
--- /dev/null
@@ -0,0 +1,42 @@
+package ru.deadsoftware.cavedroid.misc.utils
+
+import com.badlogic.gdx.math.Rectangle
+
+private fun Rectangle.shifted(shift: Float) = Rectangle(x + shift, y, width, height)
+
+private fun Rectangle.getLazyShifts(worldWidthPx: Float)
+ = Triple(
+ first = lazy { shifted(0f) },
+ second = lazy { shifted(-worldWidthPx) },
+ third = lazy { shifted(worldWidthPx) }
+ )
+
+fun Rectangle.cycledInsideWorld(
+ viewport: Rectangle,
+ worldWidthPx: Float,
+): Rectangle? {
+ val (notShifted, shiftedLeft, shiftedRight) = getLazyShifts(worldWidthPx)
+
+ return when {
+ viewport.overlaps(notShifted.value) -> notShifted.value
+ viewport.overlaps(shiftedLeft.value) -> shiftedLeft.value
+ viewport.overlaps(shiftedRight.value) -> shiftedRight.value
+ else -> null
+ }
+}
+
+fun forEachBlockInArea(
+ area: Rectangle,
+ func: (x: Int, y: Int) -> Unit
+) {
+ val startMapX = area.x.bl
+ val endMapX = startMapX + area.width.bl + 1
+ val startMapY = area.y.bl
+ val endMapY = startMapY + area.height.bl + 1
+
+ for (x in startMapX..endMapX) {
+ for (y in startMapY..endMapY) {
+ func(x, y)
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/src/ru/deadsoftware/cavedroid/misc/utils/SpriteUtils.kt b/core/src/ru/deadsoftware/cavedroid/misc/utils/SpriteUtils.kt
index 7d7aae110b22aa7a02b2c571fd1481906012cfd3..fd186e5a400e558a338895c01ebc45f20a34e97c 100644 (file)
* Draw sprite at given position rotated by [rotation] degrees
*/
@JvmOverloads
-fun SpriteBatch.drawSprite(sprite: Sprite, x: Float, y: Float, rotation: Float = 0f) {
+fun SpriteBatch.drawSprite(
+ sprite: Sprite,
+ x: Float,
+ y: Float,
+ rotation: Float = 0f
+) {
sprite.rotation = rotation
sprite.setPosition(x, y)
sprite.draw(this)
diff --git a/desktop/build.gradle b/desktop/build.gradle
index 94e48c3ebf7ff14595b2d925a2770d567a44479a..3436d706d7d6b68dda0a0bdfba095c7614331abe 100644 (file)
--- a/desktop/build.gradle
+++ b/desktop/build.gradle
standardInput = System.in
workingDir = project.assetsDir
ignoreExitValue = true as JavaExecSpec
- args "--touch --debug"
+ args "--touch", "--debug"
}
task debug(dependsOn: classes, type: JavaExec) {