Compare commits
	
		
			24 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 3fe0bb72da | ||
|   | f7fbc8b3e4 | ||
|   | daf55abd93 | ||
|   | b584589459 | ||
| a039837e89 | |||
| 04931dfd99 | |||
| 7c55e049cf | |||
| 52a4c876fa | |||
| a8908f7e13 | |||
| 5651ea76b0 | |||
| a0b0c09e1d | |||
| 7ca0a14ea2 | |||
| 9131d0e2fd | |||
| c7035ff2c5 | |||
| ad329447a9 | |||
|   | ab584c187d | ||
|   | 30011a0788 | ||
|   | 2f8a613b56 | ||
|   | 8ff179a27d | ||
|   | 46223d60ca | ||
|   | 5e879e5a3d | ||
|   | 073d9fe188 | ||
|   | 6d162adde1 | ||
|   | 545ab6a32c | 
							
								
								
									
										24
									
								
								.classpath
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										24
									
								
								.classpath
									
									
									
									
									
										Executable 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
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -0,0 +1 @@ | ||||
| /target/ | ||||
							
								
								
									
										17
									
								
								.project
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										17
									
								
								.project
									
									
									
									
									
										Executable 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> | ||||
							
								
								
									
										8
									
								
								.settings/org.eclipse.jdt.core.prefs
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										8
									
								
								.settings/org.eclipse.jdt.core.prefs
									
									
									
									
									
										Executable 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 | ||||
							
								
								
									
										3
									
								
								.settings/org.eclipse.jdt.ui.prefs
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										3
									
								
								.settings/org.eclipse.jdt.ui.prefs
									
									
									
									
									
										Executable file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										4
									
								
								.settings/org.eclipse.m2e.core.prefs
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										4
									
								
								.settings/org.eclipse.m2e.core.prefs
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| activeProfiles= | ||||
| eclipse.preferences.version=1 | ||||
| resolveWorkspaceProjects=true | ||||
| version=1 | ||||
							
								
								
									
										21
									
								
								LICENSE
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										21
									
								
								LICENSE
									
									
									
									
									
										Executable 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
									
								
							
							
						
						
									
										26
									
								
								README.md
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @@ -1,2 +1,26 @@ | ||||
| # 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
									
								
							
							
						
						
									
										33
									
								
								pom.xml
									
									
									
									
									
										Executable 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
									
								
							
							
						
						
									
										54
									
								
								src/main/dev/lh/Food.java
									
									
									
									
									
										Normal 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; } | ||||
| } | ||||
							
								
								
									
										69
									
								
								src/main/dev/lh/FoodFactory.java
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										69
									
								
								src/main/dev/lh/FoodFactory.java
									
									
									
									
									
										Executable 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; } | ||||
| } | ||||
							
								
								
									
										54
									
								
								src/main/dev/lh/Handler.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/main/dev/lh/Handler.java
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										41
									
								
								src/main/dev/lh/Main.java
									
									
									
									
									
										Executable 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
									
								
							
							
						
						
									
										165
									
								
								src/main/dev/lh/Snake.java
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										32
									
								
								src/main/dev/lh/Updateable.java
									
									
									
									
									
										Executable 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) {} | ||||
| } | ||||
							
								
								
									
										94
									
								
								src/main/dev/lh/Viewport.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								src/main/dev/lh/Viewport.java
									
									
									
									
									
										Normal 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(); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										64
									
								
								src/main/dev/lh/ui/Endscreen.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								src/main/dev/lh/ui/Endscreen.java
									
									
									
									
									
										Normal 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; } | ||||
| } | ||||
							
								
								
									
										98
									
								
								src/main/dev/lh/ui/GameWindow.java
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										98
									
								
								src/main/dev/lh/ui/GameWindow.java
									
									
									
									
									
										Executable 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(); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										63
									
								
								src/main/dev/lh/ui/StartScreen.java
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										63
									
								
								src/main/dev/lh/ui/StartScreen.java
									
									
									
									
									
										Executable 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); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										
											BIN
										
									
								
								src/main/resources/1211548-200.png
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/main/resources/1211548-200.png
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 5.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/main/resources/Try_Again.jpg
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/main/resources/Try_Again.jpg
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 11 KiB | 
		Reference in New Issue
	
	Block a user