intersection works
This commit is contained in:
@ -1,8 +1,65 @@
|
|||||||
package se.urmo.game.collision;
|
package se.urmo.game.collision;
|
||||||
|
|
||||||
import se.urmo.game.map.GameMap;
|
import se.urmo.game.map.GameMap;
|
||||||
|
import se.urmo.game.util.Direction;
|
||||||
|
|
||||||
|
import java.awt.Point;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class GhostCollisionChecker {
|
public class GhostCollisionChecker {
|
||||||
|
private final GameMap map;
|
||||||
|
|
||||||
public GhostCollisionChecker(GameMap map) {
|
public GhostCollisionChecker(GameMap map) {
|
||||||
|
this.map = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point getValidDestination(Direction direction, Point position, int agent_width, int agent_height) {
|
||||||
|
|
||||||
|
List<Point> bounderies = switch (direction) {
|
||||||
|
case RIGHT -> List.of(
|
||||||
|
new Point(position.x + agent_width, position.y), // TOPRIGHT
|
||||||
|
new Point(position.x + agent_width, position.y + agent_height)); // BOTTOMRIGHT
|
||||||
|
case LEFT -> List.of(
|
||||||
|
position, // TOPLEFT
|
||||||
|
new Point(position.x, position.y + agent_height)); // BOTTOMLEFT
|
||||||
|
case UP -> List.of(
|
||||||
|
position, // TOPLEFT
|
||||||
|
new Point(position.x + agent_width, position.y)); // TOPRIGHT
|
||||||
|
case DOWN -> List.of(
|
||||||
|
new Point(position.x, position.y + agent_height), // BOTTOMLEFT
|
||||||
|
new Point(position.x + agent_width, position.y + agent_height)); // BOTTOMRIGHT
|
||||||
|
default -> Collections.EMPTY_LIST;
|
||||||
|
};
|
||||||
|
|
||||||
|
System.out.println( direction + " bounderies for " + position + " are " + bounderies);
|
||||||
|
|
||||||
|
List<Point> normalizedBoundaries = bounderies.stream()
|
||||||
|
.map(p -> normalizePosition(direction, p, agent_width, agent_height))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
if (map.isSolid(normalizedBoundaries)) {
|
||||||
|
return normalizePosition(direction, position, agent_width, agent_height);
|
||||||
|
}
|
||||||
|
return null; // Blocked
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point normalizePosition(Direction dir, Point pos, int agent_width, int agent_height) {
|
||||||
|
int x = pos.x;
|
||||||
|
int y = pos.y;
|
||||||
|
int width = map.getWidth();
|
||||||
|
int height = map.getHeight();
|
||||||
|
|
||||||
|
// tunnel
|
||||||
|
if (x < GameMap.OFFSET_X) x = width - agent_width - GameMap.OFFSET_X; // right
|
||||||
|
if (x >= (width - GameMap.OFFSET_X)) x = GameMap.OFFSET_X; // left
|
||||||
|
|
||||||
|
return new Point(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Direction> isIntersection(Point position) {
|
||||||
|
List<Direction> intersection = map.isIntersection(position);
|
||||||
|
System.out.println("Possible travel directions: " + intersection);
|
||||||
|
return intersection;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,6 @@ package se.urmo.game.entities;
|
|||||||
|
|
||||||
import se.urmo.game.collision.GhostCollisionChecker;
|
import se.urmo.game.collision.GhostCollisionChecker;
|
||||||
import se.urmo.game.main.Game;
|
import se.urmo.game.main.Game;
|
||||||
import se.urmo.game.main.GamePanel;
|
|
||||||
import se.urmo.game.map.GameMap;
|
import se.urmo.game.map.GameMap;
|
||||||
import se.urmo.game.util.Direction;
|
import se.urmo.game.util.Direction;
|
||||||
import se.urmo.game.util.LoadSave;
|
import se.urmo.game.util.LoadSave;
|
||||||
@ -12,6 +11,7 @@ import java.awt.Color;
|
|||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Point;
|
import java.awt.Point;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class Ghost {
|
public class Ghost {
|
||||||
private static final int COLLISION_BOX_SIZE = 16;
|
private static final int COLLISION_BOX_SIZE = 16;
|
||||||
@ -24,8 +24,8 @@ public class Ghost {
|
|||||||
private static final BufferedImage COLLISION_BOX = MiscUtil.createOutlinedBox(COLLISION_BOX_SIZE, COLLISION_BOX_SIZE, Color.black, 2);
|
private static final BufferedImage COLLISION_BOX = MiscUtil.createOutlinedBox(COLLISION_BOX_SIZE, COLLISION_BOX_SIZE, Color.black, 2);
|
||||||
|
|
||||||
private final Game game;
|
private final Game game;
|
||||||
private final GhostCollisionChecker ghostCollisionChecker;
|
private final GhostCollisionChecker collisionChecker;
|
||||||
private final Point position;
|
private Point position;
|
||||||
|
|
||||||
private boolean moving = true;
|
private boolean moving = true;
|
||||||
private int aniTick = 0;
|
private int aniTick = 0;
|
||||||
@ -35,9 +35,9 @@ public class Ghost {
|
|||||||
private int movementTick = 0;
|
private int movementTick = 0;
|
||||||
|
|
||||||
|
|
||||||
public Ghost(Game game, GhostCollisionChecker ghostCollisionChecker) {
|
public Ghost(Game game, GhostCollisionChecker collisionChecker, GhostStrategy strategy) {
|
||||||
this.game = game;
|
this.game = game;
|
||||||
this.ghostCollisionChecker = ghostCollisionChecker;
|
this.collisionChecker = collisionChecker;
|
||||||
position = new Point(13 * 16 + 8 + GameMap.OFFSET_X, 4 * 16 + GameMap.OFFSET_Y);
|
position = new Point(13 * 16 + 8 + GameMap.OFFSET_X, 4 * 16 + GameMap.OFFSET_Y);
|
||||||
loadAnimation();
|
loadAnimation();
|
||||||
}
|
}
|
||||||
@ -67,16 +67,57 @@ public class Ghost {
|
|||||||
public void update() {
|
public void update() {
|
||||||
updateAnimationTick();
|
updateAnimationTick();
|
||||||
if(movementTick >= GHOST_MOVEMENT_UPDATE_FREQUENCY) {
|
if(movementTick >= GHOST_MOVEMENT_UPDATE_FREQUENCY) {
|
||||||
|
// if intersection - decide direction
|
||||||
|
// else if direction isPassible
|
||||||
|
List<Direction> i = collisionChecker.isIntersection(position);
|
||||||
|
if(!i.isEmpty()){
|
||||||
|
// Change direction
|
||||||
|
if(i.contains(Direction.DOWN)) direction = Direction.DOWN;
|
||||||
|
else if(i.contains(Direction.RIGHT)) direction = Direction.RIGHT;
|
||||||
|
else if(i.contains(Direction.UP)) direction = Direction.UP;
|
||||||
|
else direction = Direction.LEFT;
|
||||||
|
|
||||||
if (position.x + direction.dx * GHOST_SPEED < GameMap.OFFSET_X) direction = direction.opposite();
|
}
|
||||||
if (position.x + GHOST_SIZE + (direction.dx * GHOST_SPEED) > GamePanel.SCREEN_WIDTH - GameMap.OFFSET_X)
|
|
||||||
direction = direction.opposite();
|
|
||||||
|
|
||||||
position.x += direction.dx * GHOST_SPEED;
|
//Point target = strategy.chooseTarget(pacman, this, blinky);
|
||||||
|
|
||||||
|
Point newPosition = switch (direction){
|
||||||
|
case RIGHT -> new Point(position.x += GHOST_SPEED, position.y);
|
||||||
|
case LEFT -> new Point(position.x -= GHOST_SPEED, position.y);
|
||||||
|
case DOWN -> new Point(position.x, position.y += GHOST_SPEED);
|
||||||
|
case UP -> new Point(position.x, position.y -= GHOST_SPEED);
|
||||||
|
default -> throw new IllegalStateException("Illegal direction");
|
||||||
|
};
|
||||||
|
|
||||||
|
Point destination = collisionChecker.getValidDestination(direction, newPosition, GHOST_SIZE, GHOST_SIZE);
|
||||||
|
|
||||||
|
// if (position.x + direction.dx * GHOST_SPEED < GameMap.OFFSET_X) direction = direction.opposite();
|
||||||
|
// if (position.x + GHOST_SIZE + (direction.dx * GHOST_SPEED) > GamePanel.SCREEN_WIDTH - GameMap.OFFSET_X)
|
||||||
|
// direction = direction.opposite();
|
||||||
|
|
||||||
|
if(destination != null) {
|
||||||
|
position = destination;
|
||||||
|
}
|
||||||
movementTick = 0;
|
movementTick = 0;
|
||||||
} else movementTick++;
|
} else movementTick++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Direction chooseDirection(List<Direction> options, Point target) {
|
||||||
|
Direction best = options.get(0);
|
||||||
|
double bestDist = Double.MAX_VALUE;
|
||||||
|
|
||||||
|
for (Direction d : options) {
|
||||||
|
int nx = position.x + d.dx * GameMap.MAP_TILESIZE;
|
||||||
|
int ny = position.y + d.dy * GameMap.MAP_TILESIZE;
|
||||||
|
double dist = target.distance(nx, ny);
|
||||||
|
if (dist < bestDist) {
|
||||||
|
bestDist = dist;
|
||||||
|
best = d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
|
||||||
private void updateAnimationTick() {
|
private void updateAnimationTick() {
|
||||||
if (moving) {
|
if (moving) {
|
||||||
aniTick++;
|
aniTick++;
|
||||||
|
|||||||
@ -79,4 +79,8 @@ public class Game implements Runnable {
|
|||||||
public GamePanel getGamePanel() {
|
public GamePanel getGamePanel() {
|
||||||
return gamePanel;
|
return gamePanel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GameStateManager getGameStateManager() {
|
||||||
|
return gameStateManager;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package se.urmo.game.map;
|
package se.urmo.game.map;
|
||||||
|
|
||||||
import se.urmo.game.main.GamePanel;
|
import se.urmo.game.main.GamePanel;
|
||||||
|
import se.urmo.game.util.Direction;
|
||||||
import se.urmo.game.util.LoadSave;
|
import se.urmo.game.util.LoadSave;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
@ -10,6 +11,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class GameMap {
|
public class GameMap {
|
||||||
public static final int MAP_TILESIZE = 16;// 16px from left
|
public static final int MAP_TILESIZE = 16;// 16px from left
|
||||||
@ -166,4 +168,35 @@ public class GameMap {
|
|||||||
MapTile tile = mapData[row][col];
|
MapTile tile = mapData[row][col];
|
||||||
if(tile.getValue() == 0) tile.setImage(null);
|
if(tile.getValue() == 0) tile.setImage(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Direction> isIntersection(Point position) {
|
||||||
|
int row = (position.y - OFFSET_Y) / MAP_TILESIZE;
|
||||||
|
int col = (position.x - OFFSET_X) / MAP_TILESIZE;
|
||||||
|
|
||||||
|
record DirectionCheck(int rowOffset, int colOffset, Direction direction) {}
|
||||||
|
|
||||||
|
return Stream.of(
|
||||||
|
new DirectionCheck(0, 1, Direction.RIGHT),
|
||||||
|
new DirectionCheck(0, -1, Direction.LEFT),
|
||||||
|
new DirectionCheck(1, 0, Direction.DOWN),
|
||||||
|
new DirectionCheck(-1, 0, Direction.UP)
|
||||||
|
)
|
||||||
|
.filter(dc -> !mapData[row + dc.rowOffset][col + dc.colOffset].isSolid())
|
||||||
|
.map(DirectionCheck::direction)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSolid(List<Point> points) {
|
||||||
|
return points.stream().allMatch(p -> isSolid(p.x, p.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSolid(int x, int y) {
|
||||||
|
int row = (y - OFFSET_Y) / MAP_TILESIZE;
|
||||||
|
int col = (x - OFFSET_X) / MAP_TILESIZE;
|
||||||
|
MapTile mapTile = mapData[row][col];
|
||||||
|
boolean solid = mapTile.isSolid();
|
||||||
|
//System.out.println("["+row+"]["+col+"] is " + (solid?"solid":" not solid") + " (" + mapTile.getValue() + ")");
|
||||||
|
return solid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,8 +37,8 @@ public class MapTile {
|
|||||||
return this.image;
|
return this.image;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPassable() {
|
public boolean isSolid() {
|
||||||
return ! this.solid;
|
return this.solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setImage(BufferedImage img) {
|
public void setImage(BufferedImage img) {
|
||||||
|
|||||||
@ -22,7 +22,7 @@ public class PlayingState implements GameState {
|
|||||||
this.gameStateManager = gameStateManager;
|
this.gameStateManager = gameStateManager;
|
||||||
this.map = new GameMap();
|
this.map = new GameMap();
|
||||||
this.pacman = new PacMan(game, new CollisionChecker(map));
|
this.pacman = new PacMan(game, new CollisionChecker(map));
|
||||||
this.ghost = new Ghost(game, new GhostCollisionChecker(map));
|
this.ghost = new Ghost(game, new GhostCollisionChecker(map), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -58,4 +58,8 @@ public class PlayingState implements GameState {
|
|||||||
pacman.setMoving(false);
|
pacman.setMoving(false);
|
||||||
pacman.setDirection(Direction.NONE);
|
pacman.setDirection(Direction.NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GameMap getMap() {
|
||||||
|
return map;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user