snake/src/main/dev/lh/Snake.java

172 lines
4.0 KiB
Java
Executable File

package dev.lh;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;
import dev.lh.ui.Endscreen;
import dev.lh.ui.GameWindow;
/**
* 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 static 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 FoodFactory foodFactory = FoodFactory.getInstance();
private static Endscreen endscreen;
private Direction Richtung;
private int length;
private List<Point> tiles = new ArrayList<>();
private final int snakeSize = 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;
Richtung = Direction.Right;
// adding the initial tiles of the snake
for (int i = 0; i < length; i++)
tiles.add(new Point(320 - snakeSize * i, 240));
}
@Override
public void nextFrame() {
int velX = 0, velY = 0;
switch (Richtung) {
case Up:
velY = -snakeSize;
break;
case Down:
velY = snakeSize;
break;
case Left:
velX = -snakeSize;
break;
case Right:
velX = snakeSize;
break;
}
Point next = (Point) tiles.get(0).clone(), cur;
tiles.get(0).x += velX;
tiles.get(0).y += velY;
for (int i = 1; i < length; i++) {
cur = tiles.get(i);
tiles.set(i, (Point) next.clone());
next = cur;
}
// case if snake is outside of the screen or touches itself
if (checkSelfCollision()) gameOver();
// TODO: the game bounds checking below appears to work on Windows, however throws a NullPointerException on Linux/UNIX systems
// if (!Main.getGame().getBounds().contains(tiles.get(0))) gameOver();
// case if snake eats food
if (foodFactory.checkCollision(new Rectangle(tiles.get(0).x, tiles.get(0).y, snakeSize, snakeSize))) {
addLength(foodFactory.getAdditionalLength());
GameWindow game = Main.getGame();
game.newFood();
}
}
/**
*
* @since Snake 1.1
*/
private void gameOver() {
endscreen = new Endscreen(length);
endscreen.setVisible(true);
Main.getGame().close();
}
/**
* @return whether the snake collides with itself
* @since Snake 1.1
*/
private boolean checkSelfCollision() {
Point headIndex = tiles.get(0);
Rectangle head = new Rectangle(headIndex.x, headIndex.y, snakeSize, snakeSize);
for (int index = 1; index < tiles.size(); index++) {
Point bodyIndex = tiles.get(index);
if (head.contains(new Rectangle(bodyIndex.x, bodyIndex.y, snakeSize, snakeSize))) return true;
}
return false;
}
@Override
public void render(Graphics g) {
g.setColor(Color.green);
for (int i = 0; i < length; i++)
g.fillRect(tiles.get(i).x, tiles.get(i).y, snakeSize, snakeSize);
}
/**
* @return the current {@link Direction} of the snake
* @since Snake 1.0
*/
public Direction getRichtung() { return Richtung; }
/**
* @param richtung the new {@link Direction} of the snake
* @since Snake 1.0
*/
public void setRichtung(Direction richtung) { Richtung = richtung; }
/**
* Adds the given length to the current snake object
*
* @param additional the number of tiles to add
* @since Snake 1.0
*/
public void addLength(int additional) {
Point last = tiles.get(tiles.size() - 1);
for (int i = 0; i < additional; i++)
tiles.add(last);
length += additional;
}
}