From adc0cb85994f9881975473ea87cde50f47948b33 Mon Sep 17 00:00:00 2001 From: jzitnik-dev Date: Wed, 7 Jan 2026 11:07:44 +0100 Subject: [PATCH] feat: Enemies dropping items --- .../cz/jzitnik/game/mobs/HittableMob.java | 5 +- .../jzitnik/game/mobs/HittableMobDrops.java | 82 +++++++++++++++++++ .../cz/jzitnik/game/objects/DroppedItem.java | 8 +- .../cz/jzitnik/game/setup/enemies/Zombie.java | 13 +-- .../cz/jzitnik/screens/VideoPlayScreen.java | 2 +- src/main/java/cz/jzitnik/ui/Inventory.java | 2 +- .../cz/jzitnik/utils/events/EventManager.java | 5 ++ 7 files changed, 101 insertions(+), 16 deletions(-) create mode 100644 src/main/java/cz/jzitnik/game/mobs/HittableMobDrops.java diff --git a/src/main/java/cz/jzitnik/game/mobs/HittableMob.java b/src/main/java/cz/jzitnik/game/mobs/HittableMob.java index 889943e..209ba9f 100644 --- a/src/main/java/cz/jzitnik/game/mobs/HittableMob.java +++ b/src/main/java/cz/jzitnik/game/mobs/HittableMob.java @@ -30,7 +30,8 @@ import java.util.concurrent.TimeUnit; @Slf4j public abstract class HittableMob extends Mob { public abstract void onKilled(); - private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); + + private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); protected int health; private ScheduledFuture currentTimeoutHitAnimation = null; @@ -58,7 +59,7 @@ public abstract class HittableMob extends Mob { } @Override - public void interact(DependencyManager dm) { + public final void interact(DependencyManager dm) { dm.inject(this); health -= gameState.getPlayer().getDamageDeal(); diff --git a/src/main/java/cz/jzitnik/game/mobs/HittableMobDrops.java b/src/main/java/cz/jzitnik/game/mobs/HittableMobDrops.java new file mode 100644 index 0000000..a115f05 --- /dev/null +++ b/src/main/java/cz/jzitnik/game/mobs/HittableMobDrops.java @@ -0,0 +1,82 @@ +package cz.jzitnik.game.mobs; + +import cz.jzitnik.annotations.injectors.InjectDependency; +import cz.jzitnik.annotations.injectors.InjectState; +import cz.jzitnik.events.DroppedItemRerender; +import cz.jzitnik.events.InventoryRerender; +import cz.jzitnik.game.GameRoom; +import cz.jzitnik.game.GameState; +import cz.jzitnik.game.Player; +import cz.jzitnik.game.items.GameItem; +import cz.jzitnik.game.objects.DroppedItem; +import cz.jzitnik.game.utils.RoomCords; +import cz.jzitnik.utils.events.Event; +import cz.jzitnik.utils.events.EventManager; +import cz.jzitnik.utils.roomtasks.RoomTask; + +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; +import java.util.function.Supplier; + +public abstract class HittableMobDrops extends HittableMob { + @InjectState + private GameState gameState; + + @InjectDependency + private EventManager eventManager; + + private final Supplier itemDropSupplier; + + public HittableMobDrops(BufferedImage texture, RoomTask task, RoomCords cords, int initialHealth, Supplier itemDropSupplier) { + super(texture, task, cords, initialHealth); + this.itemDropSupplier = itemDropSupplier; + } + + public HittableMobDrops(Supplier itemDropSupplier, BufferedImage texture, RoomTask task, RoomCords cords, int initialHealth) { + super(texture, task, cords, initialHealth); + this.itemDropSupplier = () -> new GameItem[]{ + itemDropSupplier.get() + }; + } + + private static final int DROP_ITEM_ON_GROUND_RADIUS = 30; + + @Override + public final void onKilled() { + GameItem[] items = itemDropSupplier.get(); + boolean addedIntoInventory = false; + Player player = gameState.getPlayer(); + RoomCords enemyCords = getCords(); + BufferedImage enemyTexture = getTexture(); + GameRoom currentRoom = gameState.getCurrentRoom(); + + int roomX = enemyCords.getX() + enemyTexture.getWidth() / 2; + int roomY = enemyCords.getY() + enemyTexture.getHeight() / 2; + + List events = new ArrayList<>(); + + for (GameItem item : items) { + boolean added = player.addItem(item); + + if (added) { + if (!addedIntoInventory) { + addedIntoInventory = true; + events.add(new InventoryRerender()); + } + } else { + double angle = ThreadLocalRandom.current().nextDouble(0, Math.PI * 2); + double radius = ThreadLocalRandom.current().nextDouble(0, DROP_ITEM_ON_GROUND_RADIUS); + int randomX = roomX + (int) (Math.cos(angle) * radius); + int randomY = roomY + (int) (Math.sin(angle) * radius); + RoomCords itemCords = new RoomCords(randomX, randomY); + DroppedItem droppedItem = new DroppedItem(currentRoom, itemCords, item); + currentRoom.getDroppedItems().add(droppedItem); + events.add(new DroppedItemRerender(droppedItem)); + } + } + + eventManager.emitEvent(events); + } +} diff --git a/src/main/java/cz/jzitnik/game/objects/DroppedItem.java b/src/main/java/cz/jzitnik/game/objects/DroppedItem.java index f1add18..7214899 100644 --- a/src/main/java/cz/jzitnik/game/objects/DroppedItem.java +++ b/src/main/java/cz/jzitnik/game/objects/DroppedItem.java @@ -35,12 +35,14 @@ public final class DroppedItem implements Selectable, Serializable { public void interact(DependencyManager dm) { StateManager stateManager = dm.getDependencyOrThrow(StateManager.class); GameState gameState = stateManager.getOrThrow(GameState.class); + + if (!gameState.getPlayer().addItem(item)) { + return; + } + EventManager eventManager = dm.getDependencyOrThrow(EventManager.class); var currentRoom = gameState.getCurrentRoom(); - currentRoom.getDroppedItems().remove(this); - gameState.getPlayer().addItem(item); - eventManager.emitEvent(new InventoryRerender()); eventManager.emitEvent(new DroppedItemRerender(this)); } diff --git a/src/main/java/cz/jzitnik/game/setup/enemies/Zombie.java b/src/main/java/cz/jzitnik/game/setup/enemies/Zombie.java index be0a395..dbd73cc 100644 --- a/src/main/java/cz/jzitnik/game/setup/enemies/Zombie.java +++ b/src/main/java/cz/jzitnik/game/setup/enemies/Zombie.java @@ -1,26 +1,21 @@ package cz.jzitnik.game.setup.enemies; import cz.jzitnik.game.ResourceManager; -import cz.jzitnik.game.mobs.HittableMob; +import cz.jzitnik.game.mobs.HittableMobDrops; import cz.jzitnik.game.mobs.tasks.EnemyPlayerHittingTask; import cz.jzitnik.game.mobs.tasks.MobFollowingPlayerTask; +import cz.jzitnik.game.setup.items.Apple; import cz.jzitnik.game.utils.RoomCords; import cz.jzitnik.utils.roomtasks.RoomTask; import lombok.extern.slf4j.Slf4j; @Slf4j -public class Zombie extends HittableMob { - +public class Zombie extends HittableMobDrops { public Zombie(ResourceManager resourceManager, RoomCords cords) { - super(resourceManager.getResource(ResourceManager.Resource.PLAYER_FRONT), null, cords, 10); + super(() -> new Apple(resourceManager), resourceManager.getResource(ResourceManager.Resource.PLAYER_FRONT), null, cords, 10); setTasks(new RoomTask[]{ new MobFollowingPlayerTask(this, 1, 100), new EnemyPlayerHittingTask(this, 500, 15, () -> 5) }); } - - @Override - public void onKilled() { - log.debug("Zombie killed"); - } } diff --git a/src/main/java/cz/jzitnik/screens/VideoPlayScreen.java b/src/main/java/cz/jzitnik/screens/VideoPlayScreen.java index a973992..9532bc3 100644 --- a/src/main/java/cz/jzitnik/screens/VideoPlayScreen.java +++ b/src/main/java/cz/jzitnik/screens/VideoPlayScreen.java @@ -41,7 +41,7 @@ public abstract class VideoPlayScreen extends Screen { } } - protected void render() { + protected final void render() { File tempVideo = null; try (InputStream resource = resourceManager.getResourceAsStream(videoPath)) { diff --git a/src/main/java/cz/jzitnik/ui/Inventory.java b/src/main/java/cz/jzitnik/ui/Inventory.java index b27892c..90855cb 100644 --- a/src/main/java/cz/jzitnik/ui/Inventory.java +++ b/src/main/java/cz/jzitnik/ui/Inventory.java @@ -352,7 +352,7 @@ public class Inventory { int topR = (pixel >> 16) & 0xff; int topG = (pixel >> 8) & 0xff; int topB = pixel & 0xff; - float topOpacity = 0.80f; + float topOpacity = 0.60f; int bottomR = bottomPixel.getColor().getRed(); int bottomG = bottomPixel.getColor().getGreen(); int bottomB = bottomPixel.getColor().getBlue(); diff --git a/src/main/java/cz/jzitnik/utils/events/EventManager.java b/src/main/java/cz/jzitnik/utils/events/EventManager.java index 9187dbc..65abc8e 100644 --- a/src/main/java/cz/jzitnik/utils/events/EventManager.java +++ b/src/main/java/cz/jzitnik/utils/events/EventManager.java @@ -12,6 +12,7 @@ import org.reflections.Reflections; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; +import java.util.List; import java.util.concurrent.*; @Slf4j @@ -44,6 +45,10 @@ public class EventManager extends Thread { eventQueue.add(new EventRecord(events)); } + public void emitEvent(List events) { + eventQueue.add(new EventRecord(events.toArray(new Event[]{}))); + } + public void emitEvent(Event[] events, Runnable callback) { eventQueue.add(new EventRecord(events, callback)); }