I am creating a simple snake game to help me learn some more java. I'm running into an error however when trying to create a method that properly tracks whether the snake collides with itself or not. I created a simple print statement to check if the method is able to properly detect when my snake runs into itself, which it does. However, it seems to activate whenever the snake runs into an apple. Here is my code:
import java.awt.*;
import java.util.Random;
import javax.swing.*;
public class GamePanel extends JPanel implements Runnable {
final static int SCREEN_HEIGHT = 780;
final static int SCREEN_WIDTH = 1435;
final int FPS = 10;
final static int UNIT_SIZE = 30;
Random random = new Random();
Thread GameThread;
KeyHandler keyH = new KeyHandler();
snake Snake = new snake(keyH);
apple Apple = new apple(Snake);
GamePanel() {
// panel set up
this.setPreferredSize(new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT));
this.setBackground(Color.black);
this.setFocusable(true);
this.setDoubleBuffered(true);
this.addKeyListener(keyH);
}
//starts the thread!
public void startGameThread() {
GameThread = new Thread(this);
GameThread.start();
}
@Override
public void run() {
/* this is the game loop. drawinterval = one second (in the form of nanoseconds)
* divided by the FPS so that we get the amount (0.16 in seconds) the game should update per sec.
* We get the current time, subtract it by the last system time, divide that by this drawinterval
* which will be a very small decimal that is added to delta. Once delta is one or over, we can
* actually update the game.
*/
double drawInterval = 1000000000/FPS;
double delta = 0;
long lastTime = System.nanoTime();
long currentTime;
long timer = 0;
int drawTime = 0;
while (GameThread != null) {
currentTime = System.nanoTime();
delta += (currentTime - lastTime) / drawInterval;
timer += currentTime - lastTime;
lastTime = currentTime;
if (delta >= 1) {
update();
repaint();
delta--;
drawTime++;
}
if (timer >= 1000000000) {
//System.out.println("FPS: " + drawTime);
drawTime = 0;
timer = 0;
}
}
}
public void update(){
Apple.checkCollision();
Snake.checkSnakeCollision();
Snake.update();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.WHITE);
// grid draw
// for (int i = 0; i < (SCREEN_HEIGHT/UNIT_SIZE); i++) {
//g2.drawLine(0, i*UNIT_SIZE,SCREEN_WIDTH,i*UNIT_SIZE);
//}
//for (int i = 0; i < SCREEN_WIDTH/UNIT_SIZE; i++) {
//g2.drawLine(i*UNIT_SIZE, 0, i*UNIT_SIZE, SCREEN_HEIGHT);
//}
Snake.draw(g2);
Apple.draw(g2);
g2.dispose();
}
}
import java.awt.Color;
import java.awt.Graphics2D;
import java.util.ArrayList;
public class snake {
KeyHandler kh;
int length = 0;
int xHead = 30;
int yHead = 30;
ArrayList<Integer[]> bodyParts = new ArrayList<Integer[]>();
apple myApple = new apple(this);
public snake(KeyHandler kh) {
this.kh = kh;
}
public void increaseLength() {
Integer[] newBodyPart = {xHead, yHead};
bodyParts.add(newBodyPart);
this.length++;
}
public void checkSnakeCollision() {
for (int i = 1; i < bodyParts.size(); i++) {
Integer[] cords = bodyParts.get(i);
int xBody = cords[0];
int yBody = cords[1];
if (xHead == xBody && yHead == yBody) {
System.out.println("OOF");
}
}
}
public void update(){
if (kh.direction == ("up")) {
yHead -= 30;
} else if (kh.direction == ("down")) {
yHead += 30;
} else if (kh.direction == ("left")) {
xHead -= 30;
} else if (kh.direction == ("right")) {
xHead += 30;
}
for (int i = bodyParts.size() - 1; i > 0; i--) {
Integer[] currentBodyPart = bodyParts.get(i);
Integer[] previousBodyPart = bodyParts.get(i - 1);
currentBodyPart[0] = previousBodyPart[0];
currentBodyPart[1] = previousBodyPart[1];
}
// Update the first body part to the head position
if (bodyParts.size() > 0) {
Integer[] firstBodyPart = bodyParts.get(0);
if (kh.direction == "up") {
firstBodyPart[0] = xHead;
firstBodyPart[1] = yHead + GamePanel.UNIT_SIZE;
} else if (kh.direction == "down") {
firstBodyPart[0] = xHead;
firstBodyPart[1] = yHead - GamePanel.UNIT_SIZE;
} else if (kh.direction == "left") {
firstBodyPart[0] = xHead + GamePanel.UNIT_SIZE;
firstBodyPart[1] = yHead;
} else if (kh.direction == "right") {
firstBodyPart[0] = xHead - GamePanel.UNIT_SIZE;
firstBodyPart[1] = yHead;
}
}
}
public void draw(Graphics2D g2) {
//draw snake
g2.setColor(Color.GREEN);
g2.fillRect(xHead, yHead, GamePanel.UNIT_SIZE, GamePanel.UNIT_SIZE);
for (Integer[] cords : bodyParts) {
int x = cords[0];
int y = cords[1];
g2.fillRect(x, y, GamePanel.UNIT_SIZE, GamePanel.UNIT_SIZE);
}
}
}
import java.awt.Color;
import java.awt.Graphics2D;
import java.util.Random;
public class apple {
Random random = new Random();
snake duck;
int appleX = GamePanel.UNIT_SIZE * random.nextInt(GamePanel.SCREEN_WIDTH/GamePanel.UNIT_SIZE);
int appleY = GamePanel.UNIT_SIZE * random.nextInt(GamePanel.SCREEN_HEIGHT/GamePanel.UNIT_SIZE);
public apple(snake duck) {
this.duck = duck;
}
public void checkCollision() {
if (duck.xHead == appleX && duck.yHead == appleY) {
duck.increaseLength();
update();
}
}
public int getAppleX() {
return appleX;
}
public int getAppleY() {
return appleY;
}
public void update() {
appleX = GamePanel.UNIT_SIZE * random.nextInt(GamePanel.SCREEN_WIDTH/GamePanel.UNIT_SIZE);
appleY = GamePanel.UNIT_SIZE * random.nextInt(GamePanel.SCREEN_HEIGHT/GamePanel.UNIT_SIZE);
}
public void draw(Graphics2D g2) {
//draw apple
g2.setColor(Color.RED);
g2.fillRect(appleX, appleY, GamePanel.UNIT_SIZE, GamePanel.UNIT_SIZE);
}
}
import java.awt.RenderingHints.Key;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class KeyHandler implements KeyListener {
public boolean upPressed = false;
public boolean downPressed = false;
public boolean rightPressed = false;
public boolean leftPressed = false;
public String direction;
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
int i = e.getKeyCode();
if (i == KeyEvent.VK_D) {
rightPressed = true;
direction = "right";
}
if (i == KeyEvent.VK_A) {
leftPressed = true;
direction = "left";
}
if (i == KeyEvent.VK_S) {
downPressed = true;
direction = "down";
}
if (i == KeyEvent.VK_W) {
upPressed = true;
direction = "up";
}
}
@Override
public void keyReleased(KeyEvent e) {
int i = e.getKeyCode();
if (i == KeyEvent.VK_D) {
rightPressed = false;
}
if (i == KeyEvent.VK_A){
leftPressed = false;
}
if (i == KeyEvent.VK_S) {
downPressed = false;
}
if (i == KeyEvent.VK_W) {
upPressed = false;
}
}
}
import java.awt.*;
import javax.swing.*;
public class main {
public static void main(String[] args) throws Exception {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setTitle("Snake");
GamePanel panel = new GamePanel();
frame.add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
panel.startGameThread();
}
}
I tried increasing the i value for the for loop in the checkSnakeCollision() method to 1 and have tried to make sure the method activates if the snake head is not colliding with an apple, neither worked.
public void update(){
Apple.checkCollision();
Snake.checkSnakeCollision();
Snake.update();
}
This is the problem. When you are checking collision of apple and snake, you are adding new point same as head in snake body. after that you are checking for same point in body as head. It will match because you have added that head point in "checkCollision" method.
You need to call "checkSnakeCollision" after "Snake.update" once head is propagate to new position then you need to check for collision.