效果
我这是开启了三倍奖励,所以吃一个食物会长三节,贼快乐
可执行文件
可执行文件snake.exe
源码
--------------------------2019-11-29 星期五更新------------------
添加将最高分持久化的功能
以下代码都在GamePanel.class中
属性
File maxScoreFile;//存放最高分的文件
init()函数
public void init() throws Exception { ... String path = String.valueOf(GamePanel.class.getResource("/maxScoreFile.txt")); maxScoreFile = new File(path); if(!maxScoreFile.exists()){//如果不存在文件 maxScoreFile.createNewFile();//新创建一个,并且写入一个0 FileWriter fileWriter = new FileWriter(maxScoreFile);//写入字符流 fileWriter.write("0"); fileWriter.flush(); fileWriter.close(); } FileReader fileReader = new FileReader(maxScoreFile);//读取字符流 char c [] = new char[(int) maxScoreFile.length()]; fileReader.read(c); maxScore = Integer.parseInt(String.valueOf(c));//将文档的内容更新为当前最高分 fileReader.close(); }
计时器
@Override public void actionPerformed(ActionEvent e) { .... //结束判断,头和身体撞到了,则游戏失败 for (int i = 1; i < lenth; i++) { if (snakeX[i]==snakeX[0] && snakeY[i]==snakeY[0] ){ //如果超过当前最高分,更新 if (score > maxScore){ String scoreString = String.valueOf(score); try { FileWriter fileWriter = new FileWriter(maxScoreFile,false);//重新写入 fileWriter.write(scoreString); fileWriter.flush(); fileWriter.close(); } catch (IOException e1) { e1.printStackTrace(); } } isFail = true; } } ... }
--------------------------以下初始源码-------------------------------
这是一个普通的java项目,不需要任何依赖,属于gui的内容
图标类
里面的图片包含在上面的snake.zip压缩文件里面了
import javax.swing.*; import java.net.URL; public class Data { //游戏信息区域图片 public static URL headerUrl = Data.class.getResource("/statics/header.png"); public static ImageIcon header = new ImageIcon(headerUrl); //游戏区域背景图 public static URL game_backgroundUrl = Data.class.getResource("/statics/game_background.png"); public static ImageIcon game_background = new ImageIcon(game_backgroundUrl); //头部:上下左右 public static URL upUrl = Data.class.getResource("/statics/up.png"); public static URL downUrl = Data.class.getResource("/statics/down.png"); public static URL leftUrl = Data.class.getResource("/statics/left.png"); public static URL rightUrl = Data.class.getResource("/statics/right.png"); 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 URL bodyUrl = Data.class.getResource("/statics/body.png"); public static ImageIcon body = new ImageIcon(bodyUrl); //食物 public static URL foodUrl = Data.class.getResource("/statics/food.png"); public static ImageIcon food = new ImageIcon(foodUrl); }
主程序
import javax.swing.*; public class StarGames { public static void main(String[] args) { //1.创建一个窗口 JFrame frame = new JFrame("贪吃蛇小游戏 by 匆匆、"); frame.setBounds(250,150,850,690); // 设置窗口的位置和大小 frame.setResizable(false); //窗口大小不可调整,即固定窗口大小 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 设置关闭事件,游戏可以关闭 frame.add(new GamePanel()); frame.setVisible(true); //将窗口展示出来 } }
画板类
import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.Random; public class GamePanel extends JPanel implements KeyListener, ActionListener { int lenth; //蛇的长度 int[] snakeX = new int[600]; //蛇的坐标x int[] snakeY = new int[500]; //蛇的坐标y String fx; //蛇的方向 : R:右 L:左 U:上 D:下 boolean isStar = false;//判断游戏是否开始 Timer timer = new Timer(100,this); //定时器:第一个参数,就是定时执行时间 int foodx; //食物x轴坐标 int foody; Random random = new Random(); boolean isFail = false; //游戏是否结束 int score; //游戏分数! int degree;//游戏难度 int maxScore = 0;//最高分 public GamePanel() { init(); this.setFocusable(true);//获取焦点事件 this.addKeyListener(this);//键盘监听事件 timer.start();//时间开始! } //初始化方法 public void init() { lenth = 3;//初始小蛇有三节,包括小脑袋 //初始化开始的蛇,给蛇定位, snakeX[0] = 50; snakeY[0] = 50;//蛇的头部坐标 snakeX[1] = 25; snakeY[1] = 50;//第一个身体坐标 snakeX[2] = 0; snakeY[2] = 50;//第二个身体的坐标 fx = "R";//初始化方向 //初始化食物数据 foodx = 0 + 25 * random.nextInt(33); foody = 50 + 25 * random.nextInt(23); score = 0; //初始化游戏分数 degree = 1;//初始化游戏难度 } //画界面,画蛇 @Override protected void paintComponent(Graphics g) { super.paintComponent(g);//清屏 this.setBackground(Color.lightGray); //设置面板的背景色 Data.header.paintIcon(this, g, 0, 0);//绘制头部信息区域 Data.game_background.paintIcon(this,g,0,51);//绘制游戏区域 //根据不同的方向构造不同方向的小蛇头象 if (fx.equals("R")) { //蛇的头通过方向变量来判断 Data.right.paintIcon(this, g, snakeX[0], snakeY[0]); } else if (fx.equals("L")) { Data.left.paintIcon(this, g, snakeX[0], snakeY[0]); } else if (fx.equals("U")) { Data.up.paintIcon(this, g, snakeX[0], snakeY[0]); } else if (fx.equals("D")) { Data.down.paintIcon(this, g, snakeX[0], snakeY[0]); } //使用循环构造蛇的身体 for (int i = 1; i < lenth; i++) { Data.body.paintIcon(this, g, snakeX[i], snakeY[i]); //蛇的第i个身体 } //画食物 Data.food.paintIcon(this, g, foodx, foody); g.setColor(Color.red); g.setFont(new Font("微软雅黑",Font.BOLD,24)); //展示最高分 g.drawString("最高分 : " + maxScore,20,32); //将积分展示出来 g.drawString("当前分数 : " + score,200,32); //显示难度信息 if(degree <= 3 ) { g.drawString("当前难度 : " + degree + " 星, 菜鸡!",430,32); }else if (degree <= 5){ g.drawString("当前难度 : " + degree + " 星, 菜鸡,快点!",430,32); }else if (degree <= 7){ g.drawString("当前难度 : " + degree + " 星, 再快点!!!!",430,32); }else if (degree <= 9){ g.drawString("当前难度 : " + degree + " 星, 还能再快!!!!",430,32); }else if (degree <= 11){ g.drawString("当前难度 : " + degree + " 星, 啊哈哈,太快乐了!!",430,32); }else if (degree <=13){ g.drawString("只要我足够快,尾巴就追不上我...",430,32); }else if (degree <=16){ g.drawString("啊啊啊!!!!我控几不住我记几啊...",430,32); }else if (degree <=18){ g.drawString("吃惊,这是什么神仙手速...",430,32); }else { g.drawString("!!!!!!!! 你开外挂了吧...",430,32); } //提示游戏是否开始 if (isStar == false) { g.setColor(Color.blue); g.setFont(new Font("微软雅黑", Font.BOLD, 40)); g.drawString("按下空格开始游戏!", 290, 300); } //失败判断 if (isFail) { g.setColor(Color.red); g.setFont(new Font("微软雅黑", Font.BOLD, 60)); g.drawString("失败,! 按下空格重新开始", 120, 400); } } //实现KeyListener,重写的方法。键盘按下的操作,未弹起,我们只需要监听这一个 @Override public void keyPressed(KeyEvent e) { int keyCode = e.getKeyCode(); //获取按下的键盘 //增加空格的功能,重来or暂停 if (keyCode == KeyEvent.VK_SPACE) { //如果是空格 if (isFail) { //如果游戏失败,从头再来! isFail = false; init(); //重新初始化 } else { //否则,暂停游戏 isStar = !isStar;//取反,暂停按下空格则是启动,如果是正在游戏则暂停 } repaint();//重新绘制界面 } //键盘控制走向 if (keyCode == KeyEvent.VK_LEFT) { if(fx.equals("R")){//监听到按下左键,如果当前方向是向右 fx = "R";//则继续向右,控制不能回头 }else { fx = "L";//否则向左走 } } else if (keyCode == KeyEvent.VK_RIGHT) { if(fx.equals("L")){ fx = "L"; }else { fx = "R"; } } else if (keyCode == KeyEvent.VK_UP) { if(fx.equals("D")){ fx = "D"; }else { fx = "U"; } } else if (keyCode == KeyEvent.VK_DOWN) { if(fx.equals("U")){ fx = "U"; }else { fx = "D"; } } } //实现ActionListener,重写的方法,定时器, 监听时间。帧 @Override public void actionPerformed(ActionEvent e) { //如果游戏处于开始状态,并且没有结束,则小蛇可以移动 if (isStar && isFail == false) { //右移:即让后一个移到前一个的位置即可 ! for (int i = lenth - 1; i > 0; i--) { //除了脑袋都往前移:身体移动 snakeX[i] = snakeX[i - 1]; //即第i节(后一节)的位置变为(i-1:前一节)节的位置! snakeY[i] = snakeY[i - 1]; }//通过方向控制,头部移动 if (fx.equals("R")) { snakeX[0] = snakeX[0] + 25;//往右,+25 if (snakeX[0] > 825) snakeX[0] = 0;//边界判断,到右边了重新在左边绘制 } else if (fx.equals("L")) { snakeX[0] = snakeX[0] - 25;//往左,-25 if (snakeX[0] < 0) snakeX[0] = 825; } else if (fx.equals("U")) { snakeY[0] = snakeY[0] - 25;//往上,界面的起点是左上角,往右是x轴,往下是y轴,所以往上是-25 if (snakeY[0] < 50) snakeY[0] = 625;//界面判断,到了最上面,在y轴的最大值也就是最底下重新绘制 } else if (fx.equals("D")) { snakeY[0] = snakeY[0] + 25;//往下,+25 if (snakeY[0] > 625) snakeY[0] = 50; } //吃食物:当蛇的头和食物一样时,算吃到食物! if (snakeX[0] == foodx && snakeY[0] == foody) { lenth+=1;//1.长度加一 score+=10;//分数+10 //2.重新生成食物 foodx = 0 + 25 * random.nextInt(34); foody = 50 + 25 * random.nextInt(24); } //结束判断,头和身体撞到了 for (int i = 1; i < lenth; i++) { //如果头和身体碰撞,那就说明游戏失败 if (snakeX[i]==snakeX[0] && snakeY[i]==snakeY[0] ){ if(score > maxScore){ maxScore = score; } isFail = true; } } //自动改变游戏难度 if(score % 30 == 0){ degree = 1 + score / 30; timer.setDelay(100 - 5 * degree); } repaint(); //需要不断的更新页面实现动画 } timer.start();//让时间动起来! } @Override public void keyTyped(KeyEvent e) { //键盘按下弹起的操作 } @Override public void keyReleased(KeyEvent e) { //键盘松开的操作 } }
项目结构