From 8b09d71a44e44f2ed244f4137a2c4b79ffd7712e Mon Sep 17 00:00:00 2001 From: jzitnik-dev Date: Wed, 26 Mar 2025 11:31:25 +0100 Subject: [PATCH] feat(gameplay): Added day-night cycle --- src/main/java/cz/jzitnik/game/Game.java | 2 ++ .../handlers/place/DefaultPlaceHandler.java | 1 + .../game/handlers/place/PlaceHandler.java | 8 ++++- .../logic/services/daytime/DayTimeLogic.java | 19 +++++++++++ .../java/cz/jzitnik/game/sprites/Air.java | 32 ++++++++++++------- .../java/cz/jzitnik/tui/ScreenRenderer.java | 19 ++++++++--- 6 files changed, 65 insertions(+), 16 deletions(-) create mode 100644 src/main/java/cz/jzitnik/game/logic/services/daytime/DayTimeLogic.java diff --git a/src/main/java/cz/jzitnik/game/Game.java b/src/main/java/cz/jzitnik/game/Game.java index 92f184c..55411fa 100644 --- a/src/main/java/cz/jzitnik/game/Game.java +++ b/src/main/java/cz/jzitnik/game/Game.java @@ -45,6 +45,8 @@ public class Game extends AutoTransientSupport { private transient EntitySpawnProvider entitySpawnProvider = new EntitySpawnProvider(); @AutoTransient private transient GameStates gameStates = new GameStates(this); + @Setter + private int daytime = 0; // 0-600 public Game() { Generation.generateWorld(this); diff --git a/src/main/java/cz/jzitnik/game/handlers/place/DefaultPlaceHandler.java b/src/main/java/cz/jzitnik/game/handlers/place/DefaultPlaceHandler.java index 1bb43ae..b45f8c1 100644 --- a/src/main/java/cz/jzitnik/game/handlers/place/DefaultPlaceHandler.java +++ b/src/main/java/cz/jzitnik/game/handlers/place/DefaultPlaceHandler.java @@ -26,6 +26,7 @@ public class DefaultPlaceHandler implements CustomPlaceHandler { public boolean mine(Game game, int x, int y) { var blocks = game.getWorld()[y][x]; + log.info("Block was mined at coordinates x:{},y:{}", x, y); blocks.removeAll(blocks.stream().filter(i -> !i.getBlockId().equals("air") && !i.isMob()).toList()); return true; diff --git a/src/main/java/cz/jzitnik/game/handlers/place/PlaceHandler.java b/src/main/java/cz/jzitnik/game/handlers/place/PlaceHandler.java index daf1379..f0194be 100644 --- a/src/main/java/cz/jzitnik/game/handlers/place/PlaceHandler.java +++ b/src/main/java/cz/jzitnik/game/handlers/place/PlaceHandler.java @@ -6,8 +6,11 @@ import java.util.List; import java.util.Set; import cz.jzitnik.game.annotations.*; +import lombok.extern.slf4j.Slf4j; + import org.reflections.Reflections; +@Slf4j public class PlaceHandler { private final HashMap placeHandlerList = new HashMap<>(); private final CustomPlaceHandler defaultPlaceHandler = new DefaultPlaceHandler(); @@ -26,7 +29,10 @@ public class PlaceHandler { return defaultPlaceHandler; } - return placeHandlerList.get(itemId); + var placeHandler = placeHandlerList.get(itemId); + + log.debug("Using {} to mine/place a block", placeHandler.getClass().getSimpleName()); + return placeHandler; } public PlaceHandler() { diff --git a/src/main/java/cz/jzitnik/game/logic/services/daytime/DayTimeLogic.java b/src/main/java/cz/jzitnik/game/logic/services/daytime/DayTimeLogic.java new file mode 100644 index 0000000..d05593c --- /dev/null +++ b/src/main/java/cz/jzitnik/game/logic/services/daytime/DayTimeLogic.java @@ -0,0 +1,19 @@ +package cz.jzitnik.game.logic.services.daytime; + +import cz.jzitnik.game.Game; +import cz.jzitnik.game.annotations.CustomLogic; +import cz.jzitnik.game.logic.CustomLogicInterface; + +@CustomLogic +public class DayTimeLogic implements CustomLogicInterface { + @Override + public void nextIteration(Game game) { + int time = game.getDaytime(); + + if (time >= 600) { + game.setDaytime(0); + } else { + game.setDaytime(time + 1); + } + } +} diff --git a/src/main/java/cz/jzitnik/game/sprites/Air.java b/src/main/java/cz/jzitnik/game/sprites/Air.java index 0ba015e..a274e36 100644 --- a/src/main/java/cz/jzitnik/game/sprites/Air.java +++ b/src/main/java/cz/jzitnik/game/sprites/Air.java @@ -3,19 +3,29 @@ package cz.jzitnik.game.sprites; import cz.jzitnik.tui.Sprite; public class Air extends Sprite { - private String resource; - - public Air() { - StringBuilder sprite = new StringBuilder(); - for (int i = 0; i < 25; i++) { - sprite.append("\033[48;2;121;166;255m ".repeat(50)); - sprite.append("\n"); - } - resource = sprite.toString(); + public String getSprite() { + throw new RuntimeException("Imposible state"); } - public String getSprite() { - return resource; + public String getSprite(int daytime) { + StringBuilder sprite = new StringBuilder(); + + // Normalize daytime to a range of 0 to 1, where 300 is the darkest + double normalized = Math.abs((daytime - 300) / 300.0); + + // Interpolate blue color intensity (darker at midday, brighter at + // sunrise/sunset) + int blue = (int) (255 * normalized); + int red = (int) (121 * normalized); + int green = (int) (166 * normalized); + + String colorCode = String.format("\033[48;2;%d;%d;%dm ", red, green, blue); + + for (int i = 0; i < 25; i++) { + sprite.append(colorCode.repeat(50)).append("\n"); + } + + return sprite.toString(); } public String getSprite(Enum e) { diff --git a/src/main/java/cz/jzitnik/tui/ScreenRenderer.java b/src/main/java/cz/jzitnik/tui/ScreenRenderer.java index 3bfdb52..0ddb0f7 100644 --- a/src/main/java/cz/jzitnik/tui/ScreenRenderer.java +++ b/src/main/java/cz/jzitnik/tui/ScreenRenderer.java @@ -2,6 +2,7 @@ package cz.jzitnik.tui; import cz.jzitnik.game.entities.Block; import cz.jzitnik.game.Game; +import cz.jzitnik.game.sprites.Air; import cz.jzitnik.game.sprites.SimpleSprite; import cz.jzitnik.game.sprites.Steve; import cz.jzitnik.game.blocks.Chest; @@ -45,6 +46,19 @@ public class ScreenRenderer { return null; } + public String getTexture(Block block, SpriteList spriteList, Game game) { + if (Air.class.isAssignableFrom(spriteList.getSprite(block.getSprite()).getClass())) { + var air = (Air) spriteList.getSprite(block.getSprite()); + return air.getSprite(game.getDaytime()); + } + + if (block.getSpriteState().isEmpty()) { + return spriteList.getSprite(block.getSprite()).getSprite(); + } + + return spriteList.getSprite(block.getSprite()).getSprite(block.getSpriteState().get()); + } + public synchronized void render(Game game) { log.debug("Rendering frame"); var world = game.getWorld(); @@ -103,10 +117,7 @@ public class ScreenRenderer { for (int x = startX; x < endX; x++) { List blocks = world[y][x]; List sprites = new ArrayList<>(blocks.stream() - .map(block -> block.getSpriteState().isEmpty() - ? spriteList.getSprite(block.getSprite()).getSprite() - : spriteList.getSprite(block.getSprite()) - .getSprite(block.getSpriteState().get())) + .map(block -> getTexture(block, spriteList, game)) .toList()); if (selectedBlock.isPresent() && selectedBlock.get().get(0) == x