java制作贪吃蛇小游戏


头像
松龄
原创
发布时间: 2026-05-30 16:42:48 | 阅读数 0收藏数 0评论数 0
封面
本篇文章将带你用 Java Swing 从零实现经典的贪吃蛇小游戏。通过 JFrame 构建游戏窗口,使用 JPanel 绘制网格、蛇身与食物,借助 Timer 实现定时刷新,完成蛇的移动、吃食物、碰撞检测等核心功能。同时,我们将实现防止蛇回头、撞墙或撞到自己时游戏结束,并提供重新开始的功能,让游戏更加完整和有趣。
1

创建项目

如图所示创建一个名为snake的项目 因为我们不需要引入jar包所以不用创建maven项目

然后创建个包 com.snake

2

创建常量

如图所示我们新创建一个文件夹叫constants 里面创建一个类 叫SnakeConstant 代码如下

这个里面放的是一些我们的常量

package com.snake.constants;

/**
* @author gjq
* @version 1.0
* @description: 贪吃蛇的常量
* @date 2026/5/30 10:31
*/
public class SnakeConstant {

/**
* 窗体标题
*/
public static final String FRAME_TITLE = "DOIT-贪吃蛇";

/**
* 网格大小
*/
public static final int GRID_SIZE = 15;

/**
* 行数
*/
public static final int ROWS = 30;

/**
* 列数
*/
public static final int COLS = 30;

/**
* 窗体内容宽度
*/
public static final int FRAME_WIDTH = COLS * GRID_SIZE;

/**
* 窗体内容高度
*/
public static final int FRAME_HEIGHT = ROWS * GRID_SIZE;

/**
* 蛇的初始长度
*/
public static final int SNAKE_INIT_LENGTH = 3;

}


3

创建窗体

在com.snake 包下面创建一个类 名为 MainFrame 这个是用于跟窗体相关的代码

现在我们先设置一下固定的宽高查看一下效果

代码如下 效果如图

package com.snake;

import com.snake.constants.SnakeConstant;
import com.snake.domain.Node;

import javax.swing.*;
import java.awt.*;
import java.util.LinkedList;

/**
* @author gjq
* @version 1.0
* @description: 窗体构建类
* @date 2026/5/30 10:15
*/
public class MainFrame extends JFrame {

//创建窗体对象时,初始化船体参数
public MainFrame() {
// 构建窗体
initFrame();
// 窗体居中显示
setLocationRelativeTo(null);
}


// 初始化窗体参数
private void initFrame() {
// 设置窗体标题
setTitle(SnakeConstant.FRAME_TITLE);
// 设置窗体大小不能改变
setResizable(false);
// 设置大小
setSize(new Dimension(SnakeConstant.FRAME_WIDTH,SnakeConstant.FRAME_HEIGHT));
// 设置窗体关闭按钮的作用,是正常退出
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}


public static void main(String[] args) {
// 创建窗体,并显示在屏幕上
new MainFrame().setVisible(true);
}

}



4

构建网格

我们上一部是固定的宽高这一步通过pack();由内容撑开宽高

然后通过paintComponent进行循环画线再添加到窗体中去


代码如下 效果如图

package com.snake;

import com.snake.constants.SnakeConstant;
import com.snake.domain.Node;

import javax.swing.*;
import java.awt.*;
import java.util.LinkedList;

/**
* @author gjq
* @version 1.0
* @description: 窗体构建类
* @date 2026/5/30 10:15
*/
public class MainFrame extends JFrame {

//创建窗体对象时,初始化船体参数
public MainFrame() {
// 构建窗体
initFrame();
// 构建网格
initGamePanel();
// 内容撑开高度和宽度
pack();
// 窗体居中显示
setLocationRelativeTo(null);
}


// 初始化窗体参数
private void initFrame() {
// 设置窗体标题
setTitle(SnakeConstant.FRAME_TITLE);
// 设置窗体大小不能改变
setResizable(false);
// 设置窗体关闭按钮的作用,是正常退出
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

//构建棋盘
private void initGamePanel() {

JPanel panel = new JPanel() {

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
/* -------- 绘制网格 --------- */
g.setColor(Color.BLACK);
// 横线
for (int i = 0; i <= SnakeConstant.ROWS; i++) {
int y = i * SnakeConstant.GRID_SIZE;
g.drawLine(0, y, SnakeConstant.FRAME_WIDTH, y);
}
// 竖线
for (int i = 0; i <= SnakeConstant.COLS; i++) {
int x = i * SnakeConstant.GRID_SIZE;
g.drawLine(x, 0, x, SnakeConstant.FRAME_HEIGHT);
}

}
};

panel.setPreferredSize(new Dimension(SnakeConstant.FRAME_WIDTH, SnakeConstant.FRAME_HEIGHT));
// 添加到窗体中
add(panel);
}

public static void main(String[] args) {
// 创建窗体,并显示在屏幕上
new MainFrame().setVisible(true);
}

}


