Compare commits

...

24 Commits

Author SHA1 Message Date
delvh
3fe0bb72da
Update README.md 2020-07-07 21:08:28 +02:00
delvh
f7fbc8b3e4 Fixed text on Startscreen 2020-07-01 21:10:48 +02:00
delvh
daf55abd93 Commented any usage of images out 2020-07-01 20:58:14 +02:00
delvh
b584589459 Fixed issue with wrong WindowConstant 2020-07-01 20:31:55 +02:00
a039837e89
Merge pull request #5 from delvh/feature/optimized_pipeline
Optimized Ticking and Rendering
2020-07-01 18:17:13 +00:00
04931dfd99
Apply suggestions from code review
Co-authored-by: delvh <dev.lh@web.de>
2020-07-01 18:16:59 +00:00
7c55e049cf
Add ol' JDoc 2020-07-01 19:29:52 +02:00
52a4c876fa
Add new pipeline and other fun stuff 2020-07-01 19:19:50 +02:00
a8908f7e13
Simplify snake drawing and movement calculation 2020-07-01 16:18:59 +02:00
5651ea76b0
Remove some try statements and switches 2020-07-01 16:01:37 +02:00
a0b0c09e1d
Merge pull request #4 from delvh/feature/simplification
Simplified some calculations
2020-07-01 12:38:31 +00:00
7ca0a14ea2
Simplify FoodFactory#generateFoodLocation 2020-07-01 14:33:23 +02:00
9131d0e2fd
Simplify FoodFactory#generateFood 2020-07-01 14:29:00 +02:00
c7035ff2c5
Simplified some calculations 2020-06-30 19:29:50 +02:00
ad329447a9
Fix missing ImageIcon for PlayButton and repeated EndScreen Spawning (#3)
* Fix multiple EndScreen Instances spawning

* Removed `Play Again` icon

Co-authored-by: delvh <dev.lh@web.de>
2020-06-26 16:54:31 +02:00
delvh
ab584c187d Provisorically fixed bug resulting in an empty Endscreen
Still, the screen neither shows the Labels or the images
2020-06-18 13:08:57 +02:00
delvh
30011a0788
Update README.md 2020-04-03 11:10:48 +02:00
delvh
2f8a613b56
updated project description 2020-04-03 11:09:48 +02:00
delvh
8ff179a27d
Collision checking for outer bounds works apparentlly solely on Windows, commented out for now (#1)
* Cleaned up project

* Commented display of result-image out

* added TODO in outer-bounds checking in Snake
2020-04-03 10:43:24 +02:00
delvh
46223d60ca Updated missing Javadoc in whole repository
* reformatted whole repository
* fixed bug enabling 180° turnaround
2020-03-11 22:27:30 +01:00
delvh
5e879e5a3d Recovered most code of Snake, state: around v0.8.5 of before v1.0
only thing still not working: collision checking of foods (game crashes
when touching food)

code is mostly equal to previous version, minor improvements had to be
made to ensure functionality
2020-02-28 21:47:09 +01:00
delvh
073d9fe188 Finally found source code
Unfortunately, due to major complications while trying to upload it, the
source code will have lost most of its usability
2019-11-09 23:11:16 +01:00
delvh
6d162adde1
created license (finally)
still learning on how to use GitHub.
2019-11-05 17:07:24 +01:00
delvh
545ab6a32c
Add files via upload 2019-07-03 15:29:04 +02:00
22 changed files with 870 additions and 1 deletions

24
.classpath Executable file
View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<attributes>
<attribute name="module" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry including="**/*.java" kind="src" output="target/classes" path="src/main">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="src/main/resources"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="test" value="true"/>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

1
.gitignore vendored Executable file
View File

@ -0,0 +1 @@
/target/

17
.project Executable file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>Snake</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,8 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
org.eclipse.jdt.core.compiler.release=disabled
org.eclipse.jdt.core.compiler.source=1.8

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,4 @@
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1

21
LICENSE Executable file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 delvh
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

26
README.md Normal file → Executable file
View File

@ -1,2 +1,26 @@
# Snake # Snake
My advanced Hello World program is a version of the old game Snake My advanced Hello World program is a version of the old game Snake.
## Features
- normal playing experience of Snake but hardware-accelerated
- 5 different fruits that can be eaten to enlarge the Snake
- theoretically Start- and Endscreen, currently mostly unused
- theoretically visual display whether a result is good or bad, commented out for now as it does not appear to work as expected
## Classes
- Snake:
- stores the body parts, their position and the general direction of the Snake
- checks, whether the Snake touches itself, the outer bounds or food
- Main:
- the class where public static void main(String[] args){} is located
- stores the GameWindow used
- GameWindow:
- displays all visual components used in the game
- stores the Snake object
- FoodFactory:
- generates new Food
- other classes in the ui-package:
- as the name suggests, defines the visual appearance before and after games
## JAR of the final version
If you follow <a href="https://github.com/delvh/Snake/releases">**this link**</a> and click on release "Snake - Rattlesnake version", you can download the runnable JAR of how the project currently looks like.

Binary file not shown.

33
pom.xml Executable file
View File

@ -0,0 +1,33 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>Snake</groupId>
<artifactId>Snake</artifactId>
<version>0.0.1-SNAPSHOT</version>
<build>
<sourceDirectory>Snake/src</sourceDirectory>
<resources>
<resource>
<directory>Snake/src</directory>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
<resource>
<directory>Snake/src/dev/lh/snake</directory>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

54
src/main/dev/lh/Food.java Normal file
View File

@ -0,0 +1,54 @@
package dev.lh;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
/**
* Represents a food item.
* <p>
* Project: <strong>Snake</strong><br>
* File: <strong>Food.java</strong><br>
* Created: <strong>01.07.2020</strong><br>
*
* @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; }
}

View File

@ -0,0 +1,69 @@
package dev.lh;
import static java.awt.Color.*;
import java.awt.Color;
import java.awt.Rectangle;
import java.util.Random;
/**
* Generates food items with predefined properties at random positions and calculates the next
* spawning time.
* <p>
* Project: <strong>Snake</strong><br>
* File: <strong>FoodFactory.java</strong><br>
* Created: <strong>11 Mar 2020</strong><br>
*
* @author Leon Hofmeister
* @author Kai S. K. Engelbart
* @since Snake 1.0
*/
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
};
/**
* Initializes a food factory.
*
* @param width the width of the viewport
* @param height the height of the viewport
* @since Snake 1.2
*/
public FoodFactory(int width, int height) {
this.width = width;
this.height = height;
}
/**
* @return a new food item
* @since Snake 1.2
*/
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 time after which a new food item should be spawned
* @since Snake 1.2
*/
public long getNextSpawnTime() { return nextSpawnTime; }
}

