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
|
# 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 |
Loading…
Reference in New Issue
Block a user