5

初始化蛇体

  1. 如图1所示 在domain包下面新建一个Node实体类 这个代表每个格子的节点

实体类代码如下

package com.snake.domain;

/**
* @author gjq
* @version 1.0
* @description: 节点实体类
* @date 2026/5/30 10:54
*/
public class Node {

private int x;
private int y;

public Node() {
}

public Node(int x, int y) {
this.x = x;
this.y = y;
}

public int getX() {
return x;
}

public void setX(int x) {
this.x = x;
}

public int getY() {
return y;
}

public void setY(int y) {
this.y = y;
}
}


然后创建一个Snake 类 这个里面是我们关于蛇的方法

代码如下 相当于我们循环创建了长度为3的node节点 后面我们把这些节点填充为黑色就是蛇体了

package com.snake;

import com.snake.domain.DirectionEnum;
import com.snake.constants.SnakeConstant;
import com.snake.domain.Node;

import java.util.LinkedList;

/**
* @author gjq
* @version 1.0
* @description: 蛇的相关方法
* @date 2026/5/30 11:02
*/
public class Snake {

// body
private LinkedList<Node> body;

// 创建蛇对象时,初始化蛇身
public Snake() {
initSnake();
}


// 初始化蛇身 3个节点
public void initSnake() {
body = new LinkedList<>();
// 获取x的初始位置
int x = SnakeConstant.COLS / 2;
// 获取y 的初始位置
int y = SnakeConstant.ROWS / 2;
// 根据方向生成初始节点
for (int i = 0; i < Math.min(x,SnakeConstant.SNAKE_INIT_LENGTH); i++) {
body.add(new Node(x - i, y));
}
}

// 获取蛇蛇身
public LinkedList<Node> getBody() {
return body;
}
}


窗体构建蛇体代码如下

相当于我们把刚刚创建好的节点填充了一个颜色 效果如图

package com.snake;

import com.snake.constants.SnakeConstant;
import com.snake.domain.Node;

import javax.swing.*;
import java.awt.*;

/**
* @author gjq
* @version 1.0
* @description: 窗体构建类
* @date 2026/5/30 10:15
*/
public class MainFrame extends JFrame {

// 初始化蛇的信息
private Snake snake = new Snake();

// 游戏棋盘
JPanel panel = null;


//创建窗体对象时,初始化船体参数
public MainFrame() {
// 构建窗体
initFrame();
// 构建网格
initGamePanel();
// 内容撑开高度和宽度
pack();
// 窗体居中显示
setLocationRelativeTo(null);
// 初始化蛇
initSnake();
}

// 构建蛇体
private void initSnake() {
snake = new Snake();
}

// 初始化窗体参数
private void initFrame() {
// 设置窗体标题
setTitle(SnakeConstant.FRAME_TITLE);
// 设置窗体大小不能改变
setResizable(false);
// 设置窗体关闭按钮的作用,是正常退出
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}


// 构建内容
private void initGamePanel() {

panel = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
/* -------- 绘制网格 --------- */
g.setColor(Color.BLACK);
// 横线
for (int i = 0; i <= SnakeConstant.ROWS; i++) {
int y = i * SnakeConstant.GRID_SIZE;
g.drawLine(0, y, SnakeConstant.FRAME_WIDTH, y);
}
// 竖线
for (int i = 0; i <= SnakeConstant.COLS; i++) {
int x = i * SnakeConstant.GRID_SIZE;
g.drawLine(x, 0, x, SnakeConstant.FRAME_HEIGHT);
}

/* -------- 绘制蛇 --------- */
for (Node node : snake.getBody()) {
// 填充颜色
g.fillRect(node.getX() * SnakeConstant.GRID_SIZE,
node.getY() * SnakeConstant.GRID_SIZE,
SnakeConstant.GRID_SIZE, SnakeConstant.GRID_SIZE);
}

}
};

