From a8908f7e13b5f3c3dad57c1ccc339d6f3dfe38a0 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 1 Jul 2020 16:18:59 +0200 Subject: [PATCH] Simplify snake drawing and movement calculation --- src/main/dev/lh/FoodFactory.java | 2 +- src/main/dev/lh/Snake.java | 95 ++++++++++++++---------------- src/main/dev/lh/Updateable.java | 6 +- src/main/dev/lh/ui/GameWindow.java | 12 ++-- 4 files changed, 53 insertions(+), 62 deletions(-) diff --git a/src/main/dev/lh/FoodFactory.java b/src/main/dev/lh/FoodFactory.java index 68316c4..9e597e0 100755 --- a/src/main/dev/lh/FoodFactory.java +++ b/src/main/dev/lh/FoodFactory.java @@ -28,7 +28,7 @@ public class FoodFactory { * @author Leon Hofmeister * @since Snake 1.0 */ - public static enum Food { + public enum Food { /** * Use if white food is wanted. diff --git a/src/main/dev/lh/Snake.java b/src/main/dev/lh/Snake.java index 2c41ed3..6fda5aa 100644 --- a/src/main/dev/lh/Snake.java +++ b/src/main/dev/lh/Snake.java @@ -1,6 +1,8 @@ package dev.lh; -import java.awt.*; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Rectangle; import java.util.ArrayList; import java.util.List; @@ -31,30 +33,31 @@ public class Snake implements Updateable { /** * Use if the snake should head left. */ - Left, + LEFT, /** * Use if the snake should head right. */ - Right, + RIGHT, /** * Use if the snake should head up. */ - Up, + UP, /** * Use if the snake should head down. */ - Down; + DOWN; } - private static FoodFactory foodFactory = FoodFactory.getInstance(); - private static Endscreen endscreen; - private Direction direction; - private int length; - private List tiles = new ArrayList<>(); - private final int snakeSize = 10; + private static FoodFactory foodFactory = FoodFactory.getInstance(); + private static Endscreen endscreen; + private Direction direction = Direction.RIGHT; + private int length; + private List tiles = new ArrayList<>(); + + private static final int TILE_SIZE = 10; /** * Constructs a new Snake with the given length in tiles. @@ -63,21 +66,21 @@ public class Snake implements Updateable { * @since Snake 1.0 */ public Snake(int length) { - this.length = length; - direction = Direction.Right; - // adding the initial tiles of the snake + this.length = length; + + // Add initial tiles for (int i = 0; i < length; i++) - tiles.add(new Point(320 - snakeSize * i, 240)); + tiles.add(new Rectangle(320 - TILE_SIZE * i, 240, TILE_SIZE, TILE_SIZE)); } /** - * Adds the given length to the current snake object + * Increases the given length to the current snake object. * * @param additional the number of tiles to add * @since Snake 1.0 */ public void addLength(int additional) { - Point last = tiles.get(tiles.size() - 1); + Rectangle last = tiles.get(tiles.size() - 1); for (int i = 0; i < additional; i++) tiles.add(last); length += additional; @@ -88,17 +91,10 @@ public class Snake implements Updateable { * @since Snake 1.1 */ private boolean checkSelfCollision() { - Point headIndex = tiles.get(0); - Rectangle head = new Rectangle(headIndex.x, headIndex.y, snakeSize, snakeSize); - for (int index = 1; index < tiles.size(); index++) { - Point bodyIndex = tiles.get(index); - if (head.contains(new Rectangle(bodyIndex.x, bodyIndex.y, snakeSize, snakeSize))) return true; - } - return false; + return tiles.stream().skip(1).anyMatch(tiles.get(0)::contains); } /** - * * @since Snake 1.1 */ private void gameOver() { @@ -117,45 +113,41 @@ public class Snake implements Updateable { public void nextFrame() { int velX = 0, velY = 0; switch (direction) { - case Up: - velY = -snakeSize; + case UP: + velY = -TILE_SIZE; break; - case Down: - velY = snakeSize; + case DOWN: + velY = TILE_SIZE; break; - case Left: - velX = -snakeSize; + case LEFT: + velX = -TILE_SIZE; break; - case Right: - velX = snakeSize; + case RIGHT: + velX = TILE_SIZE; break; } - Point next = (Point) tiles.get(0).clone(), cur; - tiles.get(0).x += velX; - tiles.get(0).y += velY; - - for (int i = 1; i < length; i++) { - cur = tiles.get(i); - tiles.set(i, (Point) next.clone()); - next = cur; - } - - // case if snake is outside of the screen or touches itself + // Add a new tile at the front + tiles.add( + 0, + new Rectangle(tiles.get(0).x + velX, tiles.get(0).y + velY, TILE_SIZE, TILE_SIZE) + ); + // Remove the last tile + tiles.remove(tiles.size() - 1); + // Case if snake is outside of the screen or touches itself if (checkSelfCollision()) { gameOver(); System.out.println("Snake collided with itself."); return; } - // TODO: the game bounds checking below appears to work on Windows, however - // throws a NullPointerException on Linux/UNIX systems + // TODO: Test on Linux if (!Main.getGame().getBounds().contains(tiles.get(0))) { gameOver(); System.out.println("Snake went out of bounds."); return; } - - // case if snake eats food - if (foodFactory.checkCollision(new Rectangle(tiles.get(0).x, tiles.get(0).y, snakeSize, snakeSize))) { + // TODO: Move to Food class + // Case if snake eats food + if (foodFactory.checkCollision(tiles.get(0))) { addLength(foodFactory.getAdditionalLength()); GameWindow game = Main.getGame(); game.newFood(); @@ -163,10 +155,9 @@ public class Snake implements Updateable { } @Override - public void render(Graphics g) { + public void render(Graphics2D g) { g.setColor(Color.green); - for (int i = 0; i < length; i++) - g.fillRect(tiles.get(i).x, tiles.get(i).y, snakeSize, snakeSize); + tiles.forEach(g::fill); } /** diff --git a/src/main/dev/lh/Updateable.java b/src/main/dev/lh/Updateable.java index 2174917..272d812 100755 --- a/src/main/dev/lh/Updateable.java +++ b/src/main/dev/lh/Updateable.java @@ -1,6 +1,6 @@ package dev.lh; -import java.awt.Graphics; +import java.awt.Graphics2D; /** * This interface contains everything that needs to be updated regularly. @@ -25,8 +25,8 @@ public interface Updateable { /** * Renders the object. * - * @param g the {@link Graphics} object that is used to render this object + * @param g the graphics object that is used to render this object * @since Snake 1.0 */ - void render(Graphics g); + void render(Graphics2D g); } diff --git a/src/main/dev/lh/ui/GameWindow.java b/src/main/dev/lh/ui/GameWindow.java index f315436..211771d 100755 --- a/src/main/dev/lh/ui/GameWindow.java +++ b/src/main/dev/lh/ui/GameWindow.java @@ -52,8 +52,8 @@ public class GameWindow extends JFrame { protected void paintComponent(Graphics g) { super.paintComponent(g); g.setColor(Color.black); - g.fillRect(0, 0, super.getWidth(), super.getHeight()); - s.render(g); + g.fillRect(0, 0, getWidth(), getHeight()); + s.render((Graphics2D) g); foodFactory.paintFood(g); } }); @@ -66,19 +66,19 @@ public class GameWindow extends JFrame { switch (e.getKeyCode()) { case KeyEvent.VK_W: case KeyEvent.VK_UP: - if (!s.getRichtung().equals(Direction.Down)) s.setDirection(Direction.Up); + if (!s.getRichtung().equals(Direction.DOWN)) s.setDirection(Direction.UP); break; case KeyEvent.VK_A: case KeyEvent.VK_LEFT: - if (!s.getRichtung().equals(Direction.Right)) s.setDirection(Direction.Left); + if (!s.getRichtung().equals(Direction.RIGHT)) s.setDirection(Direction.LEFT); break; case KeyEvent.VK_S: case KeyEvent.VK_DOWN: - if (!s.getRichtung().equals(Direction.Up)) s.setDirection(Direction.Down); + if (!s.getRichtung().equals(Direction.UP)) s.setDirection(Direction.DOWN); break; case KeyEvent.VK_D: case KeyEvent.VK_RIGHT: - if (!s.getRichtung().equals(Direction.Left)) s.setDirection(Direction.Right); + if (!s.getRichtung().equals(Direction.LEFT)) s.setDirection(Direction.RIGHT); break; } }