feat: Dropping items

This commit is contained in:
2026-01-05 16:30:10 +01:00
parent 22d4e0b9f5
commit f02a186dc3
11 changed files with 214 additions and 24 deletions

2
.idea/misc.xml generated
View File

@@ -20,7 +20,7 @@
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_X" default="true" project-jdk-name="openjdk-25" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_25" default="true" project-jdk-name="openjdk-25" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

View File

@@ -1,5 +1,7 @@
package cz.jzitnik;
// events/handlers/MouseMoveEventHandler.java
public class Main {
public static void main(String[] args) {
new Game().start();

View File

@@ -0,0 +1,7 @@
package cz.jzitnik.events;
import cz.jzitnik.game.objects.DroppedItem;
import cz.jzitnik.utils.events.Event;
public record DroppedItemRerender(DroppedItem droppedItem) implements Event {
}

View File

@@ -0,0 +1,84 @@
package cz.jzitnik.events.handlers;
import com.googlecode.lanterna.TerminalPosition;
import cz.jzitnik.annotations.EventHandler;
import cz.jzitnik.annotations.injectors.InjectConfig;
import cz.jzitnik.annotations.injectors.InjectDependency;
import cz.jzitnik.annotations.injectors.InjectState;
import cz.jzitnik.config.Debugging;
import cz.jzitnik.events.DroppedItemRerender;
import cz.jzitnik.events.RerenderScreen;
import cz.jzitnik.game.GameState;
import cz.jzitnik.game.ResourceManager;
import cz.jzitnik.game.utils.RoomCords;
import cz.jzitnik.states.ScreenBuffer;
import cz.jzitnik.states.TerminalState;
import cz.jzitnik.utils.DependencyManager;
import cz.jzitnik.utils.RerenderUtils;
import cz.jzitnik.utils.events.AbstractEventHandler;
import cz.jzitnik.utils.events.EventManager;
import java.awt.image.BufferedImage;
@EventHandler(DroppedItemRerender.class)
public class DroppedItemRerenderHandler extends AbstractEventHandler<DroppedItemRerender> {
public DroppedItemRerenderHandler(DependencyManager dm) {
super(dm);
}
@InjectDependency
private EventManager eventManager;
@InjectDependency
private ResourceManager resourceManager;
@InjectState
private GameState gameState;
@InjectState
private TerminalState terminalState;
@InjectState
private ScreenBuffer screenBuffer;
@InjectConfig
private Debugging debugging;
@Override
public void handle(DroppedItemRerender event) {
RoomCords droppedItemCords = event.droppedItem().getCords();
BufferedImage droppedItemTexture = event.droppedItem().getTexture();
BufferedImage playerTexture = RerenderUtils.getPlayer(resourceManager, gameState.getPlayer());
BufferedImage room = resourceManager.getResource(gameState.getCurrentRoom().getTexture());
RoomCords start = RerenderUtils.getStart(room, terminalState.getTerminalScreen().getTerminalSize());
RerenderScreen.ScreenPart part = new RerenderScreen.ScreenPart(
new TerminalPosition(
start.getX() + droppedItemCords.getX(),
start.getY() + droppedItemCords.getY()
),
new TerminalPosition(
start.getX() + droppedItemCords.getX() + droppedItemTexture.getWidth(),
start.getY() + droppedItemCords.getY() + droppedItemTexture.getHeight()
)
);
RerenderUtils.rerenderPart(
droppedItemCords.getX(),
droppedItemCords.getX() + droppedItemTexture.getWidth(),
droppedItemCords.getY(),
droppedItemCords.getY() + droppedItemTexture.getHeight(),
start.getX(),
start.getY(),
gameState.getCurrentRoom(),
room,
gameState.getPlayer(),
playerTexture,
screenBuffer,
resourceManager,
debugging
);
eventManager.emitEvent(new RerenderScreen(part));
}
}

View File

@@ -66,8 +66,10 @@ public class MouseActionEventHandler extends AbstractEventHandler<MouseAction> {
}
Stream<? extends Selectable> combined = Stream.concat(
gameState.getCurrentRoom().getMobs().stream(),
gameState.getCurrentRoom().getObjects().stream()
Stream.concat(
gameState.getCurrentRoom().getMobs().stream(),
gameState.getCurrentRoom().getObjects().stream()),
gameState.getCurrentRoom().getDroppedItems().stream()
);
Optional<? extends Selectable> object = combined.filter(Selectable::isSelected).findFirst();

View File

@@ -14,8 +14,6 @@ import cz.jzitnik.game.GameRoom;
import cz.jzitnik.game.GameState;
import cz.jzitnik.game.Player;
import cz.jzitnik.game.ResourceManager;
import cz.jzitnik.game.objects.GameObject;
import cz.jzitnik.game.utils.Renderable;
import cz.jzitnik.game.utils.RoomCords;
import cz.jzitnik.game.utils.Selectable;
import cz.jzitnik.states.ScreenBuffer;
@@ -31,6 +29,7 @@ import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -93,8 +92,16 @@ public class MouseMoveEventHandler extends AbstractEventHandler<MouseMoveEvent>
int startX = start.getX();
int startY = start.getY();
List<? extends Selectable> combinedObjects = Stream
.concat(currentRoom.getObjects().stream(), currentRoom.getMobs().stream()).toList();
/*List<? extends Selectable> _combinedObjects = Stream.of(
currentRoom.getObjects().stream(),
currentRoom.getMobs().stream(),
currentRoom.getDroppedItems().stream())
.flatMap(Function.identity()).toList();*/ // For some reason doesn't compile
List<? extends Selectable> combinedObjects = Stream.concat(Stream.concat(
currentRoom.getObjects().stream(),
currentRoom.getMobs().stream()
), currentRoom.getDroppedItems().stream()).toList();
Set<Selectable> selectedObjects = combinedObjects.stream().filter(gameObject -> {
if (!gameObject.isSelectable()) return false;
@@ -123,9 +130,9 @@ public class MouseMoveEventHandler extends AbstractEventHandler<MouseMoveEvent>
return
relativeMouseX >= cords.getX() &&
relativeMouseX < cords.getX() + texture.getWidth() &&
relativeMouseY >= cords.getY() &&
relativeMouseY < cords.getY() + texture.getHeight();
relativeMouseX < cords.getX() + texture.getWidth() &&
relativeMouseY >= cords.getY() &&
relativeMouseY < cords.getY() + texture.getHeight();
}).collect(Collectors.toSet());
Set<Selectable> changedObjects = new HashSet<>();

View File

@@ -1,5 +1,6 @@
package cz.jzitnik.game;
import cz.jzitnik.game.objects.DroppedItem;
import cz.jzitnik.game.objects.GameObject;
import cz.jzitnik.game.mobs.Mob;
import cz.jzitnik.ui.pixels.Empty;
@@ -7,7 +8,9 @@ import cz.jzitnik.ui.pixels.Pixel;
import lombok.Getter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Getter
public class GameRoom {
@@ -19,6 +22,7 @@ public class GameRoom {
private final ResourceManager.Resource texture;
private final List<GameObject> objects = new ArrayList<>();
private final List<Mob> mobs = new ArrayList<>();
private final Set<DroppedItem> droppedItems = new HashSet<>();
private final List<GameRoomPart> colliders = new ArrayList<>();
public GameRoom(ResourceManager.Resource texture) {

View File

@@ -0,0 +1,45 @@
package cz.jzitnik.game.objects;
import cz.jzitnik.events.DroppedItemRerender;
import cz.jzitnik.events.InventoryRerender;
import cz.jzitnik.game.GameState;
import cz.jzitnik.game.items.GameItem;
import cz.jzitnik.game.utils.RoomCords;
import cz.jzitnik.game.utils.Selectable;
import cz.jzitnik.utils.DependencyManager;
import cz.jzitnik.utils.StateManager;
import cz.jzitnik.utils.events.EventManager;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import java.awt.image.BufferedImage;
import java.io.Serializable;
@Getter
@RequiredArgsConstructor
public final class DroppedItem implements Selectable, Serializable {
private final RoomCords cords;
private final GameItem item;
@Setter
private boolean isSelected = false;
@Override
public BufferedImage getTexture() {
return item.getTexture();
}
@Override
public void interact(DependencyManager dm) {
StateManager stateManager = dm.getDependencyOrThrow(StateManager.class);
GameState gameState = stateManager.getOrThrow(GameState.class);
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));
}
}

View File

@@ -28,6 +28,6 @@ public class MainRoom extends GameRoom {
addObject(chest);
Zombie zombie = new Zombie(resourceManager, new RoomCords(100, 100));
//addMob(zombie);
addMob(zombie);
}
}

View File

@@ -7,6 +7,7 @@ import cz.jzitnik.annotations.Dependency;
import cz.jzitnik.annotations.injectors.InjectDependency;
import cz.jzitnik.annotations.injectors.InjectState;
import cz.jzitnik.annotations.ui.*;
import cz.jzitnik.events.DroppedItemRerender;
import cz.jzitnik.events.InventoryRerender;
import cz.jzitnik.events.KeyboardPressEvent;
import cz.jzitnik.events.MouseAction;
@@ -14,6 +15,7 @@ import cz.jzitnik.game.GameState;
import cz.jzitnik.game.ResourceManager;
import cz.jzitnik.game.items.GameItem;
import cz.jzitnik.game.items.types.InteractableItem;
import cz.jzitnik.game.objects.DroppedItem;
import cz.jzitnik.states.ScreenBuffer;
import cz.jzitnik.states.TerminalState;
import cz.jzitnik.ui.pixels.ColoredPixel;
@@ -113,8 +115,18 @@ public class Inventory {
return false;
}
var player = gameState.getPlayer();
var inventory = player.getInventory();
var currentRoom = gameState.getCurrentRoom();
DroppedItem droppedItem = new DroppedItem(player.getPlayerCords().clone(), inventory[inventoryState.selectedItem]);
currentRoom.getDroppedItems().add(droppedItem);
inventory[inventoryState.selectedItem] = null;
inventoryState.selectedItem = -1;
eventManager.emitEvent(new InventoryRerender());
eventManager.emitEvent(new DroppedItemRerender(droppedItem));
log.debug("Dropping item!");
// TODO: Dropping items on a ground
return true;
}

View File

@@ -9,6 +9,7 @@ import cz.jzitnik.game.Player;
import cz.jzitnik.game.ResourceManager;
import cz.jzitnik.game.mobs.HittableMob;
import cz.jzitnik.game.mobs.Mob;
import cz.jzitnik.game.objects.DroppedItem;
import cz.jzitnik.game.objects.GameObject;
import cz.jzitnik.game.utils.RoomCords;
import cz.jzitnik.states.ScreenBuffer;
@@ -60,9 +61,11 @@ public class RerenderUtils {
}
}
public record PixelResult(int pixel, boolean isPlayer) {}
public record PixelResult(int pixel, boolean isPlayer) {
}
public static PixelResult getPixel(GameRoom currentRoom, BufferedImage room, BufferedImage doors, Set<FullRoomDrawHandler.DoorPosition> doorPositions, Player player, BufferedImage playerTexture, int x, int y, Debugging debugging) {
float factor = 1.5f; // brightness multiplier
if (debugging.isRenderColliders() && currentRoom.getColliders().stream().anyMatch(collider -> collider.isWithin(new RoomCords(x, y)))) {
return new PixelResult(0xFFFF0000, false);
}
@@ -72,7 +75,7 @@ public class RerenderUtils {
int relativeY = y - player.getPlayerCords().getY();
if (debugging.isRenderPlayerCollider() && relativeX == 0 && relativeY == 0){
if (debugging.isRenderPlayerCollider() && relativeX == 0 && relativeY == 0) {
return new PixelResult(0xFFFF0000, false);
}
@@ -84,7 +87,7 @@ public class RerenderUtils {
}
}
for (Mob object: currentRoom.getMobs()) {
for (Mob object : currentRoom.getMobs()) {
RoomCords startObjectCords = object.getCords();
BufferedImage texture = object.getTexture();
boolean isSelected = object.isSelected();
@@ -96,17 +99,42 @@ public class RerenderUtils {
int r = (pixel >> 16) & 0xff;
int g = (pixel >> 8) & 0xff;
int b = pixel & 0xff;
float factor = 1.5f; // brightness multiplier
float redFactor = 2f;
if (alpha != 0) {
if (object instanceof HittableMob mob && mob.isHitAnimationOn()) {
r = Math.min(255, (int)(r * redFactor));
r = Math.min(255, (int) (r * redFactor));
pixel = (alpha << 24) | (r << 16) | (g << 8) | b;
} else if (isSelected) {
r = Math.min(255, (int)(r * factor));
g = Math.min(255, (int)(g * factor));
b = Math.min(255, (int)(b * factor));
r = Math.min(255, (int) (r * factor));
g = Math.min(255, (int) (g * factor));
b = Math.min(255, (int) (b * factor));
pixel = (alpha << 24) | (r << 16) | (g << 8) | b;
}
return new PixelResult(pixel, false);
}
}
}
for (DroppedItem droppedItem : currentRoom.getDroppedItems()) {
RoomCords startDroppedItemCords = droppedItem.getCords();
BufferedImage texture = droppedItem.getTexture();
boolean isSelected = droppedItem.isSelected();
RoomCords endDroppedItemCords = new RoomCords(startDroppedItemCords.getX() + texture.getWidth() - 1, startDroppedItemCords.getY() + texture.getHeight() - 1);
if (x >= startDroppedItemCords.getX() && x <= endDroppedItemCords.getX() && y >= startDroppedItemCords.getY() && y <= endDroppedItemCords.getY()) {
int pixel = texture.getRGB(x - startDroppedItemCords.getX(), y - startDroppedItemCords.getY());
int alpha = (pixel >> 24) & 0xff;
int r = (pixel >> 16) & 0xff;
int g = (pixel >> 8) & 0xff;
int b = pixel & 0xff;
if (alpha != 0) {
if (isSelected) {
r = Math.min(255, (int) (r * factor));
g = Math.min(255, (int) (g * factor));
b = Math.min(255, (int) (b * factor));
pixel = (alpha << 24) | (r << 16) | (g << 8) | b;
}
@@ -127,13 +155,12 @@ public class RerenderUtils {
int r = (pixel >> 16) & 0xff;
int g = (pixel >> 8) & 0xff;
int b = pixel & 0xff;
float factor = 1.5f; // brightness multiplier
if (alpha != 0) {
if (isSelected) {
r = Math.min(255, (int)(r * factor));
g = Math.min(255, (int)(g * factor));
b = Math.min(255, (int)(b * factor));
r = Math.min(255, (int) (r * factor));
g = Math.min(255, (int) (g * factor));
b = Math.min(255, (int) (b * factor));
pixel = (alpha << 24) | (r << 16) | (g << 8) | b;
}