Simplify snake drawing and movement calculation

This commit is contained in:
Kai S. K. Engelbart 2020-07-01 16:18:59 +02:00
parent 5651ea76b0
commit a8908f7e13
No known key found for this signature in database
GPG Key ID: 0A48559CA32CB48F
4 changed files with 53 additions and 62 deletions

View File

@ -28,7 +28,7 @@ public class FoodFactory {
* @author Leon Hofmeister
* @since Snake 1.0
*/
public static enum Food {
public enum Food {
/**
* Use if white food is wanted.

View File

@ -1,6 +1,8 @@
package dev.lh;
import java.awt.*;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;
@ -31,30 +33,31 @@ public class Snake implements Updateable {
/**
* Use if the snake should head left.
*/
Left,
LEFT,
/**
* Use if the snake should head right.
*/
Right,
RIGHT,
/**
* Use if the snake should head up.
*/
Up,
UP,
/**
* Use if the snake should head down.
*/
Down;
DOWN;
}
private static FoodFactory foodFactory = FoodFactory.getInstance();
private static Endscreen endscreen;
private Direction direction;
private Direction direction = Direction.RIGHT;
private int length;
private List<Point> tiles = new ArrayList<>();
private final int snakeSize = 10;
private List<Rectangle> tiles = new ArrayList<>();
private static final int TILE_SIZE = 10;
/**
* Constructs a new Snake with the given length in tiles.
@ -64,20 +67,20 @@ public class Snake implements Updateable {
*/
public Snake(int length) {
this.length = length;
direction = Direction.Right;
// adding the initial tiles of the snake
// Add initial tiles
for (int i = 0; i < length; i++)
tiles.add(new Point(320 - snakeSize * i, 240));
tiles.add(new Rectangle(320 - TILE_SIZE * i, 240, TILE_SIZE, TILE_SIZE));
}
/**
* Adds the given length to the current snake object
* Increases the given length to the current snake object.
*
* @param additional the number of tiles to add
* @since Snake 1.0
*/
public void addLength(int additional) {
Point last = tiles.get(tiles.size() - 1);
Rectangle last = tiles.get(tiles.size() - 1);
for (int i = 0; i < additional; i++)
tiles.add(last);
length += additional;
@ -88,17 +91,10 @@ public class Snake implements Updateable {
* @since Snake 1.1
*/
private boolean checkSelfCollision() {
Point headIndex = tiles.get(0);
Rectangle head = new Rectangle(headIndex.x, headIndex.y, snakeSize, snakeSize);
for (int index = 1; index < tiles.size(); index++) {
Point bodyIndex = tiles.get(index);
if (head.contains(new Rectangle(bodyIndex.x, bodyIndex.y, snakeSize, snakeSize))) return true;
}
return false;
return tiles.stream().skip(1).anyMatch(tiles.get(0)::contains);
}
/**
*
* @since Snake 1.1
*/
private void gameOver() {
@ -117,45 +113,41 @@ public class Snake implements Updateable {
public void nextFrame() {
int velX = 0, velY = 0;
switch (direction) {
case Up:
velY = -snakeSize;
case UP:
velY = -TILE_SIZE;
break;
case Down:
velY = snakeSize;
case DOWN:
velY = TILE_SIZE;
break;
case Left:
velX = -snakeSize;
case LEFT:
velX = -TILE_SIZE;
break;
case Right:
velX = snakeSize;
case RIGHT:
velX = TILE_SIZE;
break;
}
Point next = (Point) tiles.get(0).clone(), cur;
tiles.get(0).x += velX;
tiles.get(0).y += velY;
for (int i = 1; i < length; i++) {
cur = tiles.get(i);
tiles.set(i, (Point) next.clone());
next = cur;
}
// case if snake is outside of the screen or touches itself
// Add a new tile at the front
tiles.add(
0,
new Rectangle(tiles.get(0).x + velX, tiles.get(0).y + velY, TILE_SIZE, TILE_SIZE)
);
// Remove the last tile
tiles.remove(tiles.size() - 1);
// Case if snake is outside of the screen or touches itself
if (checkSelfCollision()) {
gameOver();
System.out.println("Snake collided with itself.");
return;
}
// TODO: the game bounds checking below appears to work on Windows, however
// throws a NullPointerException on Linux/UNIX systems
// TODO: Test on Linux
if (!Main.getGame().getBounds().contains(tiles.get(0))) {
gameOver();
System.out.println("Snake went out of bounds.");
return;
}
// case if snake eats food
if (foodFactory.checkCollision(new Rectangle(tiles.get(0).x, tiles.get(0).y, snakeSize, snakeSize))) {
// TODO: Move to Food class
// Case if snake eats food
if (foodFactory.checkCollision(tiles.get(0))) {
addLength(foodFactory.getAdditionalLength());
GameWindow game = Main.getGame();
game.newFood();
@ -163,10 +155,9 @@ public class Snake implements Updateable {
}
@Override
public void render(Graphics g) {
public void render(Graphics2D g) {
g.setColor(Color.green);
for (int i = 0; i < length; i++)
g.fillRect(tiles.get(i).x, tiles.get(i).y, snakeSize, snakeSize);
tiles.forEach(g::fill);
}
/**

View File

@ -1,6 +1,6 @@
package dev.lh;
import java.awt.Graphics;
import java.awt.Graphics2D;
/**
* This interface contains everything that needs to be updated regularly.
@ -25,8 +25,8 @@ public interface Updateable {
/**
* Renders the object.
*
* @param g the {@link Graphics} object that is used to render this object
* @param g the graphics object that is used to render this object
* @since Snake 1.0
*/
void render(Graphics g);
void render(Graphics2D g);
}

View File

@ -52,8 +52,8 @@ public class GameWindow extends JFrame {
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.black);
g.fillRect(0, 0, super.getWidth(), super.getHeight());
s.render(g);
g.fillRect(0, 0, getWidth(), getHeight());
s.render((Graphics2D) g);
foodFactory.paintFood(g);
}
});
@ -66,19 +66,19 @@ public class GameWindow extends JFrame {
switch (e.getKeyCode()) {
case KeyEvent.VK_W:
case KeyEvent.VK_UP:
if (!s.getRichtung().equals(Direction.Down)) s.setDirection(Direction.Up);
if (!s.getRichtung().equals(Direction.DOWN)) s.setDirection(Direction.UP);
break;
case KeyEvent.VK_A:
case KeyEvent.VK_LEFT:
if (!s.getRichtung().equals(Direction.Right)) s.setDirection(Direction.Left);
if (!s.getRichtung().equals(Direction.RIGHT)) s.setDirection(Direction.LEFT);
break;
case KeyEvent.VK_S:
case KeyEvent.VK_DOWN:
if (!s.getRichtung().equals(Direction.Up)) s.setDirection(Direction.Down);
if (!s.getRichtung().equals(Direction.UP)) s.setDirection(Direction.DOWN);
break;
case KeyEvent.VK_D:
case KeyEvent.VK_RIGHT:
if (!s.getRichtung().equals(Direction.Left)) s.setDirection(Direction.Right);
if (!s.getRichtung().equals(Direction.LEFT)) s.setDirection(Direction.RIGHT);
break;
}
}