panel.setPreferredSize(new Dimension(SnakeConstant.FRAME_WIDTH, SnakeConstant.FRAME_HEIGHT));
// 添加到窗体中
add(panel);
}


public static void main(String[] args) {
// 创建窗体,并显示在屏幕上
new MainFrame().setVisible(true);
}

}


6

蛇体自动移动

我们玩过贪吃蛇的都知道贪吃蛇即使我们不去动它 它也是会移动的

我们通过定时器来实现这个自动移动的功能 效果看视频3


首先创建一个enum类用于判断是向哪个方向移动的

如图1所示创建一个 DirectionEnum 然后代码如下 以下代码就代表我们上下左右四个方位

/**
* @author gjq
* @version 1.0
* @description: 移动方向enum
* @date 2026/5/30 11:39
*/
public enum DirectionEnum {
UP,DOWN,LEFT,RIGHT
}


然后我们需要在snake文件中创建一个移动方法 代码如下 我们把尾部的填充颜色删除头部填充颜色加一个就是移动的效果了

package com.snake;

import com.snake.domain.DirectionEnum;
import com.snake.constants.SnakeConstant;
import com.snake.domain.Node;

import java.util.LinkedList;

/**
* @author gjq
* @version 1.0
* @description: 蛇的相关方法
* @date 2026/5/30 11:02
*/
public class Snake {

// body
private LinkedList<Node> body;


public void setDirection(DirectionEnum direction) {
this.direction = direction;
}

// 蛇头运动的方向
private DirectionEnum direction = DirectionEnum.RIGHT;

// 创建蛇对象时,初始化蛇身
public Snake() {
initSnake();
}

/**
* 蛇的移动方法
*/
// 移动蛇身
public void move() {
Node head = body.getFirst();

// 计算移动增量
int dx = 0, dy = 0;
switch (direction) {
case LEFT -> dx = -1;
case RIGHT -> dx = 1;
case UP -> dy = -1;
case DOWN -> dy = 1;
}

// 新蛇头
Node newHead = new Node(head.getX() + dx, head.getY() + dy);

// 添加到头部
body.addFirst(newHead);
// 删除尾部
body.removeLast();
}


// 初始化蛇身 3个节点
public void initSnake() {
body = new LinkedList<>();
// 获取x的初始位置
int x = SnakeConstant.COLS / 2;
// 获取y 的初始位置
int y = SnakeConstant.ROWS / 2;
// 根据方向生成初始节点
for (int i = 0; i < Math.min(x,SnakeConstant.SNAKE_INIT_LENGTH); i++) {
body.add(new Node(x - i, y));
}
}

// 获取蛇蛇身
public LinkedList<Node> getBody() {
return body;
}
}

然后在 窗体构建里面添加一个定时器 每100毫秒更新一次就是我们的移动效果 效果看视频

代码如下

package com.snake;

import com.snake.constants.SnakeConstant;
import com.snake.domain.Node;

import javax.swing.*;
import java.awt.*;


