feat: Recalculate mouse after player/enemy move

This commit is contained in:
2026-01-06 13:15:04 +01:00
parent 4e69859b00
commit 6943679c13
6 changed files with 93 additions and 43 deletions

View File

@@ -42,7 +42,7 @@ public class Cli implements Runnable {
terminal.setCursorPosition(null);
terminal.doResizeIfNecessary();
terminal.getTerminal().addResizeListener((_, terminalSize) -> {
terminal.getTerminal().addResizeListener((ignored, terminalSize) -> {
terminal.doResizeIfNecessary();
eventManager.emitEvent(new TerminalResizeEvent(terminalSize));
});

View File

@@ -6,6 +6,7 @@ import cz.jzitnik.annotations.EventHandler;
import cz.jzitnik.annotations.injectors.InjectState;
import cz.jzitnik.events.RerenderScreen;
import cz.jzitnik.game.Constants;
import cz.jzitnik.states.RenderState;
import cz.jzitnik.states.ScreenBuffer;
import cz.jzitnik.states.TerminalState;
import cz.jzitnik.ui.pixels.Empty;
@@ -25,12 +26,19 @@ public class CliHandler extends AbstractEventHandler<RerenderScreen> {
@InjectState
private ScreenBuffer screenBuffer;
@InjectState
private RenderState renderState;
public CliHandler(DependencyManager dm) {
super(dm);
}
@Override
public void handle(RerenderScreen event) {
if (renderState.isTerminalTooSmall()) {
return;
}
var parts = event.parts();
var buffer = screenBuffer.getRenderedBuffer();
var terminalScreen = terminalState.getTerminalScreen();

View File

@@ -1,6 +1,7 @@
package cz.jzitnik.events.handlers;
import com.googlecode.lanterna.TerminalPosition;
import com.googlecode.lanterna.input.MouseActionType;
import cz.jzitnik.annotations.EventHandler;
import cz.jzitnik.annotations.injectors.InjectConfig;
import cz.jzitnik.annotations.injectors.InjectDependency;
@@ -29,7 +30,6 @@ 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;
@@ -40,6 +40,8 @@ public class MouseMoveEventHandler extends AbstractEventHandler<MouseMoveEvent>
super(dm);
}
private MouseMoveEvent lastEvent = new MouseMoveEvent(new MouseAction(MouseActionType.MOVE, 1, new TerminalPosition(0, 0)));
@InjectState
private GameState gameState;
@@ -63,22 +65,34 @@ public class MouseMoveEventHandler extends AbstractEventHandler<MouseMoveEvent>
private double distancePointToRect(
double px, double py,
double left, double top,
double right, double bottom) {
double rectTopLeftX, double rectTopLeftY,
double rectBottomRightX, double rectBottomRightY) {
double minX = Math.min(rectTopLeftX, rectBottomRightX);
double maxX = Math.max(rectTopLeftX, rectBottomRightX);
double minY = Math.min(rectTopLeftY, rectBottomRightY);
double maxY = Math.max(rectTopLeftY, rectBottomRightY);
// Clamp point to rectangle
double closestX = Math.max(left, Math.min(px, right));
double closestY = Math.max(top, Math.min(py, bottom));
boolean isInside = (px > minX && px < maxX && py > minY && py < maxY);
double dx = px - closestX;
double dy = py - closestY;
if (isInside) {
return 0;
} else {
double closestX = Math.max(minX, Math.min(px, maxX));
double closestY = Math.max(minY, Math.min(py, maxY));
double dx = px - closestX;
double dy = py - closestY;
return Math.sqrt(dx * dx + dy * dy);
return Math.sqrt(dx * dx + dy * dy);
}
}
@Override
public void handle(MouseMoveEvent event) {
MouseAction mouseAction = event.getMouseAction();
if (event.getMouseAction() != null) {
this.lastEvent = event;
}
MouseAction mouseAction = lastEvent.getMouseAction();
int mouseX = mouseAction.getPosition().getColumn();
int mouseY = mouseAction.getPosition().getRow();

View File

@@ -9,6 +9,7 @@ import cz.jzitnik.annotations.injectors.InjectState;
import cz.jzitnik.config.Debugging;
import cz.jzitnik.config.Logging;
import cz.jzitnik.config.PlayerConfig;
import cz.jzitnik.events.MouseMoveEvent;
import cz.jzitnik.events.PlayerMoveEvent;
import cz.jzitnik.events.RerenderScreen;
import cz.jzitnik.events.RoomChangeEvent;
@@ -25,6 +26,7 @@ import cz.jzitnik.ui.Stats;
import cz.jzitnik.utils.DependencyManager;
import cz.jzitnik.utils.RerenderUtils;
import cz.jzitnik.utils.events.AbstractEventHandler;
import cz.jzitnik.utils.events.Event;
import cz.jzitnik.utils.events.EventManager;
import lombok.extern.slf4j.Slf4j;
@@ -151,18 +153,21 @@ public class PlayerMoveEventHandler extends AbstractEventHandler<PlayerMoveEvent
RerenderUtils.rerenderPart(forStartX, forEndX, forStartY, forEndY, startX, startY, currentRoom, room, player, playerTexture, screenBuffer, resourceManager, debugging);
eventManager.emitEvent(new RerenderScreen(
new RerenderScreen.ScreenPart[]{
new RerenderScreen.ScreenPart(
new TerminalPosition(forStartX + startX, forStartY + startY),
new TerminalPosition(forEndX + 1 + startX, forEndY + startY)
),
new RerenderScreen.ScreenPart(
new TerminalPosition(Stats.OFFSET_X, Stats.OFFSET_X),
new TerminalPosition(Stats.OFFSET_X + Stats.WIDTH, Stats.OFFSET_Y + Stats.HEIGHT)
)
}
));
eventManager.emitEvent(new Event[]{
new MouseMoveEvent(null),
new RerenderScreen(
new RerenderScreen.ScreenPart[]{
new RerenderScreen.ScreenPart(
new TerminalPosition(forStartX + startX, forStartY + startY),
new TerminalPosition(forEndX + 1 + startX, forEndY + startY)
),
new RerenderScreen.ScreenPart(
new TerminalPosition(Stats.OFFSET_X, Stats.OFFSET_X),
new TerminalPosition(Stats.OFFSET_X + Stats.WIDTH, Stats.OFFSET_Y + Stats.HEIGHT)
)
}
)
});
}
public static enum SprintKey {

View File

@@ -5,6 +5,7 @@ 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.MouseMoveEvent;
import cz.jzitnik.events.RerenderScreen;
import cz.jzitnik.game.GameRoomPart;
import cz.jzitnik.game.GameState;
@@ -16,6 +17,7 @@ import cz.jzitnik.game.utils.RoomCords;
import cz.jzitnik.states.ScreenBuffer;
import cz.jzitnik.states.TerminalState;
import cz.jzitnik.utils.RerenderUtils;
import cz.jzitnik.utils.events.Event;
import cz.jzitnik.utils.events.EventManager;
import cz.jzitnik.utils.roomtasks.RoomTask;
import lombok.RequiredArgsConstructor;
@@ -81,12 +83,15 @@ public class MobFollowingPlayerTask extends RoomTask {
RerenderUtils.rerenderPart(forStartX, forEndX, forStartY, forEndY, startX, startY, gameState.getCurrentRoom(), room, player, playerTexture, screenBuffer, resourceManager, debugging);
eventManager.emitEvent(new RerenderScreen(
new RerenderScreen.ScreenPart(
new TerminalPosition(forStartX + startX, forStartY + startY),
new TerminalPosition(forEndX + 1 + startX, forEndY + startY)
eventManager.emitEvent(new Event[]{
new MouseMoveEvent(null),
new RerenderScreen(
new RerenderScreen.ScreenPart(
new TerminalPosition(forStartX + startX, forStartY + startY),
new TerminalPosition(forEndX + 1 + startX, forEndY + startY)
)
)
));
});
} else {
log.debug("Mob is effectively at the target or trapped.");
}

View File

@@ -24,7 +24,7 @@ public class EventManager extends Thread {
private ExecutorService eventExecutor;
private final HashMap<Class<? extends Event>, AbstractEventHandler<? extends Event>> handlers = new HashMap<>();
private final BlockingQueue<Event> eventQueue = new LinkedBlockingQueue<>();
private final BlockingQueue<EventRecord> eventQueue = new LinkedBlockingQueue<>();
private final DependencyManager dependencyManager;
@SuppressWarnings("unchecked")
@@ -33,7 +33,26 @@ public class EventManager extends Thread {
}
public void emitEvent(Event event) {
eventQueue.add(event);
eventQueue.add(new EventRecord(new Event[]{event}));
}
public void emitEvent(Event event, Runnable callback) {
eventQueue.add(new EventRecord(new Event[]{event}, callback));
}
public void emitEvent(Event[] events) {
eventQueue.add(new EventRecord(events));
}
public void emitEvent(Event[] events, Runnable callback) {
eventQueue.add(new EventRecord(events, callback));
}
private record EventRecord(Event[] events, Runnable callback) {
public EventRecord(Event[] events) {
this(events, () -> {
});
}
}
@SuppressWarnings("unchecked")
@@ -64,7 +83,7 @@ public class EventManager extends Thread {
eventExecutor = Executors.newFixedThreadPool(threadPoolConfig.getEventThreadCount());
while (runningState.isRunning()) {
try {
Event event = eventQueue.take();
EventRecord event = eventQueue.take();
handleEvent(event);
} catch (InterruptedException e) {
// The game is shutting down.
@@ -76,18 +95,17 @@ public class EventManager extends Thread {
}
@SuppressWarnings("unchecked")
private <T extends Event> void handleEvent(Event event) {
T typedEvent = (T) event;
AbstractEventHandler<T> handler = getHandler((Class<T>) event.getClass());
if (handler != null) {
eventExecutor.submit(() -> {
try {
handler.handle(typedEvent);
} catch (Exception e) {
log.error("Error", e);
private void handleEvent(EventRecord eventRecord) {
eventExecutor.submit(() -> {
try {
for (Event event : eventRecord.events) {
AbstractEventHandler<Event> handler = getHandler((Class<Event>) event.getClass());
handler.handle(event);
}
});
}
eventRecord.callback.run();
} catch (Exception e) {
log.error("Error", e);
}
});
}
}