commit 5ffb77dd0002ce8bd08ec30dd19b72e4ed26990d Author: Urban Modig Date: Sun Aug 10 17:01:15 2025 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..7bc07ec --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,10 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Environment-dependent path to Maven home directory +/mavenHomeManager.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..44b0a07 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..ab15743 --- /dev/null +++ b/pom.xml @@ -0,0 +1,17 @@ + + + 4.0.0 + + org.example + MyPacman + 1.0-SNAPSHOT + + + 21 + 21 + UTF-8 + + + \ No newline at end of file diff --git a/src/main/java/se/urmo/game/Game.java b/src/main/java/se/urmo/game/Game.java new file mode 100644 index 0000000..8dd8723 --- /dev/null +++ b/src/main/java/se/urmo/game/Game.java @@ -0,0 +1,94 @@ +package se.urmo.game; + +import se.urmo.game.state.Playing; + +import javax.swing.*; +import java.awt.*; + +public class Game implements Runnable { + public final static int FPS_SET = 120; + public final static int UPS_SET = 200; + private final static double timePerFrame = 1000000000.0 / FPS_SET; + private final static double timePerUpdate = 1000000000.0 / UPS_SET; + + + private Thread gameThread; + private final JFrame window = new JFrame(); + private final GamePanel gamePanel = new GamePanel(this); + private Playing playing = new Playing(this); + + public void start() { + window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + window.setResizable(false); + window.setTitle("2d"); + + + window.add(gamePanel); + + window.pack(); + + window.setLocationRelativeTo(null); + window.setVisible(true); + + startGameThread(); + } + + public void startGameThread() { + this.gameThread = new Thread(this); + gameThread.start(); + } + + @Override + public void run() { + long previousTime = System.nanoTime(); + + int frames = 0; + int updates = 0; + long lastCheck = System.currentTimeMillis(); + + double deltaU = 0; + double deltaF = 0; + + while (gameThread !=null && gameThread.isAlive()) { + long currentTime = System.nanoTime(); + deltaU += (currentTime - previousTime) / timePerUpdate; + deltaF += (currentTime - previousTime) / timePerFrame; + + previousTime = currentTime; + + if (deltaU >= 1) { + update(); + updates++; + deltaU--; + } + + if (deltaF >= 1) { + gamePanel.repaint(); // triggers JPanel paintComponent + frames++; + deltaF--; + } + + if (System.currentTimeMillis() - lastCheck >= 1000) { + lastCheck = System.currentTimeMillis(); + System.out.println("FPS: " + frames + " | UPS: " + updates); + frames = 0; + updates = 0; + } + } + } + + private void update() { + playing.update(); + } + + public Playing getPlaying() { + return playing; + } + public GamePanel getGamePanel() { + return gamePanel; + } + + public void render(Graphics g) { + playing.draw(g); + } +} diff --git a/src/main/java/se/urmo/game/GameMap.java b/src/main/java/se/urmo/game/GameMap.java new file mode 100644 index 0000000..5289d3d --- /dev/null +++ b/src/main/java/se/urmo/game/GameMap.java @@ -0,0 +1,89 @@ +package se.urmo.game; + +import se.urmo.game.map.MapTile; +import se.urmo.game.util.LoadSave; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.stream.IntStream; + +public class GameMap { + public static final int MAP_TILESIZE = 16;// 16px from left + public static final int OFFSET_Y = 7 * MAP_TILESIZE; // 160px from top + public static final int OFFSET_X = MAP_TILESIZE; // 16px from left + private BufferedImage[][] image = new BufferedImage[13][19]; + private MapTile[][] mapData; + + public GameMap() { + loadMap("maps/map1.csv"); + loadSprites(); + } + + private void loadMap(String path) { + List rows = new ArrayList<>(); + try (InputStream is = getClass().getClassLoader().getResourceAsStream(path); + BufferedReader br = new BufferedReader(new InputStreamReader(Objects.requireNonNull(is)))) { + + String line; + while ((line = br.readLine()) != null) { + String[] tokens = line.split(","); + int[] row = new int[tokens.length]; + for (int i = 0; i < tokens.length; i++) { + row[i] = Integer.parseInt(tokens[i].trim()); + } + rows.add(row); + } + + } catch (IOException | NullPointerException e) { + e.printStackTrace(); + } + mapData = rows.stream() + .map(row -> IntStream.of(row) + .mapToObj(MapTile::new) + .toArray(MapTile[]::new)) + .toArray(MapTile[][]::new); + } + + private void loadSprites() { + BufferedImage img = LoadSave.GetSpriteAtlas("sprites/PacManAssets_Map_TileSet2.png");//473B78 + for (int row = 0; row < 13; row++) { + for (int col = 0; col < 19; col++) { + image[row][col] = img.getSubimage(MAP_TILESIZE * col, MAP_TILESIZE * row, MAP_TILESIZE, MAP_TILESIZE); + } + } + } + + public void draw(Graphics g) { + for (int row = 0; row < mapData.length; row++) { + for (int col = 0; col < mapData[row].length; col++) { + MapTile tile = mapData[row][col]; + + BufferedImage tileImage = tile.getImage(); + + if (tileImage != null) { + int x = OFFSET_X + col * MAP_TILESIZE; + int y = OFFSET_Y + row * MAP_TILESIZE; + g.drawImage(tileImage, x, y, MAP_TILESIZE, MAP_TILESIZE, null); + } + } + } + } + + public boolean isPassable(int x, int y) { + int row = (y - OFFSET_Y) / MAP_TILESIZE; + int col = (x - OFFSET_X) / MAP_TILESIZE; + + if (row > mapData.length - 1) row = 0; + if (col > mapData[row].length - 1) col = 0; + if (row < 0) row = mapData.length - 1; + if (col < 0) col = mapData[row].length - 1; + + boolean passable = mapData[row][col].isPassable(); + System.out.println(row + "," + col + "is" +(passable?"":" not") + " passable"); + return passable; + } +} diff --git a/src/main/java/se/urmo/game/GamePanel.java b/src/main/java/se/urmo/game/GamePanel.java new file mode 100644 index 0000000..205f10a --- /dev/null +++ b/src/main/java/se/urmo/game/GamePanel.java @@ -0,0 +1,55 @@ +package se.urmo.game; + +import se.urmo.game.input.KeyHandler; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.KeyEvent; + +public class GamePanel extends JPanel { + public static final int ORIGINAL_TILE_SIZE = 8; + public static final int SCALE = 1; + public static final int TILE_SIZE = ORIGINAL_TILE_SIZE * SCALE; + public static final int MAX_SCREEN_COL = 60; + public static final int MAX_SCREEN_ROW = 80; + public static final int SCREEN_WIDTH = MAX_SCREEN_COL * TILE_SIZE; + public static final int SCREEN_HEIGHT = MAX_SCREEN_ROW * TILE_SIZE; + private final Game game; + + + KeyHandler keyHandler = new KeyHandler(this); + + public GamePanel(Game game) { + this.game = game; + this.setPreferredSize(new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT)); + this.setBackground(Color.decode("#473B78")); + this.setDoubleBuffered(true); + this.addKeyListener(keyHandler); + this.setFocusable(true); + } + + public void paintComponent(Graphics g) { + super.paintComponent(g); + // Cast to Graphics2D for better control (optional) + Graphics2D g2d = (Graphics2D) g; + + // Fill full background with purple border + g2d.setColor(new Color(71, 59, 120)); // #473B78 + g2d.fillRect(0, 0, getWidth(), getHeight()); + + // Fill the inner map background with dark (almost black) + int border = 16; + g2d.setColor(new Color(20, 20, 28)); // Dark bluish-black like in the image + g2d.fillRect(border, border, getWidth() - 2 * border, getHeight() - 2 * border); + game.render(g); + } + + + public void keyPressed(KeyEvent e) { + game.getPlaying().keyPressed(e); + } + + public void keyReleased(KeyEvent e) { + game.getPlaying().keyReleased(); + } +} diff --git a/src/main/java/se/urmo/game/Main.java b/src/main/java/se/urmo/game/Main.java new file mode 100644 index 0000000..34637d8 --- /dev/null +++ b/src/main/java/se/urmo/game/Main.java @@ -0,0 +1,9 @@ +package se.urmo.game; + +//TIP To Run code, press or +// click the icon in the gutter. +public class Main { + public static void main(String[] args) { + new Game().start(); + } +} \ No newline at end of file diff --git a/src/main/java/se/urmo/game/PacMan.java b/src/main/java/se/urmo/game/PacMan.java new file mode 100644 index 0000000..a51b9f1 --- /dev/null +++ b/src/main/java/se/urmo/game/PacMan.java @@ -0,0 +1,148 @@ +package se.urmo.game; + +import se.urmo.game.state.CollisionChecker; +import se.urmo.game.util.LoadSave; +import se.urmo.game.util.MiscUtil; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.util.Arrays; + + +public class PacMan { + private static final int RIGHT = 0; + private static final int LEFT = 1; + private static final int DOWN = 2; + private static final int UP = 3; + public static final int PACMAN_SIZE = GamePanel.TILE_SIZE; + private final Game game; + private int aniTick = 0; + private int aniIndex = 0; + private static final int ANIMATION_UPDATE_FREQUENCY = 25; + private int speed = 1; + private boolean moving; + private final BufferedImage[][] movmentImages = new BufferedImage[4][4]; + private int direction = 0; + private int xPos = 14*16 + 8, yPos = 29*16; // top left of object + private static final BufferedImage innerBox = MiscUtil.createOutlinedBox(8,8, Color.yellow, 2); + private CollisionChecker collisionChecker; + + public PacMan(Game game, CollisionChecker collisionChecker) { + this.game = game; + this.collisionChecker = collisionChecker; + loadAnimation(); + } + + private void loadAnimation() { + BufferedImage[][] image = new BufferedImage[3][4]; + + BufferedImage img = LoadSave.GetSpriteAtlas("sprites/PacManAssets-PacMan.png"); + for (int row = 0; row < 3; row++) { + for (int col = 0; col < 4; col++) { + image[row][col] = img.getSubimage(32 * col, 32 * row, PACMAN_SIZE, PACMAN_SIZE); + } + } + movmentImages[RIGHT] = image[0]; + movmentImages[LEFT] = Arrays.stream(image[0]) + .map(i -> LoadSave.rotate(i, 180)) + .toArray(BufferedImage[]::new); + movmentImages[DOWN] = Arrays.stream(image[0]) + .map(i -> LoadSave.rotate(i, 90)) + .toArray(BufferedImage[]::new); + movmentImages[UP] = Arrays.stream(image[0]) + .map(i -> LoadSave.rotate(i, 270)) + .toArray(BufferedImage[]::new); + } + + + public void draw(Graphics g) { + g.drawImage(innerBox, xPos, yPos, PACMAN_SIZE, PACMAN_SIZE, null); + //g.setColor(Color.RED); + //g.drawLine(xPos, yPos, xPos, yPos); + //g.drawImage(movmentImages[direction][aniIndex], xPos, yPos, PACMAN_SIZE, PACMAN_SIZE, null); + } + + public void setLeft() { + direction = LEFT; + } + + public void setRight() { + direction = RIGHT; + } + + public void setUp() { + direction = UP; + } + + public void setDown() { + direction = DOWN; + } + + public void update() { + //System.out.println("Pacman current pos: " + xPos + ", " + yPos); + updateAnimationTick(); + int nextTileX = xPos; + int nextTileY = yPos; + + switch (direction) { + case RIGHT: { + nextTileX++; + break; + } + case LEFT: + nextTileX--; + break; + case UP: + nextTileY--; + break; + case DOWN: + nextTileY++; + break; + } + + + if (moving && collisionChecker.canMoveTo(direction, nextTileX, nextTileY, PACMAN_SIZE, PACMAN_SIZE)) { + //boolean b = collisionChecker.canMoveTo(direction, nextTileX, nextTileY, PACMAN_SIZE, PACMAN_SIZE); + //System.out.println("Can" + (b ? " " : "not ") + "move to (" +nextTileX+ "," + nextTileY + ")"); + updatePosition(); + } + } + + private void updatePosition() { + if(moving) { + switch (direction) { + case RIGHT -> { + if(xPos + PACMAN_SIZE < GamePanel.SCREEN_WIDTH) xPos += speed; + } + case LEFT -> { + if(xPos > 0) xPos -= speed; + else xPos = 0; + } + case DOWN -> { + if(yPos + PACMAN_SIZE < GamePanel.SCREEN_HEIGHT) yPos += speed; + } + case UP ->{ + if(yPos > 0) yPos -= speed; + } + } + } + } + + private void updateAnimationTick() { + if (moving) { + aniTick++; + if (aniTick >= ANIMATION_UPDATE_FREQUENCY) { + aniTick = 0; + aniIndex++; + if (aniIndex >= 3) { + aniIndex = 0; + } + + } + } + } + + public void setMoving(boolean moving) { + this.moving = moving; + } +} diff --git a/src/main/java/se/urmo/game/input/KeyHandler.java b/src/main/java/se/urmo/game/input/KeyHandler.java new file mode 100644 index 0000000..b495307 --- /dev/null +++ b/src/main/java/se/urmo/game/input/KeyHandler.java @@ -0,0 +1,28 @@ +package se.urmo.game.input; + +import se.urmo.game.GamePanel; + +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; + +public class KeyHandler implements KeyListener { + private final GamePanel gamePanel; + + public KeyHandler(GamePanel gamePanel) { + this.gamePanel = gamePanel; + } + + @Override + public void keyTyped(KeyEvent e) { + } + + @Override + public void keyPressed(KeyEvent e) { + gamePanel.keyPressed(e); + } + + @Override + public void keyReleased(KeyEvent e) { + gamePanel.keyReleased(e); + } +} diff --git a/src/main/java/se/urmo/game/map/MapTile.java b/src/main/java/se/urmo/game/map/MapTile.java new file mode 100644 index 0000000..ade6967 --- /dev/null +++ b/src/main/java/se/urmo/game/map/MapTile.java @@ -0,0 +1,26 @@ +package se.urmo.game.map; + +import se.urmo.game.util.MiscUtil; + +import java.awt.*; +import java.awt.image.BufferedImage; + +public class MapTile { + private final int value; + private final BufferedImage image; + private final boolean solid; + + public MapTile(int value) { + this.value = value; + this.image = value != 0 ? MiscUtil.createOutlinedBox(16, 16, Color.blue, 2) : null; + this.solid = value != 0; + } + + public BufferedImage getImage() { + return this.image; + } + + public boolean isPassable() { + return ! this.solid; + } +} diff --git a/src/main/java/se/urmo/game/state/CollisionChecker.java b/src/main/java/se/urmo/game/state/CollisionChecker.java new file mode 100644 index 0000000..fb93ff4 --- /dev/null +++ b/src/main/java/se/urmo/game/state/CollisionChecker.java @@ -0,0 +1,39 @@ +package se.urmo.game.state; + +import se.urmo.game.GameMap; + +public class CollisionChecker { + private GameMap map; + + public CollisionChecker(GameMap map) { + this.map = map; + } + + public boolean canMoveTo(int dir, int objectLeft, int objectTop, int width, int height) { + int objectRight = objectLeft + width; + int objectBotton = objectTop + height; + return switch (dir){ + case 0 -> isPassibleRight(objectRight, objectTop, objectBotton);// right + case 1 -> isPassibleLeft(objectLeft, objectTop, objectBotton);// right + case 2 -> isPassibleBottom(objectLeft, objectRight, objectBotton); + case 3 -> isPassibleTop(objectLeft, objectRight, objectTop);// right + default -> throw new IllegalArgumentException("Invalid dir: " + dir); + }; + } + + private boolean isPassibleBottom(int objectLeft, int objectRight, int objectBotton) { + return map.isPassable(objectLeft, objectBotton) && map.isPassable(objectRight, objectBotton); + } + + private boolean isPassibleTop(int objectLeft, int objectRight, int objectTop) { + return map.isPassable(objectLeft, objectTop) && map.isPassable(objectRight, objectTop); + } + + private boolean isPassibleLeft(int objectLeft, int objectTop, int objectBotton) { + return map.isPassable(objectLeft, objectTop) && map.isPassable(objectLeft, objectBotton); + } + + private boolean isPassibleRight(int objectRight, int objectTop, int objectBotton) { + return map.isPassable(objectRight, objectTop) && map.isPassable(objectRight, objectBotton); + } +} diff --git a/src/main/java/se/urmo/game/state/Playing.java b/src/main/java/se/urmo/game/state/Playing.java new file mode 100644 index 0000000..38d55ad --- /dev/null +++ b/src/main/java/se/urmo/game/state/Playing.java @@ -0,0 +1,44 @@ +package se.urmo.game.state; + +import se.urmo.game.Game; +import se.urmo.game.GameMap; +import se.urmo.game.PacMan; + +import java.awt.*; +import java.awt.event.KeyEvent; + + +public class Playing { + private PacMan pacMan; + private GameMap map = new GameMap(); + private final CollisionChecker collisionChecker = new CollisionChecker(map); + public Playing(Game game) { + this.pacMan = new PacMan(game, collisionChecker); + } + + public void update() { + pacMan.update(); + } + + public void keyPressed(KeyEvent e) { + pacMan.setMoving(true); + switch (e.getKeyCode()) { + case KeyEvent.VK_A -> pacMan.setLeft(); + case KeyEvent.VK_D -> pacMan.setRight(); + case KeyEvent.VK_W -> pacMan.setUp(); + case KeyEvent.VK_S -> pacMan.setDown(); + } + } + + public void draw(Graphics g) { + map.draw(g); + pacMan.draw(g); + } + + public void keyReleased() { + pacMan.setMoving(false); + } + public GameMap getMap() { + return map; + } +} diff --git a/src/main/java/se/urmo/game/util/LoadSave.java b/src/main/java/se/urmo/game/util/LoadSave.java new file mode 100644 index 0000000..adf9a0a --- /dev/null +++ b/src/main/java/se/urmo/game/util/LoadSave.java @@ -0,0 +1,57 @@ +package se.urmo.game.util; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.InputStream; + +public class LoadSave { + + public static BufferedImage GetSpriteAtlas(String fileName) { + BufferedImage img = null; + InputStream is = LoadSave.class.getResourceAsStream("/" + fileName); + try { + img = ImageIO.read(is); + + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + is.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return img; + } + + public static BufferedImage rotate(BufferedImage img, double angleDegrees) { + double angleRadians = Math.toRadians(angleDegrees); + + // Bildens dimensioner + int w = img.getWidth(); + int h = img.getHeight(); + + // Skapa en ny bild med samma storlek och stöd för transparens + BufferedImage rotated = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2d = rotated.createGraphics(); + + // För bästa kvalitet + g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); + g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + // Skapa transform: rotera runt bildens mittpunkt + AffineTransform transform = new AffineTransform(); + transform.rotate(angleRadians, w / 2.0, h / 2.0); + + // Rita originalbilden med transform + g2d.setTransform(transform); + g2d.drawImage(img, 0, 0, null); + g2d.dispose(); + + return rotated; + } +} diff --git a/src/main/java/se/urmo/game/util/MiscUtil.java b/src/main/java/se/urmo/game/util/MiscUtil.java new file mode 100644 index 0000000..5dd273d --- /dev/null +++ b/src/main/java/se/urmo/game/util/MiscUtil.java @@ -0,0 +1,31 @@ +package se.urmo.game.util; + +import java.awt.*; +import java.awt.image.BufferedImage; + +public class MiscUtil { + public static BufferedImage createOutlinedBox(int width, int height, Color outlineColor, float lineThickness) { + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2d = image.createGraphics(); + + // Optional: Disable anti-aliasing for pixel-perfect edges + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); + + // Set color and stroke + g2d.setColor(outlineColor); + g2d.setStroke(new BasicStroke(lineThickness)); + + // To avoid clipping, draw inside the bounds. + // Adjust for stroke thickness to stay within image bounds. + float halfStroke = lineThickness / 2f; + g2d.drawRect( + Math.round(halfStroke), + Math.round(halfStroke), + Math.round(width - lineThickness), + Math.round(height - lineThickness) + ); + + g2d.dispose(); + return image; + } +} diff --git a/src/main/resources/maps/map1.csv b/src/main/resources/maps/map1.csv new file mode 100644 index 0000000..28530d1 --- /dev/null +++ b/src/main/resources/maps/map1.csv @@ -0,0 +1,30 @@ + 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,18,19, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3 + 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9 + 7, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1,20, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 9 + 7, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1,17, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 9 + 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9 + 7, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 9 + 7, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 9 + 7, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 9 + 4, 5, 5, 5, 5,10, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0,11, 5, 5, 5, 5, 6 + 0, 0, 0, 0, 0,12, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0,13, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0,12, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,13, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0,12, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0,13, 0, 0, 0, 0, 0 +15,15,15,15,15,14, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0,16,15,15,15,15,15 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 5, 5, 5, 5, 5,10, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0,11, 5, 5, 5, 5, 5 + 0, 0, 0, 0, 0,12, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0,13, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0,12, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,13, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0,12, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0,13, 0, 0, 0, 0, 0 + 1,15,15,15,15,14, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0,16, 2, 2, 2, 2, 3 + 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9 + 7, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 9 + 7, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 9 +21, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 9 +22,24,25, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 9 +23, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 9 + 7, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 9 + 7, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 9 + 7, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 9 + 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9 + 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6 \ No newline at end of file diff --git a/src/main/resources/sprites/PacManAssets-Ghosts.png b/src/main/resources/sprites/PacManAssets-Ghosts.png new file mode 100644 index 0000000..b729d23 Binary files /dev/null and b/src/main/resources/sprites/PacManAssets-Ghosts.png differ diff --git a/src/main/resources/sprites/PacManAssets-Items.png b/src/main/resources/sprites/PacManAssets-Items.png new file mode 100644 index 0000000..fb5a453 Binary files /dev/null and b/src/main/resources/sprites/PacManAssets-Items.png differ diff --git a/src/main/resources/sprites/PacManAssets-PacMan.png b/src/main/resources/sprites/PacManAssets-PacMan.png new file mode 100644 index 0000000..74763e4 Binary files /dev/null and b/src/main/resources/sprites/PacManAssets-PacMan.png differ diff --git a/src/main/resources/sprites/PacManAssets_Map.png b/src/main/resources/sprites/PacManAssets_Map.png new file mode 100644 index 0000000..e9f9f78 Binary files /dev/null and b/src/main/resources/sprites/PacManAssets_Map.png differ diff --git a/src/main/resources/sprites/PacManAssets_Map_1.png b/src/main/resources/sprites/PacManAssets_Map_1.png new file mode 100644 index 0000000..b1a00d7 Binary files /dev/null and b/src/main/resources/sprites/PacManAssets_Map_1.png differ diff --git a/src/main/resources/sprites/PacManAssets_Map_2.png b/src/main/resources/sprites/PacManAssets_Map_2.png new file mode 100644 index 0000000..f343981 Binary files /dev/null and b/src/main/resources/sprites/PacManAssets_Map_2.png differ diff --git a/src/main/resources/sprites/PacManAssets_Map_3.png b/src/main/resources/sprites/PacManAssets_Map_3.png new file mode 100644 index 0000000..fac9c67 Binary files /dev/null and b/src/main/resources/sprites/PacManAssets_Map_3.png differ diff --git a/src/main/resources/sprites/PacManAssets_Map_Back&Maze.png b/src/main/resources/sprites/PacManAssets_Map_Back&Maze.png new file mode 100644 index 0000000..1a4e4b1 Binary files /dev/null and b/src/main/resources/sprites/PacManAssets_Map_Back&Maze.png differ diff --git a/src/main/resources/sprites/PacManAssets_Map_TileSet.png b/src/main/resources/sprites/PacManAssets_Map_TileSet.png new file mode 100644 index 0000000..c9953df Binary files /dev/null and b/src/main/resources/sprites/PacManAssets_Map_TileSet.png differ diff --git a/src/main/resources/sprites/PacManAssets_Map_TileSet2.png b/src/main/resources/sprites/PacManAssets_Map_TileSet2.png new file mode 100644 index 0000000..508b6ab Binary files /dev/null and b/src/main/resources/sprites/PacManAssets_Map_TileSet2.png differ diff --git a/src/main/resources/sprites/pear36-8x.png b/src/main/resources/sprites/pear36-8x.png new file mode 100644 index 0000000..6d34123 Binary files /dev/null and b/src/main/resources/sprites/pear36-8x.png differ diff --git a/src/main/resources/sprites/sprite_atlas.png b/src/main/resources/sprites/sprite_atlas.png new file mode 100644 index 0000000..4d91416 Binary files /dev/null and b/src/main/resources/sprites/sprite_atlas.png differ