/**
* @author gjq
* @version 1.0
* @description: 窗体构建类
* @date 2026/5/30 10:15
*/
public class MainFrame extends JFrame {

// 初始化蛇的信息
private Snake snake = new Snake();

//定义定时器
private Timer timer;

// 游戏棋盘
JPanel panel = null;


//创建窗体对象时,初始化船体参数
public MainFrame() {
// 构建窗体
initFrame();
// 构建网格
initGamePanel();
// 内容撑开高度和宽度
pack();
// 窗体居中显示
setLocationRelativeTo(null);
// 初始化蛇
initSnake();
//初始化定时器
initTimer();
}

// 构建蛇体
private void initSnake() {
snake = new Snake();
}

// 初始化窗体参数
private void initFrame() {
// 设置窗体标题
setTitle(SnakeConstant.FRAME_TITLE);
// 设置窗体大小不能改变
setResizable(false);
// 设置窗体关闭按钮的作用,是正常退出
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}


// 构建内容
private void initGamePanel() {

panel = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
/* -------- 绘制网格 --------- */
g.setColor(Color.BLACK);
// 横线
for (int i = 0; i <= SnakeConstant.ROWS; i++) {
int y = i * SnakeConstant.GRID_SIZE;
g.drawLine(0, y, SnakeConstant.FRAME_WIDTH, y);
}
// 竖线
for (int i = 0; i <= SnakeConstant.COLS; i++) {
int x = i * SnakeConstant.GRID_SIZE;
g.drawLine(x, 0, x, SnakeConstant.FRAME_HEIGHT);
}

/* -------- 绘制蛇 --------- */
for (Node node : snake.getBody()) {
// 填充颜色
g.fillRect(node.getX() * SnakeConstant.GRID_SIZE,
node.getY() * SnakeConstant.GRID_SIZE,
SnakeConstant.GRID_SIZE, SnakeConstant.GRID_SIZE);
}

}
};

panel.setPreferredSize(new Dimension(SnakeConstant.FRAME_WIDTH, SnakeConstant.FRAME_HEIGHT));
// 添加到窗体中
add(panel);
}


// 初始化定时器
private void initTimer() {
timer = new Timer(100, e -> {
snake.move();
panel.repaint();
});

timer.start();
}

public static void main(String[] args) {
// 创建窗体,并显示在屏幕上
new MainFrame().setVisible(true);
}

}



7

控制移动方向

我们手动控制移动方向也很简单 只需要监听键盘事件 把上下左右四个按键对应四个不同的enum进行修改即可 代码如下 效果看视频


package com.snake;

import com.snake.constants.SnakeConstant;
import com.snake.domain.DirectionEnum;
import com.snake.domain.Node;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
;

/**
* @author gjq
* @version 1.0
* @description: 窗体构建类
* @date 2026/5/30 10:15
*/
public class MainFrame extends JFrame {

// 初始化蛇的信息
private Snake snake = new Snake();

//定义定时器
private Timer timer;

// 游戏棋盘
JPanel panel = null;


//创建窗体对象时,初始化船体参数
public MainFrame() {
// 构建窗体
initFrame();
// 构建网格
initGamePanel();
// 内容撑开高度和宽度
pack();
// 窗体居中显示
setLocationRelativeTo(null);
// 初始化蛇
initSnake();
//初始化定时器
initTimer();
setKeyListener();
}

// 构建蛇体
private void initSnake() {
snake = new Snake();
}

// 初始化窗体参数
private void initFrame() {
// 设置窗体标题
setTitle(SnakeConstant.FRAME_TITLE);
// 设置窗体大小不能改变
setResizable(false);
// 设置窗体关闭按钮的作用,是正常退出
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}


// 构建内容
private void initGamePanel() {

panel = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
/* -------- 绘制网格 --------- */
g.setColor(Color.BLACK);
// 横线
for (int i = 0; i <= SnakeConstant.ROWS; i++) {
int y = i * SnakeConstant.GRID_SIZE;
g.drawLine(0, y, SnakeConstant.FRAME_WIDTH, y);
}
// 竖线
for (int i = 0; i <= SnakeConstant.COLS; i++) {
int x = i * SnakeConstant.GRID_SIZE;
g.drawLine(x, 0, x, SnakeConstant.FRAME_HEIGHT);
}

/* -------- 绘制蛇 --------- */
for (Node node : snake.getBody()) {
// 填充颜色
g.fillRect(node.getX() * SnakeConstant.GRID_SIZE,
node.getY() * SnakeConstant.GRID_SIZE,
SnakeConstant.GRID_SIZE, SnakeConstant.GRID_SIZE);
}

}
};

panel.setPreferredSize(new Dimension(SnakeConstant.FRAME_WIDTH, SnakeConstant.FRAME_HEIGHT));
// 添加到窗体中
add(panel);
}

