import java.awt.*;
import java.awt.event.*;
import java.util.LinkedList;
import java.util.Random;
import javax.swing.*;
public class SnakeGame extends JPanel implements ActionListener {
private final int TILE_SIZE = 30;
private final int WIDTH = 600;
private final int HEIGHT = 600;
private final int NUM_TILES_X = WIDTH / TILE_SIZE;
private final int NUM_TILES_Y = HEIGHT / TILE_SIZE;
private LinkedList<Point> snake;
private Point food;
private int direction; // 0 = UP, 1 = RIGHT, 2 = DOWN, 3 = LEFT
private boolean gameOver;
private Timer timer;
public SnakeGame() {
setPreferredSize(new Dimension(WIDTH, HEIGHT));
setBackground(Color.BLACK);
addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (!gameOver) {
switch (e.getKeyCode()) {
case KeyEvent.VK_UP:
if (direction != 2) direction = 0;
break;
case KeyEvent.VK_RIGHT:
if (direction != 3) direction = 1;
break;
case KeyEvent.VK_DOWN:
if (direction != 0) direction = 2;
break;
case KeyEvent.VK_LEFT:
if (direction != 1) direction = 3;
break;
}
}
}
});
setFocusable(true);
snake = new LinkedList<>();
snake.add(new Point(NUM_TILES_X / 2, NUM_TILES_Y / 2));
direction = 1; // Starting direction: Right
gameOver = false;
spawnFood();
timer = new Timer(100, this);
timer.start();
}
@Override
public void actionPerformed(ActionEvent e) {
if (!gameOver) {
moveSnake();
checkCollision();
checkFoodCollision();
repaint();
}
}
private void moveSnake() {
Point head = snake.getFirst();
Point newHead = null;
switch (direction) {
case 0: // UP
newHead = new Point(head.x, head.y - 1);
break;
case 1: // RIGHT
newHead = new Point(head.x + 1, head.y);
break;
case 2: // DOWN
newHead = new Point(head.x, head.y + 1);
break;
case 3: // LEFT
newHead = new Point(head.x - 1, head.y);
break;
}
if (newHead != null) {
snake.addFirst(newHead);
snake.removeLast();
}
}
private void checkCollision() {
Point head = snake.getFirst();
// Check wall collision
if (head.x < 0 || head.x >= NUM_TILES_X || head.y < 0 || head.y >= NUM_TILES_Y) {
gameOver = true;
}
// Check self-collision
for (int i = 1; i < snake.size(); i++) {
if (head.equals(snake.get(i))) {
gameOver = true;
}
}
}
private void checkFoodCollision() {
Point head = snake.getFirst();
// Check if snake head has eaten food
if (head.equals(food)) {
snake.addLast(new Point(-1, -1)); // Add new segment to the tail
spawnFood(); // Respawn food
}
}
private void spawnFood() {
Random rand = new Random();
food = new Point(rand.nextInt(NUM_TILES_X), rand.nextInt(NUM_TILES_Y));
// Ensure food does not spawn on the snake
while (snake.contains(food)) {
food = new Point(rand.nextInt(NUM_TILES_X), rand.nextInt(NUM_TILES_Y));
}
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (gameOver) {
g.setColor(Color.RED);
g.setFont(new Font("Arial", Font.BOLD, 50));
g.drawString("Game Over", WIDTH / 4, HEIGHT / 2);
return;
}
// Draw the snake
g.setColor(Color.GREEN);
for (Point p : snake) {
g.fillRect(p.x * TILE_SIZE, p.y * TILE_SIZE, TILE_SIZE, TILE_SIZE);
}
// Draw the food
g.setColor(Color.RED);
g.fillRect(food.x * TILE_SIZE, food.y * TILE_SIZE, TILE_SIZE, TILE_SIZE);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Snake Game");
SnakeGame game = new SnakeGame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(game);
frame.pack();
frame.setVisible(true);
}
}