View File

@ -0,0 +1,54 @@
package dev.lh;
import java.awt.Graphics2D;
/**
* Manages the state of game objects.
* <p>
* Project: <strong>Snake</strong><br>
* File: <strong>Handler.java</strong><br>
* Created: <strong>01.07.2020</strong><br>
*
* @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);
}
}

41
src/main/dev/lh/Main.java Executable file
View File

@ -0,0 +1,41 @@
package dev.lh;
import dev.lh.ui.GameWindow;
/**
* Project: <strong>Snake</strong><br>
* File: <strong>Main.java</strong><br>
* Created: <strong>11 Mar 2020</strong><br>
*
* @author Leon Hofmeister
* @since Snake 1.0
*/
public class Main {
private static GameWindow game;
/**
* @param args the program arguments
* @since Snake 1.0
*/
public static void main(String[] args) {
// if wanted, the StartScreen can be added here
startGame();
}
/**
* Starts a new game of Snake.
*
* @since Snake 1.0
*/
public static void startGame() {
game = new GameWindow("Snake");
game.setVisible(true);
}
/**
* @return the currently used game
* @since Snake 1.0
*/
public static GameWindow getGame() { return game; }
}

165
src/main/dev/lh/Snake.java Normal file
View File

@ -0,0 +1,165 @@
package dev.lh;
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;
/**
* Project: <strong>Snake</strong><br>
* File: <strong>Snake.java</strong><br>
* Created: <strong>11 Mar 2020</strong><br>
*
* @author Leon Hofmeister
* @since Snake 1.0
*/
public class Snake implements Updateable {
/**
* This enum contains all possible directions for the {@link Snake}.<br>
* <br>
* Project: <strong>Snake</strong><br>
* File: <strong>Snake.java</strong><br>
* Created: <strong>11 Mar 2020</strong><br>
*
* @author Leon Hofmeister
* @since Snake 1.0
*/
public enum Direction {
/**
* Use if the snake should head left.
*/
LEFT,
/**
* Use if the snake should head right.
*/
RIGHT,
/**
* Use if the snake should head up.
*/
UP,
/**
* Use if the snake should head down.
*/
DOWN;
}
private static Endscreen endscreen;
private Direction direction = Direction.RIGHT;
private int length;
private final List<Rectangle> tiles = new ArrayList<>();
private static final int TILE_SIZE = 10;
/**
* Constructs a new Snake with the given length in tiles.
*
* @param length the length of the snake in tiles
* @since Snake 1.0
*/
public Snake(int length) {
this.length = length;
// Add initial tiles
for (int i = 0; i < length; i++)
tiles.add(new Rectangle(320 - TILE_SIZE * i, 240, TILE_SIZE, TILE_SIZE));
}
/**
* 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) {
final Rectangle last = tiles.get(tiles.size() - 1);
for (int i = 0; i < additional; i++)
tiles.add(last);
length += additional;
}
/**
* @return whether the snake collides with itself
* @since Snake 1.1
*/
private boolean checkSelfCollision() {
return tiles.stream().skip(1).anyMatch(tiles.get(0)::contains);
}
/**
* @since Snake 1.1
*/
private void gameOver() {
Main.getGame().close();
endscreen = new Endscreen(length);
endscreen.setVisible(true);
}
@Override
public void tick() {
int velX = 0, velY = 0;
switch (direction) {
case UP:
velY = -TILE_SIZE;
break;
case DOWN:
velY = TILE_SIZE;
break;
case LEFT:
velX = -TILE_SIZE;
break;
case RIGHT:
velX = TILE_SIZE;
break;
}
// 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: Test on Linux
if (!Main.getGame().getBounds().contains(getHead())) {
gameOver();
System.out.println("Snake went out of bounds.");
return;
}
}
@Override
public void render(Graphics2D g) {
g.setColor(Color.green);
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); }
}