//添加键盘监听
private void setKeyListener() {
addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
// 获取选择的值
DirectionEnum newDirection = switch (e.getKeyCode()) {
case KeyEvent.VK_UP -> DirectionEnum.UP;
case KeyEvent.VK_DOWN -> DirectionEnum.DOWN;
case KeyEvent.VK_LEFT -> DirectionEnum.LEFT;
case KeyEvent.VK_RIGHT -> DirectionEnum.RIGHT;
default -> null;
};
// 调整方向
if (newDirection != null) {
snake.setDirection(newDirection);
}
}
});
}


// 初始化定时器
private void initTimer() {
timer = new Timer(100, e -> {
snake.move();
panel.repaint();
});

timer.start();
}

public static void main(String[] args) {
// 创建窗体,并显示在屏幕上
new MainFrame().setVisible(true);
}

}


8

贪吃蛇死亡

贪吃蛇死亡有两种 一种是撞到边缘了 一种是碰到了自己的身体 撞到边缘我们需要判断他的位置是否为0或者最大长度

修改 Snake 代码如下

package com.snake;

import com.snake.domain.DirectionEnum;
import com.snake.constants.SnakeConstant;
import com.snake.domain.Node;

import java.util.LinkedList;

/**
* @author gjq
* @version 1.0
* @description: 蛇的相关方法
* @date 2026/5/30 11:02
*/
public class Snake {

// body
private LinkedList<Node> body;


public void setDirection(DirectionEnum direction) {
this.direction = direction;
}

// 蛇头运动的方向
private DirectionEnum direction = DirectionEnum.RIGHT;

// 创建蛇对象时,初始化蛇身
public Snake() {
initSnake();
}

/**
* 蛇的移动方法
*/
public boolean move() {
Node head = body.getFirst();


// 计算移动增量
int dx = 0, dy = 0;
switch (direction) {
case LEFT -> dx = -1;
case RIGHT -> dx = 1;
case UP -> dy = -1;
case DOWN -> dy = 1;
}

// 新蛇头
Node newHead = new Node(head.getX() + dx, head.getY() + dy);
if (!isLive(newHead)) {
return false;
}

// 添加到头部
body.addFirst(newHead);
// 删除尾部
body.removeLast();
return true;
}

/**
* 判断是否还活着
* @param newHead 新的头部
* @return 是否存活
*/
public boolean isLive(Node newHead) {

// 检测撞墙
if (newHead.getX() < 0 || newHead.getX() >= SnakeConstant.COLS ||
newHead.getY() < 0 || newHead.getY() >= SnakeConstant.ROWS) {
return false;
}

// 撞自己身体死亡
if (body.contains(newHead)) {
return false;
}
return true;
}


/**
* 初始化蛇身
*/
public void initSnake() {
body = new LinkedList<>();
// 获取x的初始位置
int x = SnakeConstant.COLS / 2;
// 获取y 的初始位置
int y = SnakeConstant.ROWS / 2;
// 根据方向生成初始节点
for (int i = 0; i < Math.min(x, SnakeConstant.SNAKE_INIT_LENGTH); i++) {
body.add(new Node(x - i, y));
}
}

/**
* 获取蛇蛇身
*
* @return
*/
public LinkedList<Node> getBody() {
return body;
}
}


修改MainFrame代码如下

package com.snake;

import com.snake.constants.SnakeConstant;
import com.snake.domain.DirectionEnum;
import com.snake.domain.Node;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
;

