import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Random;
public class SnakeGame extends JPanel {
static final Color SNAKE_COLOR = new Color(66, 150, 66);
static final Color FRUIT_COLOR = new Color(239, 79, 30);
static final Color CELL_LINE_COLOR = new Color(239, 209, 127);
static final Color FIELD_BORDER_COLOR = new Color(92, 92, 239);
static final Color TEXT_COLOR = new Color(0, 0, 0);
static final Font TEXT_FONT = new Font("SansSerif", Font.PLAIN, 40);
static final Font HINT_FONT = new Font("SansSerif", Font.PLAIN, 14);
static final int MAX_TIMER_DELAY = 500;
static final int MIN_TIMER_DELAY = 50;
static final int TIMER_STEP = 50;
static final int LEVEL_STEP = 2;
int fieldCols, fieldRows, cellSize, paddingX, paddingY;
int currentDelay;
int score;
Snake snake;
Cell fruit;
Timer timer;
boolean isGameOver = false;
boolean isPaused = false;
Random random = new Random();
SnakeGame(int fieldCols, int fieldRows, int cellSize, int paddingX, int paddingY) {
this.fieldCols = fieldCols;
this.fieldRows = fieldRows;
this.cellSize = cellSize;
this.paddingX = paddingX;
this.paddingY = paddingY;
addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (KeyEvent.VK_R == e.getKeyCode()) restartGame();// Рестарт
if (KeyEvent.VK_P == e.getKeyCode()) isPaused = !isPaused;// Пауза
if (isGameOver || isPaused) return;
if (KeyEvent.VK_RIGHT == e.getKeyCode()) snake.setDirection(Direction.RIGHT);
if (KeyEvent.VK_LEFT == e.getKeyCode()) snake.setDirection(Direction.LEFT);
if (KeyEvent.VK_UP == e.getKeyCode()) snake.setDirection(Direction.UP);
if (KeyEvent.VK_DOWN == e.getKeyCode()) snake.setDirection(Direction.DOWN);
}
});
restartGame();
}
void increaseSpeed() {
currentDelay = Math.max(MIN_TIMER_DELAY, currentDelay - TIMER_STEP);
timer.setDelay(currentDelay);
}
void restartGame() {
snake = new Snake(fieldCols / 2, fieldRows / 2);
fruit = null;
isGameOver = false;
isPaused = false;
currentDelay = MAX_TIMER_DELAY;
score = 0;
if (timer != null) {
timer.stop();
}
timer = new Timer(currentDelay, e -> {
if (!isPaused && !isGameOver) {
updateGame();
}
repaint();
});
timer.start();
SwingUtilities.invokeLater(this::requestFocusInWindow);
}
void updateGame() {
if (fruit == null) generateFruit();
snake.update();
if (snake.isSelfIntersected() || isOutOfBounds()) {
isGameOver = true;
timer.stop();
return;
}
if (snake.getHead().samePosition(fruit)) {
fruit = null;
snake.grow();
score++;
if (score % LEVEL_STEP == 0) {
increaseSpeed();
}
}
}
boolean isOutOfBounds() {
return snake.getHead().x < 0 || snake.getHead().y < 0
|| snake.getHead().x >= fieldCols || snake.getHead().y >= fieldRows;
}
void generateFruit() {
int x, y;
do {
x = random.nextInt(0, fieldCols);
y = random.nextInt(0, fieldRows);
} while (snake.contains(x, y));
fruit = new Cell(x, y);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// Поле
g.setColor(CELL_LINE_COLOR);
for (int i = 0; i < fieldCols; i++) {
g.drawLine(i * cellSize + paddingX, paddingY, i * cellSize + paddingX, fieldRows * cellSize + paddingY);
}
for (int i = 1; i < fieldRows; i++) {
g.drawLine(paddingX, i * cellSize + paddingY, fieldCols * cellSize + paddingX, i * cellSize + paddingY);
}
g.setColor(FIELD_BORDER_COLOR);
g.drawRect(paddingX, paddingY, fieldCols * cellSize, fieldRows * cellSize);
//Фрукт
if (fruit != null) {
g.setColor(FRUIT_COLOR);
g.fillRoundRect(
fruit.x * cellSize + paddingX, fruit.y * cellSize + paddingY,
cellSize, cellSize,
cellSize / 10, cellSize / 10
);
}
// Змейка
g.setColor(SNAKE_COLOR);
for (Cell cell : snake.getBody()) {
g.fillRoundRect(
cell.x * cellSize + paddingX, cell.y * cellSize + paddingY,
cellSize, cellSize,
cellSize / 10, cellSize / 10
);
}
g.setFont(HINT_FONT);
g.setColor(TEXT_COLOR);
g.drawString("Arrows: move | P: pause | R: restart", paddingX, paddingY + fieldRows * cellSize + HINT_FONT.getSize());
g.drawString("SCORE: " + score, paddingX + fieldCols * cellSize + HINT_FONT.getSize(), paddingY + HINT_FONT.getSize());
int level = (MAX_TIMER_DELAY - currentDelay) / TIMER_STEP;
g.drawString("LEVEL: " + level, paddingX + fieldCols * cellSize + HINT_FONT.getSize(), paddingY + HINT_FONT.getSize() * 3);
g.setFont(TEXT_FONT);
if (isPaused) {
g.drawString(
"PAUSED",
paddingX + cellSize * fieldCols / 2 - TEXT_FONT.getSize() * 2,
paddingY + cellSize * fieldRows / 2 + TEXT_FONT.getSize() / 2
);
}
if (isGameOver) {
g.drawString(
"GAME OVER",
paddingX + cellSize * fieldCols / 2 - TEXT_FONT.getSize() * 3,
paddingY + cellSize * fieldRows / 2 + TEXT_FONT.getSize() / 2
);
}
}
}
import java.util.ArrayList;
public class Snake {
static final int INITIAL_LENGTH = 3;
private final ArrayList<Cell> body = new ArrayList<>();
private Direction direction = Direction.RIGHT;
private boolean isGrowing = false;
Snake(int x, int y) {
this.setDirection(Direction.RIGHT);
this.init(x, y);
}
void init(int x, int y) {
for (int i = 0; i < INITIAL_LENGTH; i++) {
body.add(new Cell(x - i, y));
}
}
ArrayList<Cell> getBody() {
return this.body;
}
Cell getHead() {
return body.getFirst();
}
void update() {
int lastX = body.getLast().x, lastY = body.getLast().y;
for (int i = body.size() - 1; i > 0; i--) {
body.get(i).x = body.get(i - 1).x;
body.get(i).y = body.get(i - 1).y;
}
getHead().x += direction.dx;
getHead().y += direction.dy;
if (isGrowing) {
body.add(new Cell(lastX, lastY));
isGrowing = false;
}
}
void setDirection(Direction newDirection) {
if (newDirection.dx == -direction.dx && newDirection.dy == direction.dy) return;
this.direction = newDirection;
}
boolean contains(int x, int y) {
for (Cell cell : body) {
if (cell.isAt(x, y)) {
return true;
}
}
return false;
}
void grow() {
isGrowing = true;
}
boolean isSelfIntersected() {
for (int i = 1; i < body.size(); i++) {
if (getHead().samePosition(body.get(i))) {
return true;
}
}
return false;
}
}
import javax.swing.*;
public class Main {
public static void main(String[] args) {
JFrame window = new JFrame();
window.setBounds(600, 400, 1000, 1000);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setFocusable(true);
SnakeGame snakeGame = new SnakeGame(10, 10, 30, 100, 20);
window.setContentPane(snakeGame);
window.setVisible(true);
SwingUtilities.invokeLater(snakeGame::requestFocusInWindow);
}
}
public class Cell {
int x, y;
public Cell(int x, int y) {
this.x = x;
this.y = y;
}
boolean samePosition(Cell cell) {
return cell.x == this.x && cell.y == this.y;
}
boolean isAt(int x, int y) {
return this.x == x && this.y == y;
}
}
public class Direction {
final int dx;
final int dy;
public Direction(int directionX, int directionY) {
this.dx = directionX;
this.dy = directionY;
}
public static final Direction LEFT = new Direction(-1, 0);
public static final Direction RIGHT = new Direction(1, 0);
public static final Direction UP = new Direction(0, -1);
public static final Direction DOWN = new Direction(0, 1);
}