diff --git a/src/main/dev/lh/Food.java b/src/main/dev/lh/Food.java new file mode 100644 index 0000000..484e21c --- /dev/null +++ b/src/main/dev/lh/Food.java @@ -0,0 +1,54 @@ +package dev.lh; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Rectangle; + +/** + * Represents a food item. + *

+ * Project: Snake
+ * File: Food.java
+ * Created: 01.07.2020
+ * + * @author Kai S. K. Engelbart + * @since Snake 1.2 + */ +public final class Food implements Updateable { + + private final Color color; + private final int lengthBonus; + private final Rectangle bounds; + + /** + * Constructs a food item. + * + * @param color the color of the food item + * @param lengthBonus the length added to the snake when the food item is eaten + * @param bounds the bounds of the food item + * @since Snake 1.2 + */ + public Food(Color color, int lengthBonus, Rectangle bounds) { + this.color = color; + this.lengthBonus = lengthBonus; + this.bounds = bounds; + } + + @Override + public void render(Graphics2D g) { + g.setColor(color); + g.fill(bounds); + } + + /** + * @return the length added to the snake when the food item is eaten + * @since Snake 1.2 + */ + public int getLengthBonus() { return lengthBonus; } + + /** + * @return the bounds of the food item + * @since Snake 1.2 + */ + public Rectangle getBounds() { return bounds; } +} diff --git a/src/main/dev/lh/FoodFactory.java b/src/main/dev/lh/FoodFactory.java index f7c0b23..8811273 100755 --- a/src/main/dev/lh/FoodFactory.java +++ b/src/main/dev/lh/FoodFactory.java @@ -1,209 +1,69 @@ package dev.lh; -import java.awt.*; +import static java.awt.Color.*; + +import java.awt.Color; +import java.awt.Rectangle; import java.util.Random; -import dev.lh.ui.GameWindow; - /** + * Generates food items with predefined properties at random positions and calculates the next + * spawning time. + *

* Project: Snake
* File: FoodFactory.java
* Created: 11 Mar 2020
* * @author Leon Hofmeister + * @author Kai S. K. Engelbart * @since Snake 1.0 */ -public class FoodFactory { +public final class FoodFactory { + + private int width, height; + private long nextSpawnTime; + private Random random = new Random(); + + private static final Color[] FOOD_COLORS = { + WHITE, YELLOW, ORANGE, RED, BLUE + }; + private static final int[] FOOD_LENGTH_BONUSES = { + 40, 15, 6, 2, 1 + }; /** - * This enum contains all possible variations of foods. The higher the ordinal - * of an element, the less it is worth.
- *
- * Project: Snake
- * File: FoodFactory.java
- * Created: 11 Mar 2020
- * - * @author Leon Hofmeister - * @since Snake 1.0 + * Initializes a food factory. + * + * @param width the width of the viewport + * @param height the height of the viewport + * @since Snake 1.2 */ - public static enum Food { - /** - * Use if white food is wanted. - */ - white, - - /** - * Use if yellow food is wanted. - */ - yellow, - - /** - * Use if orange food is wanted. - */ - orange, - - /** - * Use if red food is wanted. - */ - red, - - /** - * Use if blue food is wanted. - */ - blue - } - - private static FoodFactory foodFactory = new FoodFactory(); - - private long timeOfNextFood; - - private Point pFood; - - private Food nextFood = Food.white; - - private int rectangleSize = 6; - - private FoodFactory() {} - - /** - * @return the (singleton) instance of FoodFactory - * @since Snake 1.0 - */ - public static FoodFactory getInstance() { return foodFactory; } - - /** - * @return a new {@link Food} object without its position - * @since Snake 1.0 - */ - public Food generateFood() { - nextFood = Food.values()[new Random().nextInt(Food.values().length)]; - rectangleSize = nextFood.ordinal() + 2; - setTimeToNextFoodMillis(); - return nextFood; + public FoodFactory(int width, int height) { + this.width = width; + this.height = height; } /** - * Generates the amount of time that needs to pass before the next food object - * will be constructed. - * - * @since Snake 1.0 + * @return a new food item + * @since Snake 1.2 */ - public void setTimeToNextFoodMillis() { - timeOfNextFood = System.currentTimeMillis() + new Random().nextInt(15000) + 1000; + public synchronized Food spawn() { + nextSpawnTime = System.currentTimeMillis() + random.nextInt(15000) + 1000; + int seed = random.nextInt(5); + return new Food( + FOOD_COLORS[seed], + FOOD_LENGTH_BONUSES[seed], + new Rectangle(random.nextInt(width - 100) + 50, + random.nextInt(height - 100) + 50, + 10 + seed * 5, + 10 + seed * 5 + ) + ); } /** - * @return the type of the next food - * @since Snake 1.0 + * @return the time after which a new food item should be spawned + * @since Snake 1.2 */ - public Food getNextFood() { return nextFood; } - - /** - * @param nextFood the type the next food should have - * @since Snake 1.0 - */ - public void setNext(Food nextFood) { this.nextFood = nextFood; } - - /** - * @return the time at which a new food object will be automatically created - * @since Snake 1.0 - */ - public long getTimeOfNextFood() { return timeOfNextFood; } - - /** - * @param width the width of the currently used {@link GameWindow} - * @param height the height of the currently used {@link GameWindow} - * @return the position of the new {@link Food} object - * @since Snake 1.0 - */ - public Point generateFoodLocation(int width, int height) { - assert (width > 100 && height > 100); - Random r = new Random(); - return pFood = new Point(r.nextInt(width - 100) + 50, r.nextInt(height - 100) + 50); - } - - /** - * @return the size of the corresponding food (length = width) - * @since Snake 1.0 - */ - public int getRectangleSize() { return rectangleSize; } - - /** - * @return the location of the currently displayed food - * @since Snake 1.0 - */ - public Point getFoodLocation() { return pFood; } - - /** - * Sets the color of the given {@link Graphics} object according to the type of - * food. - * - * @param g the graphics object to paint - * @since Snake 1.0 - */ - public void colorOfFood(Graphics g) { - switch (nextFood) { - case white: - g.setColor(Color.white); - break; - case yellow: - g.setColor(Color.yellow); - break; - case orange: - g.setColor(Color.orange); - break; - case red: - g.setColor(Color.red); - break; - case blue: - g.setColor(Color.blue); - break; - } - } - - /** - * @param g the {@link Graphics} object used to paint the current food object - * @since Snake 1.0 - */ - public void paintFood(Graphics g) { - colorOfFood(g); - g.fillRect(pFood.x, pFood.y, 5 * rectangleSize, 5 * rectangleSize); - } - - /** - * @param snakeHead the the head of a {@link Snake} object - * @return true if the current food intersects with the snakehead - * @since Snake 1.0 - */ - public boolean checkCollision(Rectangle snakeHead) { - int s = rectangleSize * 5; - Rectangle food = new Rectangle(pFood, new Dimension(s, s)); - return food.intersects(snakeHead); - } - - /** - * @return the length that will be added to the snake - * @since Snake 1.0 - */ - public int getAdditionalLength() { - int snakeAdditionalLength = 0; - switch (nextFood) { - case white: - snakeAdditionalLength = 40; - break; - case yellow: - snakeAdditionalLength = 15; - break; - case orange: - snakeAdditionalLength = 6; - break; - case red: - snakeAdditionalLength = 2; - break; - case blue: - snakeAdditionalLength = 1; - break; - } - return snakeAdditionalLength; - } + public long getNextSpawnTime() { return nextSpawnTime; } } diff --git a/src/main/dev/lh/Handler.java b/src/main/dev/lh/Handler.java new file mode 100644 index 0000000..9c00d10 --- /dev/null +++ b/src/main/dev/lh/Handler.java @@ -0,0 +1,54 @@ +package dev.lh; + +import java.awt.Graphics2D; + +/** + * Manages the state of game objects. + *

+ * Project: Snake
+ * File: Handler.java
+ * Created: 01.07.2020
+ * + * @author Kai S. K. Engelbart + * @since Snake 1.2 + */ +public final class Handler implements Updateable { + + private Snake snake = new Snake(7); + private FoodFactory foodFactory; + + private volatile Food food; + + /** + * Constructs a handler. + * + * @param snake the snake + * @param foodFactory the food factory + * @since Snake 1.2 + */ + public Handler(Snake snake, FoodFactory foodFactory) { + this.snake = snake; + this.foodFactory = foodFactory; + food = foodFactory.spawn(); + } + + @Override + public void tick() { + snake.tick(); + food.tick(); + + // Check for food collision + if (snake.getHead().intersects(food.getBounds())) { + snake.addLength(food.getLengthBonus()); + food = foodFactory.spawn(); + } + if (System.currentTimeMillis() > foodFactory.getNextSpawnTime()) + food = foodFactory.spawn(); + } + + @Override + public void render(Graphics2D g) { + snake.render(g); + food.render(g); + } +} diff --git a/src/main/dev/lh/Snake.java b/src/main/dev/lh/Snake.java index 2c41ed3..f0fa54d 100644 --- a/src/main/dev/lh/Snake.java +++ b/src/main/dev/lh/Snake.java @@ -1,11 +1,12 @@ 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; import dev.lh.ui.Endscreen; -import dev.lh.ui.GameWindow; /** * Project: Snake
@@ -31,30 +32,30 @@ 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 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 +64,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 +89,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() { @@ -107,71 +101,65 @@ public class Snake implements Updateable { Main.getGame().close(); } - /** - * @return the current {@link Direction} of the snake - * @since Snake 1.0 - */ - public Direction getRichtung() { return direction; } - @Override - public void nextFrame() { + public void tick() { 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 - if (!Main.getGame().getBounds().contains(tiles.get(0))) { + // TODO: Test on Linux + if (!Main.getGame().getBounds().contains(getHead())) { 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))) { - addLength(foodFactory.getAdditionalLength()); - GameWindow game = Main.getGame(); - game.newFood(); - } } @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); } + /** + * @return the current {@link Direction} of the snake + * @since Snake 1.2 + */ + public Direction getDirection() { return direction; } + /** * @param direction the new {@link Direction} of the snake * @since Snake 1.0 */ public void setDirection(Direction direction) { this.direction = direction; } + + /** + * @return a rectangle representing the head of the snake + * @since Snake 1.2 + */ + public Rectangle getHead() { return tiles.get(0); } } diff --git a/src/main/dev/lh/Updateable.java b/src/main/dev/lh/Updateable.java index f2f91c6..87b3f7d 100755 --- a/src/main/dev/lh/Updateable.java +++ b/src/main/dev/lh/Updateable.java @@ -1,10 +1,10 @@ package dev.lh; -import java.awt.Graphics; +import java.awt.Graphics2D; /** - * This interface contains everything that needs to updated regularly.
- *
+ * This interface contains everything that needs to be updated regularly. + *

* Project: Snake
* File: Updateable.java
* Created: 11 Mar 2020
@@ -18,15 +18,15 @@ public interface Updateable { * Here should the actions be implemented that are supposed to happen when a new * frame gets created. * - * @since Snake 1.0 + * @since Snake 1.2 */ - void nextFrame(); + default void tick() {} /** * 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); + default void render(Graphics2D g) {} } diff --git a/src/main/dev/lh/Viewport.java b/src/main/dev/lh/Viewport.java new file mode 100644 index 0000000..874c436 --- /dev/null +++ b/src/main/dev/lh/Viewport.java @@ -0,0 +1,98 @@ +package dev.lh; + +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Graphics2D; +import java.util.Timer; +import java.util.TimerTask; + +/** + * Implements a hardware-accelerated rendering loop. + *

+ * Project: Snake
+ * File: Viewport.java
+ * Created: 01.07.2020
+ * + * @author Kai S. K. Engelbart + * @since Snake 1.2 + */ +public class Viewport extends Canvas { + + private static final long serialVersionUID = 1L; + + // Enable OpenGL hardware acceleration + static { + System.setProperty("sun.java2d.trace", "timestamp,log,count"); + System.setProperty("sun.java2d.transaccel", "True"); + System.setProperty("sun.java2d.opengl", "True"); + } + + private Updateable gameRoot; + private Timer timer = new Timer(); + private TimerTask renderTask; + + /** + * @param gameRoot the game object responsible for updating the rest + * @since Snake 1.2 + */ + public Viewport(Updateable gameRoot) { + this.gameRoot = gameRoot; + setIgnoreRepaint(true); + } + + /** + * Starts the render task. + * + * @since Snake 1.2 + */ + public void start() { + if (renderTask != null) + renderTask.cancel(); + else + createBufferStrategy(2); + + renderTask = new TimerTask() { + + private long lastTime = System.currentTimeMillis(); + + @Override + public void run() { + long time = System.currentTimeMillis(); + double dt = (time - lastTime) * 1E-3; + lastTime = time; + // TODO: Delta time adjustment + gameRoot.tick(); + render(); + } + }; + + timer.schedule(renderTask, 0, 100); + } + + /** + * Stops the render task. + * + * @since Snake 1.2 + */ + public void stop() { + renderTask.cancel(); + } + + private void render() { + Graphics2D g = (Graphics2D) getBufferStrategy().getDrawGraphics(); + + // Clear the screen + g.setColor(Color.BLACK); + g.fillRect(0, 0, getWidth(), getHeight()); + + // Perform the actual rendering + gameRoot.render(g); + + // Flip buffers + g.dispose(); + getBufferStrategy().show(); + + // Synchronize with display refresh rate + getToolkit().sync(); + } +} diff --git a/src/main/dev/lh/ui/Endscreen.java b/src/main/dev/lh/ui/Endscreen.java index be5cb30..56fdc07 100644 --- a/src/main/dev/lh/ui/Endscreen.java +++ b/src/main/dev/lh/ui/Endscreen.java @@ -20,9 +20,9 @@ public class Endscreen extends JDialog { private static final long serialVersionUID = -4457484397259161063L; - private static final int goodOrBadResult = 200; - private final JPanel contentPanel = new JPanel(); - private final int score; + private static final int goodOrBadResult = 200; + private final JPanel contentPanel = new JPanel(); + private final int score; /** * Create the dialog. @@ -31,32 +31,33 @@ public class Endscreen extends JDialog { */ public Endscreen(int score) { this.score = score; - try { + setTitle("Endscreen"); + setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + setBounds(100, 100, 700, 700); + getContentPane().setLayout(new BorderLayout()); + contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); + contentPanel.setLayout(new BorderLayout(0, 0)); + getContentPane().add(contentPanel, BorderLayout.CENTER); - setTitle("Endscreen"); - setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); - setBounds(100, 100, 700, 700); - getContentPane().setLayout(new BorderLayout()); - contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); - contentPanel.setLayout(new BorderLayout(0, 0)); - getContentPane().add(contentPanel, BorderLayout.CENTER); + JButton btnNewButton = new JButton("Play again"); + btnNewButton.setMnemonic(KeyEvent.VK_ENTER); + btnNewButton.addActionListener(e -> { + Main.startGame(); + dispose(); + }); + btnNewButton.setFont(new Font("Times New Roman", Font.PLAIN, 15)); + contentPanel.add(btnNewButton, BorderLayout.SOUTH); - JButton btnNewButton = new JButton("Play again"); - btnNewButton.setMnemonic(KeyEvent.VK_ENTER); - btnNewButton.addActionListener(e -> { Main.startGame(); dispose(); }); - btnNewButton.setFont(new Font("Times New Roman", Font.PLAIN, 15)); - contentPanel.add(btnNewButton, BorderLayout.SOUTH); + JLabel lblDeinPunktestand = new JLabel("Dein Punktestand: " + String.valueOf(score)); + lblDeinPunktestand.setFont(new Font("Times New Roman", Font.PLAIN, 25)); + contentPanel.add(lblDeinPunktestand, BorderLayout.NORTH); - JLabel lblDeinPunktestand = new JLabel("Dein Punktestand: " + String.valueOf(score)); - lblDeinPunktestand.setFont(new Font("Times New Roman", Font.PLAIN, 25)); - contentPanel.add(lblDeinPunktestand, BorderLayout.NORTH); - - Image resultImage = Toolkit.getDefaultToolkit() - .getImage(this.getClass().getResource((score < goodOrBadResult) ? "/Try_Again.jpg" : "/1211548-200.png")); - resultImage.flush(); - } catch (Exception e) { - e.printStackTrace(); - } + Image resultImage = Toolkit.getDefaultToolkit() + .getImage( + this.getClass() + .getResource((score < goodOrBadResult) ? "/Try_Again.jpg" : "/1211548-200.png") + ); + resultImage.flush(); } /** diff --git a/src/main/dev/lh/ui/GameWindow.java b/src/main/dev/lh/ui/GameWindow.java index f315436..d190736 100755 --- a/src/main/dev/lh/ui/GameWindow.java +++ b/src/main/dev/lh/ui/GameWindow.java @@ -1,15 +1,14 @@ package dev.lh.ui; -import java.awt.*; +import java.awt.Dimension; +import java.awt.Rectangle; +import java.awt.Toolkit; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import javax.swing.JFrame; -import javax.swing.JPanel; -import javax.swing.Timer; -import dev.lh.FoodFactory; -import dev.lh.Snake; +import dev.lh.*; import dev.lh.Snake.Direction; /** @@ -22,21 +21,20 @@ import dev.lh.Snake.Direction; */ public class GameWindow extends JFrame { - private static final long serialVersionUID = 1L; - private Snake s = new Snake(7); - private FoodFactory foodFactory = FoodFactory.getInstance(); - private Timer timer; + private static final long serialVersionUID = 1L; + + private Viewport viewport; /** * @param title the title of the frame * @since Snake 1.0 */ public GameWindow(String title) { + // Initialize window super(title); Dimension size = Toolkit.getDefaultToolkit().getScreenSize(); setBounds(new Rectangle(size)); setLocation(0, 0); - setLocationRelativeTo(null); setMinimumSize(size); setPreferredSize(size); setMaximumSize(size); @@ -44,19 +42,14 @@ public class GameWindow extends JFrame { setResizable(false); setDefaultCloseOperation(EXIT_ON_CLOSE); - add(new JPanel() { + // Initialize game objects + Snake snake = new Snake(7); + FoodFactory foodFactory = new FoodFactory(getWidth(), getHeight()); + Handler handler = new Handler(snake, foodFactory); - private static final long serialVersionUID = 1L; - - @Override - protected void paintComponent(Graphics g) { - super.paintComponent(g); - g.setColor(Color.black); - g.fillRect(0, 0, super.getWidth(), super.getHeight()); - s.render(g); - foodFactory.paintFood(g); - } - }); + // Initialize viewport + viewport = new Viewport(handler); + add(viewport); addKeyListener(new KeyAdapter() { @@ -66,56 +59,40 @@ 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 (!snake.getDirection().equals(Direction.DOWN)) + snake.setDirection(Direction.UP); break; case KeyEvent.VK_A: case KeyEvent.VK_LEFT: - if (!s.getRichtung().equals(Direction.Right)) s.setDirection(Direction.Left); + if (!snake.getDirection().equals(Direction.RIGHT)) + snake.setDirection(Direction.LEFT); break; case KeyEvent.VK_S: case KeyEvent.VK_DOWN: - if (!s.getRichtung().equals(Direction.Up)) s.setDirection(Direction.Down); + if (!snake.getDirection().equals(Direction.UP)) + snake.setDirection(Direction.DOWN); break; case KeyEvent.VK_D: case KeyEvent.VK_RIGHT: - if (!s.getRichtung().equals(Direction.Left)) s.setDirection(Direction.Right); + if (!snake.getDirection().equals(Direction.LEFT)) + snake.setDirection(Direction.RIGHT); break; } } }); - newFood(); - timer = new Timer( - 50, - evt -> { - s.nextFrame(); - if (System.currentTimeMillis() >= foodFactory.getTimeOfNextFood()) - newFood(); - repaint(); - } - ); - timer.start(); - setVisible(true); + viewport.start(); } /** - * Generates new food. - * - * @since Snake 1.1 - */ - public void newFood() { - foodFactory.generateFood(); - foodFactory.generateFoodLocation(getWidth(), getHeight()); - } - - /** - * Disposes this frame + * Disposes this frame. * * @since Snake 1.1 */ public void close() { - timer.stop(); + viewport.stop(); + setVisible(false); dispose(); } } diff --git a/src/main/dev/lh/ui/StartScreen.java b/src/main/dev/lh/ui/StartScreen.java index c8d3cb9..0b908d7 100755 --- a/src/main/dev/lh/ui/StartScreen.java +++ b/src/main/dev/lh/ui/StartScreen.java @@ -21,13 +21,14 @@ import dev.lh.Main; */ public class StartScreen extends JFrame { - private static final long serialVersionUID = 6055940532003735543L; - private JPanel contentPane; + private static final long serialVersionUID = 6055940532003735543L; /** * Closes the application. */ - public static void close() { System.exit(0); } + public static void close() { + System.exit(0); + } /** * Launches Snake. @@ -43,31 +44,27 @@ public class StartScreen extends JFrame { * Create the frame. */ public StartScreen() { - try { - // readInHighscores(); - setTitle("Snake - Startscreen"); - setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - setBounds(500, 200, 550, 550); - contentPane = new JPanel(); - contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); - setContentPane(contentPane); + setTitle("Snake - Startscreen"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setBounds(500, 200, 550, 550); - JButton buPlay = new JButton("Start Game"); - buPlay.setBounds(158, 197, 190, 131); - buPlay.setText("Play Again"); - buPlay.setMnemonic(KeyEvent.VK_ENTER); - buPlay.setFont(new Font("Times New Roman", Font.PLAIN, 16)); - buPlay.addActionListener(a -> { - Main.startGame(); - setVisible(false); - dispose(); - System.gc(); - }); - contentPane.add(buPlay); - contentPane.setLayout(null); - setVisible(true); - } catch (Exception e) { - e.printStackTrace(); - } + JPanel contentPane = new JPanel(); + contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); + setContentPane(contentPane); + + JButton buPlay = new JButton("Start Game"); + buPlay.setBounds(158, 197, 190, 131); + buPlay.setText("Play Again"); + buPlay.setMnemonic(KeyEvent.VK_ENTER); + buPlay.setFont(new Font("Times New Roman", Font.PLAIN, 16)); + buPlay.addActionListener(a -> { + Main.startGame(); + setVisible(false); + dispose(); + System.gc(); + }); + contentPane.add(buPlay); + contentPane.setLayout(null); + setVisible(true); } }