/**
* @author gjq
* @version 1.0
* @description: 窗体构建类
* @date 2026/5/30 10:15
*/
public class MainFrame extends JFrame {

// 初始化蛇的信息
private Snake snake = new Snake();

//定义定时器
private Timer timer;

// 游戏棋盘
JPanel panel = null;


//创建窗体对象时,初始化船体参数
public MainFrame() {
// 构建窗体
initFrame();
// 构建网格
initGamePanel();
// 内容撑开高度和宽度
pack();
// 窗体居中显示
setLocationRelativeTo(null);
// 初始化蛇
initSnake();
//初始化定时器
initTimer();
setKeyListener();
}

// 构建蛇体
private void initSnake() {
snake = new Snake();
}

// 初始化窗体参数
private void initFrame() {
// 设置窗体标题
setTitle(SnakeConstant.FRAME_TITLE);
// 设置窗体大小不能改变
setResizable(false);
// 设置窗体关闭按钮的作用,是正常退出
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}


// 构建内容
private void initGamePanel() {

panel = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
/* -------- 绘制网格 --------- */
g.setColor(Color.BLACK);
// 横线
for (int i = 0; i <= SnakeConstant.ROWS; i++) {
int y = i * SnakeConstant.GRID_SIZE;
g.drawLine(0, y, SnakeConstant.FRAME_WIDTH, y);
}
// 竖线
for (int i = 0; i <= SnakeConstant.COLS; i++) {
int x = i * SnakeConstant.GRID_SIZE;
g.drawLine(x, 0, x, SnakeConstant.FRAME_HEIGHT);
}

/* -------- 绘制蛇 --------- */
for (Node node : snake.getBody()) {
// 填充颜色
g.fillRect(node.getX() * SnakeConstant.GRID_SIZE,
node.getY() * SnakeConstant.GRID_SIZE,
SnakeConstant.GRID_SIZE, SnakeConstant.GRID_SIZE);
}

}
};

panel.setPreferredSize(new Dimension(SnakeConstant.FRAME_WIDTH, SnakeConstant.FRAME_HEIGHT));
// 添加到窗体中
add(panel);
}

//添加键盘监听
private void setKeyListener() {
addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
// 获取选择的值
DirectionEnum newDirection = switch (e.getKeyCode()) {
case KeyEvent.VK_UP -> DirectionEnum.UP;
case KeyEvent.VK_DOWN -> DirectionEnum.DOWN;
case KeyEvent.VK_LEFT -> DirectionEnum.LEFT;
case KeyEvent.VK_RIGHT -> DirectionEnum.RIGHT;
default -> null;
};
// 调整方向
if (newDirection != null) {
snake.setDirection(newDirection);
}
}
});
}


// 初始化定时器
private void initTimer() {
timer = new Timer(100, e -> {
boolean isLive = snake.move();
panel.repaint();

// 撞墙死亡
if (!isLive) {
// 停止游戏
((Timer) e.getSource()).stop();
JOptionPane.showMessageDialog(this, "游戏结束!蛇死亡了!");
}
});

timer.start();
}

public static void main(String[] args) {
// 创建窗体,并显示在屏幕上
new MainFrame().setVisible(true);
}

}




9

吃食物

首先我们创建一个food方法 用于放置食物的位置

循环是为了防止食物和蛇的身体位置重复

package com.snake;

import com.snake.constants.SnakeConstant;
import com.snake.domain.Node;

import java.util.Random;

/**
* @author gjq
* @version 1.0
* @description: 食物类
* @date 2026/5/30 16:03
*/
public class Food extends Node {

// 创建食物的时候,随机产生一个位置
public Food() {
reset(null);
}

/**
* 随机产生位置
* @param snake
*/
public void reset(Snake snake) {

Random r = new Random();

while (true) {
int x = r.nextInt(SnakeConstant.COLS);
int y = r.nextInt(SnakeConstant.ROWS);

if (snake == null) {
setX(x);
setY(y);
return;
}

boolean onSnake = false;

for (Node node : snake.getBody()) {
if (node.getX() == x && node.getY() == y) {
onSnake = true;
break;
}
}

if (!onSnake) {
setX(x);
setY(y);
return;
}
}
}


}


然后我们在snake的类里面 吃食物的方法代码如下

/**
* 吃食物
*/
public void eatFood(Food food) {
Node head = body.getFirst();
// 判断是否吃到了食物
if (head.getX() == food.getX() && head.getY() == food.getY()) {
int[] delta = getDelta();
Node newHead = new Node(head.getX() + delta[0], head.getY() + delta[1]);
body.addFirst(newHead);

// 重置食物位置
food.reset(this);
}
}

/**
* 获取当前方向的增量
*/
private int[] getDelta() {
int dx = 0, dy = 0;
switch (direction) {
case LEFT -> dx = -1;
case RIGHT -> dx = 1;
case UP -> dy = -1;
case DOWN -> dy = 1;
}
return new int[]{dx, dy};
}


