Java贪吃蛇小游戏
贪吃蛇
思路
首先构思游戏布局,计算合理的坐标系。
绘制静态数据(广告、初始小蛇、提示信息、棋盘)

添加键盘监听事件,改变游戏状态以及小蛇运动方向
添加定时器,让小蛇在一段时间内移动一定的距离
随机产生食物,并监听食物状态是否被吃
处理游戏结束事件
扩展相关游戏机制(积分、等级)
- 定义数据
- 绘制图像
- 事件监听
注意事项
导入文件资源时,通过类的相对路径获取
URL headURL = Data.class.getResource("header.png"); // 这是放在源代码同一个包下的文件
URL headURL = Data.class.getResource("/header.png"); // 这是放在项目根目录下的文件
键盘监听时,需要自动获取焦点。
- this.setFocusable(true); // 获取焦点
this.addKeyListener(new MyKeyListener());
- this.setFocusable(true); // 获取焦点
在修改数据之后,需要repaint重绘图形
小蛇运动时,需要注意边界问题
食物随机产生的坐标也要限制在游戏区域内
添加游戏的可玩性
具体实现
Data.java 存放所有图像数据
package snake;
import javax.swing.*;
import java.net.URL;
/**
* 数据中心
*/
public class Data {
// 相对路径
// 绝对路径 / 当前项目-->"GUI编程目录"
public static URL headURL = Data.class.getResource("header.png");
public static URL upURL = Data.class.getResource("up.png");
public static URL downURL = Data.class.getResource("down.png");
public static URL leftURL = Data.class.getResource("left.png");
public static URL rightURL = Data.class.getResource("right.png");
public static URL bodyURL = Data.class.getResource("body.png");
public static URL foodURL = Data.class.getResource("food.png");
public static URL foodURL2 = Data.class.getResource("food2.png");
public static ImageIcon header = new ImageIcon(headURL);
public static ImageIcon up = new ImageIcon(upURL);
public static ImageIcon down = new ImageIcon(downURL);
public static ImageIcon left = new ImageIcon(leftURL);
public static ImageIcon right = new ImageIcon(rightURL);
public static ImageIcon body = new ImageIcon(bodyURL);
public static ImageIcon food = new ImageIcon(foodURL);
public static ImageIcon food2 = new ImageIcon(foodURL2);
}
StartGame.java 游戏启动类
package snake;
import javax.swing.*;
import java.awt.*;
public class StartGame {
public static void main(String[] args) {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
int screenWidth = (int) screenSize.getWidth();
int screenHeight = (int) screenSize.getHeight();
System.out.println("屏幕宽度:" + screenWidth + ",屏幕高度:" + screenHeight);
// 本游戏固定窗体大小(900,720)不可变
int x = (screenWidth - 900) / 2;
int y = (screenHeight - 720) / 2;
System.out.println("相对坐标x:" + x + ",y:" + y);
JFrame jFrame = new JFrame("贪吃蛇");
jFrame.setBounds(x, y, 900, 720);
jFrame.setResizable(false);
jFrame.add(new GamePanel());
jFrame.setVisible(true);
jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
}
GamePanel.java 处理游戏逻辑
package snake;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Random;
public class GamePanel extends JPanel {
// 蛇的数据结构
int length;
int[] snakeX = new int[600];
int[] snakeY = new int[500];
char direction;
// 食物的坐标
int foodx;
int foody;
Random random = new Random();
// 计数器
int count;
int score;
int worth;
boolean isStart;
boolean isFail;
// 定时器,每隔100毫秒执行一次参数的事件。
int interval = 100;
Timer timer = new Timer(interval, new MyActionLinstener());
public void init() {
// 默认游戏未开始
this.isStart = false;
this.isFail = false;
// 初始化速度
interval = 200;
timer.setDelay(interval);
// 初始化小蛇数据
this.length = 3;
this.score = 0;
this.snakeX[0] = 100;
this.snakeY[0] = 100;
this.snakeX[1] = 75;
this.snakeY[1] = 100;
this.snakeX[2] = 50;
this.snakeY[2] = 100;
this.direction = 'R';
// 随机产生事物的坐标
this.foodx = 25 + 25 * random.nextInt(34);
this.foody = 75 + 25 * random.nextInt(24);
this.count = 1; // 统计食物数量
// 获得焦点和键盘监听事件
this.setFocusable(true);
// 添加键盘监听事件
this.addKeyListener(new MyKeyListener());
// 开启定时器
timer.start();
}
public GamePanel() {
init();
}
// 自动绘制面板
// paintComponent()是swing的一个方法,相当于图形版的main(),是会自执行的。
@Override
protected void paintComponent(Graphics g) {
//清屏
super.paintComponent(g);
this.setBackground(Color.WHITE);
//绘制静态面板
// 顶部广告
Data.header.paintIcon(this, g, 25, 11);
// 游戏区域
g.fillRect(25, 75, 850, 600);
// 画积分
g.setColor(Color.white);
g.setFont(new Font("微软雅黑", Font.BOLD, 18));
g.drawString("长度:" + length, 750, 30);
g.drawString("分数:" + score, 750, 56);
// 绘制食物
if (count % 5 != 0) {
Data.food.paintIcon(this, g, foodx, foody);
worth = 1;
} else {
Data.food2.paintIcon(this, g, foodx, foody);
worth = 3;
}
// 游戏状态 默认为暂停 需要提示信息
if (!isStart) {
g.setColor(Color.white);
g.setFont(new Font("微软雅黑", Font.BOLD, 40));
g.drawString("按下空格开始游戏", 300, 300);
}
// 画小蛇 初始化向右 长度为3
// 选择头部的方向
ImageIcon head = Data.right;
switch (this.direction) {
case 'U':
head = Data.up;
break;
case 'D':
head = Data.down;
break;
case 'L':
head = Data.left;
break;
case 'R':
head = Data.right;
break;
default:
break;
}
head.paintIcon(this, g, snakeX[0], snakeY[0]);
for (int i = 1; i < this.length; i++) {
Data.body.paintIcon(this, g, snakeX[i], snakeY[i]);
}
// 结束状态
if (isFail) {
g.setColor(Color.red);
g.setFont(new Font("微软雅黑", Font.BOLD, 100));
g.drawString("Game Over", 150, 200);
g.drawString("按空格重新开始", 100, 400);
}
}
/**
* 内部类监听键盘事件
*/
class MyKeyListener extends KeyAdapter {
// 只需要监听键盘按下
@Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
// System.out.println(keyCode);
if (keyCode == KeyEvent.VK_SPACE) {
if (isFail) {
// 重新开始
init();
isStart = true;
} else {
isStart = !isStart;
}
repaint();
}
// 内层增加一个判断,180度转向 不生效
switch (keyCode) {
case KeyEvent.VK_UP:
if (direction != 'D') {
direction = 'U';
}
break;
case KeyEvent.VK_DOWN:
if (direction != 'U') {
direction = 'D';
}
break;
case KeyEvent.VK_LEFT:
if (direction != 'R') {
direction = 'L';
}
break;
case KeyEvent.VK_RIGHT:
if (direction != 'L') {
direction = 'R';
}
break;
default:
break;
}
// 调整速度 小键盘的 + -
if (keyCode == 107) {
interval = interval > 10 ? interval - 10 : 10;
timer.setDelay(interval);
System.out.println("加速" + interval);
} else if (keyCode == 109) {
interval += 20;
timer.setDelay(interval);
System.out.println("减速" + interval);
}
}
}
class MyActionLinstener implements ActionListener {
// 事件监听类
@Override
public void actionPerformed(ActionEvent e) {
// 通过事件刷新界面
// 如果游戏开始且未失败,则刷新界面
if (isStart && !isFail) {
// 吃食物 蛇头与食物重合
if (snakeX[0] == foodx && snakeY[0] == foody) {
length++; // 吃了边长
foodx = 25 + 25 * random.nextInt(34);
foody = 75 + 25 * random.nextInt(24);
count++; // 统计食物数量
score += worth;
// 这里可以设置积分到一定值,增加移动速度
if (score < 5) {
interval = 200;
timer.setDelay(interval);
System.out.println("一级速度");
} else if (score < 15) {
interval = 150;
timer.setDelay(interval);
System.out.println("二级速度");
} else if (score < 25) {
interval = 100;
timer.setDelay(interval);
System.out.println("三级速度");
} else if (score < 50) {
interval = 50;
timer.setDelay(interval);
System.out.println("四级速度");
}
}
for (int i = length - 1; i > 0; i--) {
// 从最后一节开始继承前一节的位置
snakeX[i] = snakeX[i - 1];
snakeY[i] = snakeY[i - 1];
}
// 头部找新的路,利用三元运算符判断边界重置
switch (direction) {
case 'U':
snakeY[0] = snakeY[0] <= 75 ? 650 : snakeY[0] - 25;
break;
case 'D':
snakeY[0] = snakeY[0] >= 650 ? 75 : snakeY[0] + 25;
break;
case 'L':
snakeX[0] = snakeX[0] <= 25 ? 850 : snakeX[0] - 25;
break;
case 'R':
snakeX[0] = snakeX[0] % 850 + 25;
break;
default:
break;
}
// 失败判定
for (int i = 1; i < length; i++) {
if (snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]) {
isFail = true;
}
}
repaint();
}
}
}
}
游戏效果

