Simplify snake drawing and movement calculation
This commit is contained in:
parent
5651ea76b0
commit
a8908f7e13
@ -28,7 +28,7 @@ public class FoodFactory {
|
|||||||
* @author Leon Hofmeister
|
* @author Leon Hofmeister
|
||||||
* @since Snake 1.0
|
* @since Snake 1.0
|
||||||
*/
|
*/
|
||||||
public static enum Food {
|
public enum Food {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use if white food is wanted.
|
* Use if white food is wanted.
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package dev.lh;
|
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.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -31,30 +33,31 @@ public class Snake implements Updateable {
|
|||||||
/**
|
/**
|
||||||
* Use if the snake should head left.
|
* Use if the snake should head left.
|
||||||
*/
|
*/
|
||||||
Left,
|
LEFT,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use if the snake should head right.
|
* Use if the snake should head right.
|
||||||
*/
|
*/
|
||||||
Right,
|
RIGHT,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use if the snake should head up.
|
* Use if the snake should head up.
|
||||||
*/
|
*/
|
||||||
Up,
|
UP,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use if the snake should head down.
|
* Use if the snake should head down.
|
||||||
*/
|
*/
|
||||||
Down;
|
DOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static FoodFactory foodFactory = FoodFactory.getInstance();
|
private static FoodFactory foodFactory = FoodFactory.getInstance();
|
||||||
private static Endscreen endscreen;
|
private static Endscreen endscreen;
|
||||||
private Direction direction;
|
private Direction direction = Direction.RIGHT;
|
||||||
private int length;
|
private int length;
|
||||||
private List<Point> tiles = new ArrayList<>();
|
private List<Rectangle> tiles = new ArrayList<>();
|
||||||
private final int snakeSize = 10;
|
|
||||||
|
private static final int TILE_SIZE = 10;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new Snake with the given length in tiles.
|
* Constructs a new Snake with the given length in tiles.
|
||||||
@ -64,20 +67,20 @@ public class Snake implements Updateable {
|
|||||||
*/
|
*/
|
||||||
public Snake(int length) {
|
public Snake(int length) {
|
||||||
this.length = length;
|
this.length = length;
|
||||||
direction = Direction.Right;
|
|
||||||
// adding the initial tiles of the snake
|
// Add initial tiles
|
||||||
for (int i = 0; i < length; i++)
|
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
|
* @param additional the number of tiles to add
|
||||||
* @since Snake 1.0
|
* @since Snake 1.0
|
||||||
*/
|
*/
|
||||||
public void addLength(int additional) {
|
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++)
|
for (int i = 0; i < additional; i++)
|
||||||
tiles.add(last);
|
tiles.add(last);
|
||||||
length += additional;
|
length += additional;
|
||||||
@ -88,17 +91,10 @@ public class Snake implements Updateable {
|
|||||||
* @since Snake 1.1
|
* @since Snake 1.1
|
||||||
*/
|
*/
|
||||||
private boolean checkSelfCollision() {
|
private boolean checkSelfCollision() {
|
||||||
Point headIndex = tiles.get(0);
|
return tiles.stream().skip(1).anyMatch(tiles.get(0)::contains);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @since Snake 1.1
|
* @since Snake 1.1
|
||||||
*/
|
*/
|
||||||
private void gameOver() {
|
private void gameOver() {
|
||||||
@ -117,45 +113,41 @@ public class Snake implements Updateable {
|
|||||||
public void nextFrame() {
|
public void nextFrame() {
|
||||||
int velX = 0, velY = 0;
|
int velX = 0, velY = 0;
|
||||||
switch (direction) {
|
switch (direction) {
|
||||||
case Up:
|
case UP:
|
||||||
velY = -snakeSize;
|
velY = -TILE_SIZE;
|
||||||
break;
|
break;
|
||||||
case Down:
|
case DOWN:
|
||||||
velY = snakeSize;
|
velY = TILE_SIZE;
|
||||||
break;
|
break;
|
||||||
case Left:
|
case LEFT:
|
||||||
velX = -snakeSize;
|
velX = -TILE_SIZE;
|
||||||
break;
|
break;
|
||||||
case Right:
|
case RIGHT:
|
||||||
velX = snakeSize;
|
velX = TILE_SIZE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Point next = (Point) tiles.get(0).clone(), cur;
|
// Add a new tile at the front
|
||||||
tiles.get(0).x += velX;
|
tiles.add(
|
||||||
tiles.get(0).y += velY;
|
0,
|
||||||
|
new Rectangle(tiles.get(0).x + velX, tiles.get(0).y + velY, TILE_SIZE, TILE_SIZE)
|
||||||
for (int i = 1; i < length; i++) {
|
);
|
||||||
cur = tiles.get(i);
|
// Remove the last tile
|
||||||
tiles.set(i, (Point) next.clone());
|
tiles.remove(tiles.size() - 1);
|
||||||
next = cur;
|
// Case if snake is outside of the screen or touches itself
|
||||||
}
|
|
||||||
|
|
||||||
// case if snake is outside of the screen or touches itself
|
|
||||||
if (checkSelfCollision()) {
|
if (checkSelfCollision()) {
|
||||||
gameOver();
|
gameOver();
|
||||||
System.out.println("Snake collided with itself.");
|
System.out.println("Snake collided with itself.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// TODO: the game bounds checking below appears to work on Windows, however
|
// TODO: Test on Linux
|
||||||
// throws a NullPointerException on Linux/UNIX systems
|
|
||||||
if (!Main.getGame().getBounds().contains(tiles.get(0))) {
|
if (!Main.getGame().getBounds().contains(tiles.get(0))) {
|
||||||
gameOver();
|
gameOver();
|
||||||
System.out.println("Snake went out of bounds.");
|
System.out.println("Snake went out of bounds.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// TODO: Move to Food class
|
||||||
// case if snake eats food
|
// Case if snake eats food
|
||||||
if (foodFactory.checkCollision(new Rectangle(tiles.get(0).x, tiles.get(0).y, snakeSize, snakeSize))) {
|
if (foodFactory.checkCollision(tiles.get(0))) {
|
||||||
addLength(foodFactory.getAdditionalLength());
|
addLength(foodFactory.getAdditionalLength());
|
||||||
GameWindow game = Main.getGame();
|
GameWindow game = Main.getGame();
|
||||||
game.newFood();
|
game.newFood();
|
||||||
@ -163,10 +155,9 @@ public class Snake implements Updateable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(Graphics g) {
|
public void render(Graphics2D g) {
|
||||||
g.setColor(Color.green);
|
g.setColor(Color.green);
|
||||||
for (int i = 0; i < length; i++)
|
tiles.forEach(g::fill);
|
||||||
g.fillRect(tiles.get(i).x, tiles.get(i).y, snakeSize, snakeSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package dev.lh;
|
package dev.lh;
|
||||||
|
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics2D;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This interface contains everything that needs to be updated regularly.
|
* This interface contains everything that needs to be updated regularly.
|
||||||
@ -25,8 +25,8 @@ public interface Updateable {
|
|||||||
/**
|
/**
|
||||||
* Renders the object.
|
* 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
|
* @since Snake 1.0
|
||||||
*/
|
*/
|
||||||
void render(Graphics g);
|
void render(Graphics2D g);
|
||||||
}
|
}
|
||||||
|
@ -52,8 +52,8 @@ public class GameWindow extends JFrame {
|
|||||||
protected void paintComponent(Graphics g) {
|
protected void paintComponent(Graphics g) {
|
||||||
super.paintComponent(g);
|
super.paintComponent(g);
|
||||||
g.setColor(Color.black);
|
g.setColor(Color.black);
|
||||||
g.fillRect(0, 0, super.getWidth(), super.getHeight());
|
g.fillRect(0, 0, getWidth(), getHeight());
|
||||||
s.render(g);
|
s.render((Graphics2D) g);
|
||||||
foodFactory.paintFood(g);
|
foodFactory.paintFood(g);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -66,19 +66,19 @@ public class GameWindow extends JFrame {
|
|||||||
switch (e.getKeyCode()) {
|
switch (e.getKeyCode()) {
|
||||||
case KeyEvent.VK_W:
|
case KeyEvent.VK_W:
|
||||||
case KeyEvent.VK_UP:
|
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;
|
break;
|
||||||
case KeyEvent.VK_A:
|
case KeyEvent.VK_A:
|
||||||
case KeyEvent.VK_LEFT:
|
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;
|
break;
|
||||||
case KeyEvent.VK_S:
|
case KeyEvent.VK_S:
|
||||||
case KeyEvent.VK_DOWN:
|
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;
|
break;
|
||||||
case KeyEvent.VK_D:
|
case KeyEvent.VK_D:
|
||||||
case KeyEvent.VK_RIGHT:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user