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
@Config
public class Debugging {
private final boolean renderColliders = false;
private final boolean renderPlayerCollider = false;
private final boolean renderColliders = true;
private final boolean renderPlayerCollider = true;
}

View File

@@ -87,7 +87,7 @@ public class PlayerMoveEventHandler extends AbstractEventHandler<PlayerMoveEvent
}
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);
}
case 'a' -> {
@@ -98,7 +98,7 @@ public class PlayerMoveEventHandler extends AbstractEventHandler<PlayerMoveEvent
}
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);
}
case 's' -> {
@@ -109,7 +109,7 @@ public class PlayerMoveEventHandler extends AbstractEventHandler<PlayerMoveEvent
}
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);
}
case 'd' -> {
@@ -120,7 +120,7 @@ public class PlayerMoveEventHandler extends AbstractEventHandler<PlayerMoveEvent
}
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);
}
}

View File

@@ -13,10 +13,19 @@ public class GameRoomPart {
private RoomCords end;
public boolean isWithin(RoomCords cords) {
return
cords.getX() >= start.getX() &&
cords.getX() <= end.getX() &&
cords.getY() >= start.getY() &&
cords.getY() <= end.getY();
return cords.getX() >= start.getX() &&
cords.getX() <= end.getX() &&
cords.getY() >= start.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 RoomCords playerCords;
private final GameRoomPart collider;
private final GameItem[] inventory = new GameItem[Inventory.ITEMS_X * Inventory.ITEMS_Y];
@Setter
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.InjectState;
import cz.jzitnik.game.GameRoomPart;
import cz.jzitnik.game.dialog.Dialog;
import cz.jzitnik.game.utils.RoomCords;
import cz.jzitnik.states.DialogState;
@@ -16,13 +17,13 @@ import java.awt.image.BufferedImage;
public abstract class DialogMob extends Mob {
protected Dialog dialog;
public DialogMob(BufferedImage texture, RoomTask[] tasks, RoomCords cords, Dialog dialog) {
super(texture, tasks, cords);
public DialogMob(BufferedImage texture, RoomTask[] tasks, RoomCords cords, GameRoomPart collider, Dialog dialog) {
super(texture, tasks, cords, collider);
this.dialog = dialog;
}
public DialogMob(BufferedImage texture, RoomTask task, RoomCords cords, Dialog dialog) {
super(texture, task, cords);
public DialogMob(BufferedImage texture, RoomTask task, RoomCords cords, GameRoomPart collider, Dialog dialog) {
super(texture, task, cords, collider);
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.InjectState;
import cz.jzitnik.events.RerenderPart;
import cz.jzitnik.game.GameRoomPart;
import cz.jzitnik.game.GameState;
import cz.jzitnik.game.utils.RoomCords;
import cz.jzitnik.utils.DependencyManager;
@@ -67,8 +68,8 @@ public abstract class HittableMob extends Mob {
@InjectDependency
private RoomTaskScheduler roomTaskScheduler;
public HittableMob(BufferedImage texture, RoomTask task, RoomCords cords, int initialHealth) {
super(texture, task, cords);
public HittableMob(BufferedImage texture, RoomTask task, RoomCords cords, GameRoomPart collider, int initialHealth) {
super(texture, task, cords, collider);
health = initialHealth;
}

View File

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

View File

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

View File

@@ -1,6 +1,7 @@
package cz.jzitnik.game.mobs;
import cz.jzitnik.annotations.injectors.InjectDependency;
import cz.jzitnik.game.GameRoomPart;
import cz.jzitnik.game.utils.Renderable;
import cz.jzitnik.game.utils.RoomCords;
import cz.jzitnik.game.utils.Selectable;
@@ -17,6 +18,7 @@ public abstract class Mob implements Renderable, Selectable {
protected RoomTask[] tasks;
protected final RoomCords cords;
protected final GameRoomPart collider;
@InjectDependency
private RoomTaskScheduler roomTaskScheduler;
@@ -28,16 +30,18 @@ public abstract class Mob implements Renderable, Selectable {
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.tasks = new RoomTask[] {task};
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.tasks = tasks;
this.cords = cords;
this.collider = collider;
}
@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) {
RoomCords mobCords = mob.getCords();
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) {
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 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));
Set<String> closedSet = new HashSet<>();
@@ -34,7 +34,7 @@ public class AStarAlg {
String neighborKey = neighbor.x + "," + neighbor.y;
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()) {
continue;
}
@@ -68,14 +68,17 @@ public class AStarAlg {
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 (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) {
if (part.isWithin(temp)) {
if (part.isOverlapping(temp)) {
return false;
}
}

View File

@@ -35,6 +35,12 @@ public class GameSetup {
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;
import cz.jzitnik.game.GameRoomPart;
import cz.jzitnik.game.ResourceManager;
import cz.jzitnik.game.dialog.Dialog;
import cz.jzitnik.game.dialog.OnEnd;
@@ -11,7 +12,12 @@ import cz.jzitnik.utils.roomtasks.RoomTask;
public class Pepa extends DialogMob {
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(

View File

@@ -1,5 +1,6 @@
package cz.jzitnik.game.setup.enemies;
import cz.jzitnik.game.GameRoomPart;
import cz.jzitnik.game.ResourceManager;
import cz.jzitnik.game.mobs.HittableMobDrops;
import cz.jzitnik.game.mobs.tasks.EnemyPlayerHittingTask;
@@ -12,7 +13,13 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j
public class Zombie extends HittableMobDrops {
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[]{
new MobFollowingPlayerTask(this, 1, 100),
new EnemyPlayerHittingTask(this, 500, 15, () -> 5)

View File

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

View File

@@ -23,8 +23,13 @@ public class RoomCords implements Cloneable {
this.y = y;
}
public void updateCordsWithColliders(List<GameRoomPart> colliders, int x, int y) {
if (colliders.stream().anyMatch(collider -> collider.isWithin(new RoomCords(x, y)))) {
public void updateCordsWithColliders(List<GameRoomPart> colliders, int x, int y, GameRoomPart playerCollider) {
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;
}
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) {
int relativeX = x - player.getPlayerCords().getX();
int relativeY = y - player.getPlayerCords().getY();
var playerCollider = player.getCollider();
if (debugging.isRenderPlayerCollider() && relativeX == 0 && relativeY == 0) {
if (debugging.isRenderPlayerCollider() && playerCollider.isWithin(new RoomCords(relativeX, relativeY))) {
return new PixelResult(0xFFFF0000, false);
}