refactor: Reworked collision system

This commit is contained in:
2026-01-22 16:11:16 +01:00
parent f8d28acc33
commit aac651cf93
17 changed files with 85 additions and 40 deletions

View File

@@ -6,6 +6,6 @@ import lombok.Getter;
@Getter @Getter
@Config @Config
public class Debugging { public class Debugging {
private final boolean renderColliders = false; private final boolean renderColliders = true;
private final boolean renderPlayerCollider = false; private final boolean renderPlayerCollider = true;
} }

View File

@@ -87,7 +87,7 @@ public class PlayerMoveEventHandler extends AbstractEventHandler<PlayerMoveEvent
} }
return; return;
} }
playerCords.updateCordsWithColliders(currentRoom.getColliders(), player.getPlayerCords().getX(), playerCords.getY() - moveStep); playerCords.updateCordsWithColliders(currentRoom.getColliders(), player.getPlayerCords().getX(), playerCords.getY() - moveStep, player.getCollider());
player.setPlayerRotation(Player.PlayerRotation.BACK); player.setPlayerRotation(Player.PlayerRotation.BACK);
} }
case 'a' -> { case 'a' -> {
@@ -98,7 +98,7 @@ public class PlayerMoveEventHandler extends AbstractEventHandler<PlayerMoveEvent
} }
return; return;
} }
playerCords.updateCordsWithColliders(currentRoom.getColliders(), player.getPlayerCords().getX() - moveStep, playerCords.getY()); playerCords.updateCordsWithColliders(currentRoom.getColliders(), player.getPlayerCords().getX() - moveStep, playerCords.getY(), player.getCollider());
player.setPlayerRotation(Player.PlayerRotation.LEFT); player.setPlayerRotation(Player.PlayerRotation.LEFT);
} }
case 's' -> { case 's' -> {
@@ -109,7 +109,7 @@ public class PlayerMoveEventHandler extends AbstractEventHandler<PlayerMoveEvent
} }
return; return;
} }
playerCords.updateCordsWithColliders(currentRoom.getColliders(), player.getPlayerCords().getX(), playerCords.getY() + moveStep); playerCords.updateCordsWithColliders(currentRoom.getColliders(), player.getPlayerCords().getX(), playerCords.getY() + moveStep, player.getCollider());
player.setPlayerRotation(Player.PlayerRotation.FRONT); player.setPlayerRotation(Player.PlayerRotation.FRONT);
} }
case 'd' -> { case 'd' -> {
@@ -120,7 +120,7 @@ public class PlayerMoveEventHandler extends AbstractEventHandler<PlayerMoveEvent
} }
return; return;
} }
playerCords.updateCordsWithColliders(currentRoom.getColliders(), player.getPlayerCords().getX() + moveStep, playerCords.getY()); playerCords.updateCordsWithColliders(currentRoom.getColliders(), player.getPlayerCords().getX() + moveStep, playerCords.getY(), player.getCollider());
player.setPlayerRotation(Player.PlayerRotation.RIGHT); player.setPlayerRotation(Player.PlayerRotation.RIGHT);
} }
} }

View File

@@ -13,10 +13,19 @@ public class GameRoomPart {
private RoomCords end; private RoomCords end;
public boolean isWithin(RoomCords cords) { public boolean isWithin(RoomCords cords) {
return return cords.getX() >= start.getX() &&
cords.getX() >= start.getX() &&
cords.getX() <= end.getX() && cords.getX() <= end.getX() &&
cords.getY() >= start.getY() && cords.getY() >= start.getY() &&
cords.getY() <= end.getY(); cords.getY() <= end.getY();
} }
/**
* Checks if this GameRoomPart overlaps with another.
*/
public boolean isOverlapping(GameRoomPart other) {
return start.getX() <= other.getEnd().getX() &&
end.getX() >= other.getStart().getX() &&
start.getY() <= other.getEnd().getY() &&
end.getY() >= other.getStart().getY();
}
} }

View File