然后在窗体类里面加上构建食物和吃食物的方法调用 代码如下

package com.snake;

import com.snake.constants.SnakeConstant;
import com.snake.domain.DirectionEnum;
import com.snake.domain.Node;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

/**
* @author gjq
* @version 1.0
* @description: 窗体构建类
* @date 2026/5/30 10:15
*/
public class MainFrame extends JFrame {

// 初始化蛇的信息
private final Snake snake = new Snake();

//定义定时器
private Timer timer;

// 游戏棋盘
private JPanel panel;

//定义食物
private final Food food = new Food();

//创建窗体对象时,初始化船体参数
public MainFrame() {
// 构建窗体
initFrame();
// 构建网格
initGamePanel();
// 内容撑开高度和宽度
pack();
// 窗体居中显示
setLocationRelativeTo(null);
// 初始化定时器
initTimer();
// 初始化键盘监听
setKeyListener();
// 显示窗口
setVisible(true);
}

// 初始化窗体参数
private void initFrame() {
// 设置窗体标题
setTitle(SnakeConstant.FRAME_TITLE);
// 设置窗体大小不能改变
setResizable(false);
// 设置窗体关闭按钮的作用,是正常退出
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

// 构建内容
private void initGamePanel() {

panel = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);

/* -------- 绘制网格 --------- */
g.setColor(Color.BLACK);

// 横线
for (int i = 0; i <= SnakeConstant.ROWS; i++) {
int y = i * SnakeConstant.GRID_SIZE;
g.drawLine(0, y,
SnakeConstant.getFrameWidth(), y);
}

// 竖线
for (int i = 0; i <= SnakeConstant.COLS; i++) {
int x = i * SnakeConstant.GRID_SIZE;
g.drawLine(x, 0,
x, SnakeConstant.getFrameHeight());
}

/* -------- 绘制蛇 --------- */
g.setColor(Color.BLACK);
for (Node node : snake.getBody()) {
g.fillRect(node.getX() * SnakeConstant.GRID_SIZE,
node.getY() * SnakeConstant.GRID_SIZE,
SnakeConstant.GRID_SIZE,
SnakeConstant.GRID_SIZE);
}

/* -------- 绘制食物 --------- */
g.setColor(Color.RED);
g.fillRect(food.getX() * SnakeConstant.GRID_SIZE,
food.getY() * SnakeConstant.GRID_SIZE,
SnakeConstant.GRID_SIZE,
SnakeConstant.GRID_SIZE);
}
};

panel.setPreferredSize(new Dimension(
SnakeConstant.getFrameWidth(),
SnakeConstant.getFrameHeight()
));

// 添加到窗体中
add(panel);
}

//添加键盘监听
private void setKeyListener() {
addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {

// 获取选择的值
DirectionEnum newDirection = switch (e.getKeyCode()) {
case KeyEvent.VK_UP -> DirectionEnum.UP;
case KeyEvent.VK_DOWN -> DirectionEnum.DOWN;
case KeyEvent.VK_LEFT -> DirectionEnum.LEFT;
case KeyEvent.VK_RIGHT -> DirectionEnum.RIGHT;
default -> null;
};

// 调整方向
if (newDirection != null) {
snake.setDirection(newDirection);
}
}
});
}

// 初始化定时器
private void initTimer() {

timer = new Timer(100, e -> {
// 移动
boolean isLive = snake.move();
// 吃食物
snake.eatFood(food);
panel.repaint();

// 撞墙死亡
if (!isLive) {
((Timer) e.getSource()).stop();
JOptionPane.showMessageDialog(this, "游戏结束!蛇死亡了!");
}
});

timer.start();
}

public static void main(String[] args) {
// 创建窗体,并显示在屏幕上
new MainFrame();
}

}



10

完整代码

完整代码在附件里 我额外做了一点优化 效果看视频

ZIP
snake.zip
35.86KB
阅读记录0
点赞0
收藏0
禁止 本文未经作者允许授权,禁止转载
猜你喜欢
评论/提问(已发布 0 条)
头像
评论 评论
收藏 收藏
分享 分享
pdf下载 下载
pdf下载 举报