32
src/main/dev/lh/Updateable.java Executable file
View File

@ -0,0 +1,32 @@
package dev.lh;
import java.awt.Graphics2D;
/**
* This interface contains everything that needs to be updated regularly.
* <p>
* Project: <strong>Snake</strong><br>
* File: <strong>Updateable.java</strong><br>
* Created: <strong>11 Mar 2020</strong><br>
*
* @author Leon Hofmeister
* @since Snake 1.0
*/
public interface Updateable {
/**
* Here should the actions be implemented that are supposed to happen when a new
* frame gets created.
*
* @since Snake 1.2
*/
default void tick() {}
/**
* Renders the object.
*
* @param g the graphics object that is used to render this object
* @since Snake 1.0
*/
default void render(Graphics2D g) {}
}

View File

@ -0,0 +1,94 @@
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.
* <p>
* Project: <strong>Snake</strong><br>
* File: <strong>Viewport.java</strong><br>
* Created: <strong>01.07.2020</strong><br>
*
* @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() {
// final long time = System.currentTimeMillis();
// final 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() {
final 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();
}
}

View File

@ -0,0 +1,64 @@
package dev.lh.ui;
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.event.KeyEvent;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import dev.lh.Main;
/**
* Project: <strong>Snake</strong><br>
* File: <strong>Endscreen.java</strong><br>
* Created: <strong>11 Mar 2020</strong><br>
*
* @author Leon Hofmeister
* @since Snake v1.1
*/
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;
/**
* Create the dialog.
*
* @param score the highscore to set
*/
public Endscreen(int score) {
this.score = score;
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);
final 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);
final JLabel lblDeinPunktestand = new JLabel("Dein Punktestand: " + String.valueOf(score));
lblDeinPunktestand.setFont(new Font("Times New Roman", Font.PLAIN, 25));
contentPanel.add(lblDeinPunktestand, BorderLayout.NORTH);
// final Image resultImage = Toolkit.getDefaultToolkit()
// .getImage(this.getClass().getResource(score < goodOrBadResult ?
// "/Try_Again.jpg" : "/1211548-200.png"));
// resultImage.flush();
}
/**
* @return the highscore of the current game
* @since Snake 1.0
*/
public int getScore() { return score; }
}