该版本已知bug
小蛇不能反向运动,玩家操作过快导致的意外死亡。
比如小蛇向↑运动过程中,玩家按 ↓ 是无效的,但如果按 ← 的瞬间按 ↓
由于定时器的刷新速度没有跟上玩家的操作,游戏帧尚未刷新就已经有了下一次操作。
误判为小蛇回头撞了自己,游戏结束。
第二个问题是
空格本应该具有暂停/继续/重玩的功能。
游戏局数为偶数时,空格键暂停功能失效。
打包游戏
首先通过IDEA生成Jar包,再通过exe4j将jar打包为exe

具体操作跳转至Java桌面应用程序打包。
Java贪吃蛇小游戏的更多相关文章
- java贪吃蛇小游戏详解
https://blog.csdn.net/u011622021/article/details/81162083
- Java GUI学习,贪吃蛇小游戏
JAVA GUI练习 贪吃蛇小游戏 前几天虽然生病了,但还是跟着狂神学习了GUI的方面,跟着练习了贪吃蛇的小项目,这里有狂神写的源码点我下载,还有我跟着敲的点我下载,嘿嘿,也就注释了下重要的地方,这方 ...
- 用GUI实现java版贪吃蛇小游戏
项目结构 新建一个JFrame窗口,作为程序入口 public class GameStart{ public static void main(String[] args) { JFrame jFr ...
- C++ 简单的控制台贪吃蛇小游戏
由于比较懒,所以不怎么写,觉得这样不应该.我应该对自己学的做出整理,不管是高端低端,写出来是自己的. // 贪吃蛇.cpp : 定义控制台应用程序的入口点. // #include "std ...
- 贪吃蛇小游戏-----C语言实现
1.分析 众所周知,贪吃蛇游戏是一款经典的益智游戏,有PC和手机等多平台版本,既简单又耐玩.该游戏通过控制蛇头方向吃食物,从而使得蛇变得越来越长,蛇不能撞墙,也不能装到自己,否则游戏结束.玩过贪吃蛇的 ...
- JS高级---案例:贪吃蛇小游戏
案例:贪吃蛇小游戏 可以玩的小游戏,略复杂,过了2遍,先pass吧 先创建构造函数,再给原型添加方法.分别创建食物,小蛇和游戏对象. 食物,小蛇的横纵坐标,设置最大最小值,运动起来的函数,按上下左右键 ...
- Java 用java GUI写一个贪吃蛇小游戏
目录 主要用到 swing 包下的一些类 上代码 游戏启动类 游戏数据类 游戏面板类 代码地址 主要用到 swing 包下的一些类 JFrame 窗口类 JPanel 面板类 KeyListener ...
- html5面向对象做一个贪吃蛇小游戏
canvas加面向对象方式的贪吃蛇 2016-08-25 这个小游戏可以增加对面向对象的理解,可以加强js逻辑能力,总之认真自己敲一两遍收获还是不少啊!!适合刚学canvas的同学练习!! 废话不多说 ...
- 用python+pygame写贪吃蛇小游戏
因为python语法简单好上手,前两天在想能不能用python写个小游戏出来,就上网搜了一下发现了pygame这个写2D游戏的库.了解了两天再参考了一些资料就开始写贪吃蛇这个小游戏. 毕竟最开始的练手 ...
随机推荐
- java实现第五届蓝桥杯出栈次序
出栈次序 X星球特别讲究秩序,所有道路都是单行线.一个甲壳虫车队,共16辆车,按照编号先后发车,夹在其它车流中,缓缓前行. 路边有个死胡同,只能容一辆车通过,是临时的检查站,如图[p1.png]所示. ...
- java实现第四届蓝桥杯组素数
组素数 题目描述 素数就是不能再进行等分的数.比如:2 3 5 7 11 等. 9 = 3 * 3 说明它可以3等分,因而不是素数. 我们国家在1949年建国.如果只给你 1 9 4 9 这4个数字卡 ...
- java创建透明背景的PNG图片加自定义文字水印
人在码上走,需求天天有.这不,今天前端让我返回一个带自定义水印的背景图片.一通google,有现成的代码,但是基本是直接在源图上添加水印,生成出来的文字样式也没有控制好,看来又只有自己造轮子了. 过程 ...
- hadoop知识整理(2)之MapReduce
之前写的关于MR的文章的前半部分已丢. 所以下面重点从3个部分来谈MR: 1)Job任务执行过程,以及主要进程-ResourceManager和NodeManager作用: 2)shuffle过程: ...
- Git Commit 提交规范
写好 Commit message 好处多多: 1.统一团队Git commit 日志风格 2.方便日后 Reviewing Code 3.帮助我们写好 Changelog 4.能很好的提升项目整体质 ...
- @loj - 2106@ 「JLOI2015」有意义的字符串
目录 @description@ @solution@ @accepted code@ @details@ @description@ B 君有两个好朋友,他们叫宁宁和冉冉.有一天,冉冉遇到了一个有趣 ...
- 3.kubernetes的CNI网络插件-Flannel
目录 1.1.K8S的CNI网络插件-Flannel 1.1.1.集群规划 1.1.2.下载软件.解压.软链接 1.1.3.最终目录结构 1.1.4.拷贝证书 1.1.5.创建配置 1.1.6.创建启 ...
- PHP丨PHP基础知识之流程控制WHILE循环「理论篇」
昨天讲完FOR循环今天来讲讲他的兄弟WHILE循环!进入正题: while是计算机的一种基本循环模式.当满足条件时进入循环,进入循环后,当条件不满足时,跳出循环.while语句的一般表达式为:whil ...
- RedHat服务器安装
为什么选择 RedHat 市场占有率商业化比较高 厂商的支持比较丰富 新手建议ubuntu 进行上手 等熟悉了Linux环境可以选择自己喜欢的发行版 (有些Geeker就是认为Ubuntu太易于使用了 ...
- Beta冲刺--冲刺总结
这个作业属于哪个课程 软件工程 (福州大学至诚学院 - 计算机工程系) 这个作业要求在哪里 Beta 冲刺 这个作业的目标 Beta冲刺--冲刺总结 作业正文 如下 其他参考文献 ... Beta冲刺 ...