@@ -29,6 +29,7 @@ public class Player {
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private final RoomCords playerCords; private final RoomCords playerCords;
private final GameRoomPart collider;
private final GameItem[] inventory = new GameItem[Inventory.ITEMS_X * Inventory.ITEMS_Y]; private final GameItem[] inventory = new GameItem[Inventory.ITEMS_X * Inventory.ITEMS_Y];
@Setter @Setter
private PlayerRotation playerRotation = PlayerRotation.FRONT; private PlayerRotation playerRotation = PlayerRotation.FRONT;

View File

@@ -2,6 +2,7 @@ package cz.jzitnik.game.mobs;
import cz.jzitnik.annotations.injectors.InjectDependency; import cz.jzitnik.annotations.injectors.InjectDependency;
import cz.jzitnik.annotations.injectors.InjectState; import cz.jzitnik.annotations.injectors.InjectState;
import cz.jzitnik.game.GameRoomPart;
import cz.jzitnik.game.dialog.Dialog; import cz.jzitnik.game.dialog.Dialog;
import cz.jzitnik.game.utils.RoomCords; import cz.jzitnik.game.utils.RoomCords;
import cz.jzitnik.states.DialogState; import cz.jzitnik.states.DialogState;
@@ -16,13 +17,13 @@ import java.awt.image.BufferedImage;
public abstract class DialogMob extends Mob { public abstract class DialogMob extends Mob {
protected Dialog dialog; protected Dialog dialog;
public DialogMob(BufferedImage texture, RoomTask[] tasks, RoomCords cords, Dialog dialog) { public DialogMob(BufferedImage texture, RoomTask[] tasks, RoomCords cords, GameRoomPart collider, Dialog dialog) {
super(texture, tasks, cords); super(texture, tasks, cords, collider);
this.dialog = dialog; this.dialog = dialog;
} }
public DialogMob(BufferedImage texture, RoomTask task, RoomCords cords, Dialog dialog) { public DialogMob(BufferedImage texture, RoomTask task, RoomCords cords, GameRoomPart collider, Dialog dialog) {
super(texture, task, cords); super(texture, task, cords, collider);
this.dialog = dialog; this.dialog = dialog;
} }

View File

@@ -3,6 +3,7 @@ package cz.jzitnik.game.mobs;
import cz.jzitnik.annotations.injectors.InjectDependency; import cz.jzitnik.annotations.injectors.InjectDependency;
import cz.jzitnik.annotations.injectors.InjectState; import cz.jzitnik.annotations.injectors.InjectState;
import cz.jzitnik.events.RerenderPart; import cz.jzitnik.events.RerenderPart;
import cz.jzitnik.game.GameRoomPart;
import cz.jzitnik.game.GameState; import cz.jzitnik.game.GameState;
import cz.jzitnik.game.utils.RoomCords; import cz.jzitnik.game.utils.RoomCords;
import cz.jzitnik.utils.DependencyManager; import cz.jzitnik.utils.DependencyManager;
@@ -67,8 +68,8 @@ public abstract class HittableMob extends Mob {
@InjectDependency @InjectDependency
private RoomTaskScheduler roomTaskScheduler; private RoomTaskScheduler roomTaskScheduler;
public HittableMob(BufferedImage texture, RoomTask task, RoomCords cords, int initialHealth) { public HittableMob(BufferedImage texture, RoomTask task, RoomCords cords, GameRoomPart collider, int initialHealth) {
super(texture, task, cords); super(texture, task, cords, collider);
health = initialHealth; health = initialHealth;
} }

View File

@@ -5,6 +5,7 @@ import cz.jzitnik.annotations.injectors.InjectState;
import cz.jzitnik.events.DroppedItemRerender; import cz.jzitnik.events.DroppedItemRerender;
import cz.jzitnik.events.InventoryRerender; import cz.jzitnik.events.InventoryRerender;
import cz.jzitnik.game.GameRoom; import cz.jzitnik.game.GameRoom;
import cz.jzitnik.game.GameRoomPart;
import cz.jzitnik.game.GameState; import cz.jzitnik.game.GameState;
import cz.jzitnik.game.Player; import cz.jzitnik.game.Player;
import cz.jzitnik.game.items.GameItem; import cz.jzitnik.game.items.GameItem;
@@ -29,13 +30,13 @@ public abstract class HittableMobDrops extends HittableMob {
private final Supplier<GameItem[]> itemDropSupplier; private final Supplier<GameItem[]> itemDropSupplier;
public HittableMobDrops(BufferedImage texture, RoomTask task, RoomCords cords, int initialHealth, Supplier<GameItem[]> itemDropSupplier) { public HittableMobDrops(BufferedImage texture, RoomTask task, RoomCords cords, GameRoomPart collider, int initialHealth, Supplier<GameItem[]> itemDropSupplier) {
super(texture, task, cords, initialHealth); super(texture, task, cords, collider, initialHealth);
this.itemDropSupplier = itemDropSupplier; this.itemDropSupplier = itemDropSupplier;
} }
public HittableMobDrops(Supplier<GameItem> itemDropSupplier, BufferedImage texture, RoomTask task, RoomCords cords, int initialHealth) { public HittableMobDrops(Supplier<GameItem> itemDropSupplier, BufferedImage texture, RoomTask task, RoomCords cords, GameRoomPart collider, int initialHealth) {
super(texture, task, cords, initialHealth); super(texture, task, cords, collider, initialHealth);
this.itemDropSupplier = () -> new GameItem[]{ this.itemDropSupplier = () -> new GameItem[]{
itemDropSupplier.get() itemDropSupplier.get()
}; };

View File

@@ -1,13 +1,14 @@
package cz.jzitnik.game.mobs; package cz.jzitnik.game.mobs;
import cz.jzitnik.game.GameRoomPart;
import cz.jzitnik.game.utils.RoomCords; import cz.jzitnik.game.utils.RoomCords;
import cz.jzitnik.utils.roomtasks.RoomTask; import cz.jzitnik.utils.roomtasks.RoomTask;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
public abstract class HittableMobNoDrops extends HittableMob { public abstract class HittableMobNoDrops extends HittableMob {
public HittableMobNoDrops(BufferedImage texture, RoomTask task, RoomCords cords, int initialHealth) { public HittableMobNoDrops(BufferedImage texture, RoomTask task, RoomCords cords, GameRoomPart collider, int initialHealth) {
super(texture, task, cords, initialHealth); super(texture, task, cords, collider, initialHealth);
} }
@Override @Override

View File

@@ -1,6 +1,7 @@
package cz.jzitnik.game.mobs; package cz.jzitnik.game.mobs;
import cz.jzitnik.annotations.injectors.InjectDependency; import cz.jzitnik.annotations.injectors.InjectDependency;
import cz.jzitnik.game.GameRoomPart;
import cz.jzitnik.game.utils.Renderable; import cz.jzitnik.game.utils.Renderable;
import cz.jzitnik.game.utils.RoomCords; import cz.jzitnik.game.utils.RoomCords;
import cz.jzitnik.game.utils.Selectable; import cz.jzitnik.game.utils.Selectable;
@@ -17,6 +18,7 @@ public abstract class Mob implements Renderable, Selectable {
protected RoomTask[] tasks; protected RoomTask[] tasks;
protected final RoomCords cords; protected final RoomCords cords;
protected final GameRoomPart collider;
@InjectDependency @InjectDependency
private RoomTaskScheduler roomTaskScheduler; private RoomTaskScheduler roomTaskScheduler;
@@ -28,16 +30,18 @@ public abstract class Mob implements Renderable, Selectable {
roomTaskScheduler.registerNewMob(this, oldTasks); roomTaskScheduler.registerNewMob(this, oldTasks);
} }
public Mob(BufferedImage texture, RoomTask task, RoomCords cords) { public Mob(BufferedImage texture, RoomTask task, RoomCords cords, GameRoomPart collider) {
this.texture = texture; this.texture = texture;
this.tasks = new RoomTask[] {task}; this.tasks = new RoomTask[] {task};
this.cords = cords; this.cords = cords;
this.collider = collider;
} }
public Mob(BufferedImage texture, RoomTask[] tasks, RoomCords cords) { public Mob(BufferedImage texture, RoomTask[] tasks, RoomCords cords, GameRoomPart collider) {
this.texture = texture; this.texture = texture;
this.tasks = tasks; this.tasks = tasks;
this.cords = cords; this.cords = cords;
this.collider = collider;
} }
@Setter @Setter

View File

@@ -59,7 +59,7 @@ public class MobFollowingPlayerTask extends RoomTask {
protected static void moveMob(RoomCords playerCords, Mob mob, GameState gameState, int speed, ResourceManager resourceManager, TerminalState terminalState, ScreenBuffer screenBuffer, Debugging debugging, EventManager eventManager) { protected static void moveMob(RoomCords playerCords, Mob mob, GameState gameState, int speed, ResourceManager resourceManager, TerminalState terminalState, ScreenBuffer screenBuffer, Debugging debugging, EventManager eventManager) {
RoomCords mobCords = mob.getCords(); RoomCords mobCords = mob.getCords();
List<GameRoomPart> solidParts = gameState.getCurrentRoom().getColliders(); List<GameRoomPart> solidParts = gameState.getCurrentRoom().getColliders();
List<RoomCords> path = AStarAlg.findPath(mobCords, playerCords, solidParts); List<RoomCords> path = AStarAlg.findPath(mobCords, playerCords, solidParts, mob.getCollider());
if (path.size() > 1) { if (path.size() > 1) {
int targetIndex = Math.min(speed, path.size() - 1); int targetIndex = Math.min(speed, path.size() - 1);

View File

@@ -12,7 +12,7 @@ public class AStarAlg {
private static final int MIN_Y = 10; private static final int MIN_Y = 10;
private static final int MAX_Y = 113; private static final int MAX_Y = 113;
public static List<RoomCords> findPath(RoomCords start, RoomCords target, List<GameRoomPart> colliders) { public static List<RoomCords> findPath(RoomCords start, RoomCords target, List<GameRoomPart> colliders, GameRoomPart mobCollider) {
PriorityQueue<Node> openSet = new PriorityQueue<>(Comparator.comparingInt(n -> n.f)); PriorityQueue<Node> openSet = new PriorityQueue<>(Comparator.comparingInt(n -> n.f));
Set<String> closedSet = new HashSet<>(); Set<String> closedSet = new HashSet<>();
@@ -34,7 +34,7 @@ public class AStarAlg {
String neighborKey = neighbor.x + "," + neighbor.y; String neighborKey = neighbor.x + "," + neighbor.y;
if (closedSet.contains(neighborKey)) continue; if (closedSet.contains(neighborKey)) continue;
if (!isValidPosition(neighbor.x, neighbor.y, colliders)) { if (!isValidPosition(neighbor.x, neighbor.y, colliders, mobCollider)) {
if (neighbor.x != target.getX() || neighbor.y != target.getY()) { if (neighbor.x != target.getX() || neighbor.y != target.getY()) {
continue; continue;
} }
@@ -68,14 +68,17 @@ public class AStarAlg {
return neighbors; return neighbors;
} }
private static boolean isValidPosition(int x, int y, List<GameRoomPart> colliders) { private static boolean isValidPosition(int x, int y, List<GameRoomPart> colliders, GameRoomPart mobCollider) {
if (x < MIN_X || x > MAX_X) return false; if (x < MIN_X || x > MAX_X) return false;
if (y < MIN_Y || y > MAX_Y) return false; if (y < MIN_Y || y > MAX_Y) return false;
RoomCords temp = new RoomCords(x, y); var temp = new GameRoomPart(
new RoomCords(mobCollider.getStart().getX() + x, mobCollider.getStart().getY() + y),
new RoomCords(mobCollider.getEnd().getX() + x, mobCollider.getEnd().getY() + y)
);
for (GameRoomPart part : colliders) { for (GameRoomPart part : colliders) {
if (part.isWithin(temp)) { if (part.isOverlapping(temp)) {
return false; return false;
} }
} }

View File

@@ -35,6 +35,12 @@ public class GameSetup {
gameState.setCurrentRoom(mainRoom); gameState.setCurrentRoom(mainRoom);
gameState.setPlayer(new Player(new RoomCords(90, 100))); gameState.setPlayer(new Player(
new RoomCords(90, 100),
new GameRoomPart(
new RoomCords(0, 52),
new RoomCords(44, 78)
)
));
} }
} }

View File

@@ -1,5 +1,6 @@
package cz.jzitnik.game.setup.enemies; package cz.jzitnik.game.setup.enemies;
import cz.jzitnik.game.GameRoomPart;
import cz.jzitnik.game.ResourceManager; import cz.jzitnik.game.ResourceManager;
import cz.jzitnik.game.dialog.Dialog; import cz.jzitnik.game.dialog.Dialog;
import cz.jzitnik.game.dialog.OnEnd; import cz.jzitnik.game.dialog.OnEnd;
@@ -11,7 +12,12 @@ import cz.jzitnik.utils.roomtasks.RoomTask;
public class Pepa extends DialogMob { public class Pepa extends DialogMob {
public Pepa(ResourceManager resourceManager, RoomCords cords) { public Pepa(ResourceManager resourceManager, RoomCords cords) {
super(resourceManager.getResource(ResourceManager.Resource.PLAYER_FRONT), new RoomTask[]{}, cords, null super(resourceManager.getResource(ResourceManager.Resource.PLAYER_FRONT), new RoomTask[]{}, cords,
new GameRoomPart(
new RoomCords(0, 52),
new RoomCords(44, 78)
),
null
); );
dialog = new Dialog( dialog = new Dialog(

View File

@@ -1,5 +1,6 @@
package cz.jzitnik.game.setup.enemies; package cz.jzitnik.game.setup.enemies;
import cz.jzitnik.game.GameRoomPart;
import cz.jzitnik.game.ResourceManager; import cz.jzitnik.game.ResourceManager;
import cz.jzitnik.game.mobs.HittableMobDrops; import cz.jzitnik.game.mobs.HittableMobDrops;
import cz.jzitnik.game.mobs.tasks.EnemyPlayerHittingTask; import cz.jzitnik.game.mobs.tasks.EnemyPlayerHittingTask;
@@ -12,7 +13,13 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j
public class Zombie extends HittableMobDrops { public class Zombie extends HittableMobDrops {
public Zombie(ResourceManager resourceManager, RoomCords cords) { public Zombie(ResourceManager resourceManager, RoomCords cords) {
super(() -> new Apple(resourceManager), resourceManager.getResource(ResourceManager.Resource.PLAYER_FRONT), null, cords, 10); super(() -> new Apple(resourceManager), resourceManager.getResource(ResourceManager.Resource.PLAYER_FRONT), null, cords,
new GameRoomPart(
new RoomCords(0, 52),
new RoomCords(44, 78)
),
10
);
tasks = new RoomTask[]{ tasks = new RoomTask[]{
new MobFollowingPlayerTask(this, 1, 100), new MobFollowingPlayerTask(this, 1, 100),
new EnemyPlayerHittingTask(this, 500, 15, () -> 5) new EnemyPlayerHittingTask(this, 500, 15, () -> 5)

View File

@@ -22,8 +22,8 @@ public class MainRoom extends GameRoom {
new Apple(resourceManager) new Apple(resourceManager)
}); });
addCollider(new GameRoomPart( addCollider(new GameRoomPart(
new RoomCords(60, 10), new RoomCords(100, 45),
new RoomCords(135, 15) new RoomCords(140, 67)
)); ));
addObject(chest); addObject(chest);

View File

@@ -23,8 +23,13 @@ public class RoomCords implements Cloneable {
this.y = y; this.y = y;
} }
public void updateCordsWithColliders(List<GameRoomPart> colliders, int x, int y) { public void updateCordsWithColliders(List<GameRoomPart> colliders, int x, int y, GameRoomPart playerCollider) {
if (colliders.stream().anyMatch(collider -> collider.isWithin(new RoomCords(x, y)))) { var normalizedPlayerCollider = new GameRoomPart(
new RoomCords(playerCollider.getStart().getX() + x, playerCollider.getStart().getY() + y),
new RoomCords(playerCollider.getEnd().getX() + x, playerCollider.getEnd().getY() + y)
);
if (colliders.stream().anyMatch(collider -> collider.isOverlapping(normalizedPlayerCollider))) {
return; return;
} }
updateCords(x, y); updateCords(x, y);

View File

@@ -73,9 +73,9 @@ public class RerenderUtils {
if (x >= player.getPlayerCords().getX() && x < player.getPlayerCords().getX() + playerTexture.getWidth() - 1 && y >= player.getPlayerCords().getY() && y <= player.getPlayerCords().getY() + playerTexture.getHeight() - 1) { if (x >= player.getPlayerCords().getX() && x < player.getPlayerCords().getX() + playerTexture.getWidth() - 1 && y >= player.getPlayerCords().getY() && y <= player.getPlayerCords().getY() + playerTexture.getHeight() - 1) {
int relativeX = x - player.getPlayerCords().getX(); int relativeX = x - player.getPlayerCords().getX();
int relativeY = y - player.getPlayerCords().getY(); int relativeY = y - player.getPlayerCords().getY();
var playerCollider = player.getCollider();
if (debugging.isRenderPlayerCollider() && playerCollider.isWithin(new RoomCords(relativeX, relativeY))) {
if (debugging.isRenderPlayerCollider() && relativeX == 0 && relativeY == 0) {
return new PixelResult(0xFFFF0000, false); return new PixelResult(0xFFFF0000, false);
} }