View File

@ -0,0 +1,98 @@
package dev.lh.ui;
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 dev.lh.*;
import dev.lh.Snake.Direction;
/**
* Project: <strong>Snake</strong><br>
* File: <strong>GameWindow.java</strong><br>
* Created: <strong>11 Mar 2020</strong><br>
*
* @author Leon Hofmeister
* @since Snake 1.0
*/
public class GameWindow extends JFrame {
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);
setMinimumSize(size);
setPreferredSize(size);
setMaximumSize(size);
setExtendedState(getExtendedState() | JFrame.MAXIMIZED_BOTH);
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
// Initialize game objects
Snake snake = new Snake(7);
FoodFactory foodFactory = new FoodFactory(getWidth(), getHeight());
Handler handler = new Handler(snake, foodFactory);
// Initialize viewport
viewport = new Viewport(handler);
add(viewport);
addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
super.keyPressed(e);
switch (e.getKeyCode()) {
case KeyEvent.VK_W:
case KeyEvent.VK_UP:
if (!snake.getDirection().equals(Direction.DOWN))
snake.setDirection(Direction.UP);
break;
case KeyEvent.VK_A:
case KeyEvent.VK_LEFT:
if (!snake.getDirection().equals(Direction.RIGHT))
snake.setDirection(Direction.LEFT);
break;
case KeyEvent.VK_S:
case KeyEvent.VK_DOWN:
if (!snake.getDirection().equals(Direction.UP))
snake.setDirection(Direction.DOWN);
break;
case KeyEvent.VK_D:
case KeyEvent.VK_RIGHT:
if (!snake.getDirection().equals(Direction.LEFT))
snake.setDirection(Direction.RIGHT);
break;
}
}
});
setVisible(true);
viewport.start();
}
/**
* Disposes this frame.
*
* @since Snake 1.1
*/
public void close() {
viewport.stop();
setVisible(false);
dispose();
}
}

View File

@ -0,0 +1,63 @@
package dev.lh.ui;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.KeyEvent;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import dev.lh.Main;
/**
* Project: <strong>Snake</strong><br>
* File: <strong>StartScreen.java</strong><br>
* Created: <strong>11 Mar 2020</strong><br>
*
* @author Leon Hofmeister
* @since Snake 1.0
*/
public class StartScreen extends JFrame {
private static final long serialVersionUID = 6055940532003735543L;
/**
* Closes the application.
*/
public static void close() { System.exit(0); }
/**
* Launches Snake.
*
* @param args the program arguments
* @since Snake 1.0
*/
public static void main(String[] args) { EventQueue.invokeLater(StartScreen::new); }
/**
* Create the frame.
*/
public StartScreen() {
setTitle("Snake - Startscreen");
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setBounds(500, 200, 550, 550);
final JPanel contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
final JButton buPlay = new JButton("Start Game");
buPlay.setBounds(158, 197, 190, 131);
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);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

BIN
src/main/resources/Try_Again.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB