一、实验要求

1)、实现贪吃蛇游戏基本功能,屏幕上随机出现一个“食物”,称为豆子,上下左右控制“蛇”的移动,吃到“豆子”以后“蛇”的身体加长一点。
2)、“蛇”碰到边界或蛇头与蛇身相撞,蛇死亡,游戏结束。
3)、为游戏设计友好的交互界面;例如欢迎界面,游戏界面,游戏结束界面。要有开始键、暂停键和停止退出的选项。
4)、对蛇吃到豆子进行分值计算,可以设置游戏速度,游戏音乐等拓展元素。

二、实验步骤

1、首先是搭建游戏基本界面框架

搭建窗口:创建一个JFrame的继承类Frame,完成窗口的基本设置(窗口尺寸,名称,窗口可视化等等)

this.setTitle("贪吃蛇");
this.setSize(500, 600);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
//窗体居中
this.setLocationRelativeTo(null);this.setVisible(true);

创建一个JPanel的继承类GamePanel,来装游戏的基本界面

首先考虑游戏过程中需要的按钮

基本的游戏按钮需要设置开始,暂停,退出,在这里为了简洁,我把开始和暂停设置在同一个按钮上,根据不同的情况触发不同的功能除此之外,还需要设置一个JLable用于显示当前分数。并对这些组件进行基本设置,如背景色,字体大小等。

设置好后,全部添加到Frame的NORTH位置。

String str = new String("0");
JLabel score = new JLabel(str);
JPanel panel = new JPanel();JButton start = new Button("暂停");JButton esc = new Button("退出");score.setFont(new Font("", Font.PLAIN, 25));score.setForeground(new Color(121, 135, 162));System.out.println(score);JPanel button = new JPanel();button.setLayout(new GridLayout(1, 3));button.add(start);button.add(esc);button.add(score);panel.setBorder(new EmptyBorder(20, 0, 7, 0));panel.setLayout(new BorderLayout());panel.setOpaque(false);panel.add(button);panel.setVisible(true);frame.add(panel, BorderLayout.NORTH);

2、贪吃蛇算法实现

1)、首先要实现的是蛇头和食物的随机生成

创建一个关于蛇的类Snake,并在其中设置两个列表,一个snake列表,存放除蛇头以外的所有蛇身的坐标,一个snakeHead列表 ,存放蛇头坐标。并且设置两个全局变量x,y记录蛇头坐标。

并分别给蛇头和蛇身设置图片,以及游戏界面背景图片

    //蛇身坐标;List<List<Integer>> snake = new ArrayList<>();//蛇头坐标;List<Integer> snakeHead = new ArrayList<>();public int x;public int y;
public ImageIcon head = new ImageIcon("C:\\Users\\miracle\\OneDrive\\图片\\贪吃蛇素材\\3.png");public ImageIcon head1 = new ImageIcon("C:\\Users\\miracle\\OneDrive\\图片\\贪吃蛇素材\\1.png");public ImageIcon head2 = new ImageIcon("C:\\Users\\miracle\\OneDrive\\图片\\贪吃蛇素材\\2.png");public ImageIcon body = new ImageIcon("C:\\Users\\miracle\\OneDrive\\图片\\贪吃蛇素材\\水母2.png");public ImageIcon backGround = new ImageIcon("C:\\Users\\miracle\\OneDrive\\图片\\贪吃蛇素材\\比奇宝.jpg");

同样的,创建一个豆子的类Food,设置全局变量x,y和列表food来存放豆子坐标。

public class Food {public int x;public int y;List<Integer> bean = new ArrayList<>();public ImageIcon food = new ImageIcon("C:\\Users\\miracle\\OneDrive\\图片\\贪吃蛇素材\\水母王.png");}

注意:在上面两个类中,设置列表来存放坐标是为了之后方便用存放列表的列表snake进行判断是否包含相关列表。而又用x,y来存放坐标是为了方便改动坐标。

在主游戏界面GamePanel中分别创建这两个类的对象,s和f。

Snake s = new Snake();
Food f = new Food();

给s中的蛇头坐标和f中的食物坐标分别附一个随机初始值。

do {s.x = random.nextInt(0, 460);} while (s.x % 25 != 0);do {s.y = random.nextInt(20, 460);} while (s.y % 25 != 0);do {do {f.x = random.nextInt(0, 460);} while (f.x % 25 != 0);do {f.y = random.nextInt(20, 460);} while (f.y % 25 != 0);} while (s.x == f.x && s.y == f.y);

注意:蛇头和食物坐标不能重合!并且要确保移动后能够重合坐标。

2)、贪吃蛇移动实现

首先给开始和暂停按钮设置键盘监听。在这里,我用键盘按键的code值来进行判断并设置相应动作。

 start.addKeyListener(new KeyListener() {@Overridepublic void keyTyped(KeyEvent e) {}@Overridepublic void keyPressed(KeyEvent e) {//int x = 0, y = 0;switch (e.getKeyCode()) {case 38://str = "up";y = -25;x = 0;img=s.head;break;case 40://str = "down";y = 25;x = 0;img=s.head;break;case 37://str = "left";x = -25;y = 0;img=s.head1;break;case 39://str = "right";x = 25;y = 0;img=s.head2;break;default:break;}}@Overridepublic void keyReleased(KeyEvent e) {}});

当按键为“上”时,则蛇头纵坐标需要移动-25,横坐标不变。其中x,y是全局变量,用于存储每次蛇的坐标的变化情况。

但 仅仅这样还不能让蛇动起来,需要面板不断进行刷新,才能实现蛇的移动。

新建一个Thread的子类ReThread,用于面板的刷新,重绘。

public class Rethread extends Thread {GamePanel gamePanel;int speed;public Rethread(GamePanel gamePanel, int speed) {this.gamePanel = gamePanel;this.speed = speed;}@Overridepublic void run() {while (true) {try {Thread.sleep(speed);} catch (Exception e) {e.printStackTrace();}gamePanel.repaint();}}
}

并在Game Panel主游戏界面中生成对象调用

Rethread rt = new Rethread(this, speed);rt.start();

然后重写paintComponent方法,用于重绘面板

@Overrideprotected void paintComponent(Graphics g) {super.paintComponent(g);g.drawImage(backGround.getImage(), 0, 0, this.getWidth(), this.getHeight(), this);

将蛇和食物设置的图片画在界面中

ImageIcon bean = f.food;ImageIcon backGround = s.backGround;ImageIcon b = s.body;ImageIcon img = s.head;
 //画出蛇和食物;
g.drawImage(img.getImage(), s.x, s.y, 25, 25, this);
g.drawImage(bean.getImage(), f.x, f.y, 25, 25, this);

根据之前通过键盘按键得到的蛇的坐标变化情况来改变蛇头的坐标。

            s.x = s.x + x;s.y = s.y + y;s.snakeHead.set(0, s.x);s.snakeHead.set(1, s.y);

蛇头坐标改变后,需要判断是否越界,也就是离开游戏界面,若出界,则蛇身清空,游戏结束,打开新的提示界面

if (s.x > 460 || s.x < 0 || s.y > 460 || s.y < 0) {if (best < sc) {best = sc;}s.snake.removeAll(s.snake);stop = 1;OverFrame of = new OverFrame();of.init(frame, best, speed);}

此时需要判断,是否只有蛇头,也就是snake列表是否为空。

当蛇身长度不为空时,判断蛇头是否与蛇身的某一坐标重合,若相撞,则打开新的提示界面,结束游戏

if (s.snake.size() >= 1 && s.snake.contains(s.snakeHead)) {s.snake.removeAll(s.snake);if (best < sc) {best = sc;}stop = 1;OverFrame of = new OverFrame();of.init(frame, best, speed);}

当snake列表为空时,再判断蛇头是否与食物的坐标重合,若重合,则蛇身长度加1,并将蛇头的上一坐标作为蛇尾的坐标,食物重新随机获取坐标(仍然不能与蛇身重合,且不能越界)

            if (s.x == f.x && s.y == f.y && s.snake.size() == 0) {List<Integer> list = new ArrayList<>();list.add(s.x - x);list.add(s.y - y);//s.snake.set(0, s.snakeHead);s.snake.add(list);sc = 10;do {do {f.x = random.nextInt(0, 460);} while (f.x % 25 != 0);do {f.y = random.nextInt(20, 460);} while (f.y % 25 != 0);f.bean.set(0, f.x);f.bean.set(1, f.y);} while (s.snake.contains(f.bean) || s.snakeHead.equals(f.bean));}

注意:这里要先判断snake是否不为空,再判断是否为空,否则,当snake为空且蛇头与食物 坐标重合时,snake会从空变成不为空,若再进行不为空的判断就会出错。

如若游戏还没结束,则蛇身坐标接着移动,这里我是新建一个类来专门进行蛇身移动的计算。主要思想是,每个身体段的坐标都变成上一段身体的坐标,第0段的身体坐标则是蛇头上一个坐标。

public class Move {public List<List<Integer>> move(List<List<Integer>> snake, int x, int y, List<Integer> food, List<Integer> head) {List<Integer> list = new ArrayList<>();Iterator<Integer> iterator = snake.get(snake.size() - 1).iterator();int m = iterator.next();int n = iterator.next();//蛇尾坐标;list.add(m);list.add(n);for (int i = snake.size() - 1; i > 0; i--) {snake.get(i).set(0, snake.get(i - 1).get(0));snake.get(i).set(1, snake.get(i - 1).get(1));}snake.get(0).set(0, x);snake.get(0).set(1, y);if (head.equals(food)) {snake.add(list);}return snake;}
}

注意:由于存储列表的列表的特殊性:会随着内部列表的变化而变化,因此,我使用了两个整型变量来存放原有蛇尾坐标。如果吃到豆子,则蛇尾增加原有蛇尾坐标。

在Game Panel判断snake不为空后,进行调用

            if (s.snake.size() >= 1) {s.snake = m.move(s.snake, s.x - x, s.y - y, f.bean, s.snakeHead);//吃掉豆子后,豆子重新获取;if (s.snakeHead.equals(f.bean)) {sc = sc + 10;do {do {f.x = random.nextInt(0, 460);} while (f.x % 25 != 0);do {f.y = random.nextInt(20, 460);} while (f.y % 25 != 0);f.bean.set(0, f.x);f.bean.set(1, f.y);} while (s.snake.contains(f.bean) || s.snakeHead.equals(f.bean));}}

实现了整条蛇的移动后,还要画出移动后的蛇的图案。在此之前,已经将蛇头和食物画在了面板上,接下来就是画出移动后的蛇身。在这里,我调用循环来依次画出每一段蛇身。

            for (int i = 0; i < s.snake.size(); i++) {List list = new ArrayList();list.add(s.snake.get(i).get(0));list.add(s.snake.get(i).get(1));Iterator<Integer> iterator = list.iterator();int c = iterator.next();int d = iterator.next();g.drawImage(b.getImage(), c, d, 25, 25, this);s.snake.get(i).set(0, s.snake.get(i).get(0));s.snake.get(i).set(1, s.snake.get(i).get(1));}

最后再在label上显示出分数,我这里设置的是吃掉一颗豆子,得10分。

 score.setText("分数:" + sc);

至此,贪吃蛇的主要游戏界面和主要算法基本实现

3、开始界面和游戏结束界面的搭建

1)、创建一个JPanel继承类StartPanel用于设置开始界面的组件内容。

在此需要包含的组件有游戏名称(JLabel)、开始按钮、速度按钮、历史最高纪录按钮。设置网格布局模式,并按4排1列的方式排列。并设置好这几个组件的外观。(为了增加趣味性,我把游戏名称设置为“抓水母”。)

给三个按钮设置按键监听。

点击开始按钮时,关闭当前窗口,打开之前设置的主要游戏窗口。

start.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {frame.dispose();Frame frame = new Frame();frame.init(best);frame.game(speed);}});

点击速度按钮时,改变速度,也就是面板刷新速度,并用相关字符串给出提示

set.addActionListener(new ActionListener() {int i = 0;@Overridepublic void actionPerformed(ActionEvent e) {if (i == 3) {set.setText("ffffast");i++;speed = 50;}if (i == 2) {set.setText("fast");i++;speed = 150;}if (i == 1) {set.setText("normal");i++;speed = 300;}if (i == 0) {set.setText("slow");i++;speed = 500;}if (i == 4) {i = 0;}}});

点击历史最高按钮时,显示最高分数

 history.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {history.setText(best + "");}});}

其中,为了存储和传递速度和最高分数这两个数字,我在每个相关的类中都设置了speed和score两个全局变量,并且调用这些类的对象时,也要进行参数传递,防止出现不匹配的问题。

2)、创建一个JFrame的继承类OverFrame作为结束提示

其中包含“Game over”的JLabel,“重新开始”按钮,“退出”按钮。

当点击重新开始按钮时,关闭当前前窗口,重新打开游戏主界面

 yes.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {frame.dispose();Frame frame = new Frame();frame.init(best);frame.game(speed);}});

点击退出按钮后,回到开始界面。

esc.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {OverFrame.this.dispose();frame.dispose();Frame frame = new Frame();frame.init(best);StartPanel startPanel = new StartPanel(best, frame);frame.add(startPanel);}});

至此贪吃蛇游戏基本实现。

实验二 贪吃蛇游戏开发相关推荐

  1. 实验项目二 贪吃蛇游戏开发

    一.实验要求 1.实现贪吃蛇游戏基本功能,屏幕上随机出现一个"食物",称为豆子, 2.上下左右控制"蛇"的移动,吃到"豆子"以后" ...

  2. 实验项目二:贪吃蛇游戏开发

    贪吃蛇游戏开发 一.前言 二.基本流程 三.游戏界面设计 1. 界面构造 2. 蛇的构造 3. 食物构造 四.游戏过程 1. 蛇的移动 2. 蛇吃食物与碰撞检测 五.游戏结束 1. 结束界面 六.扩展 ...

  3. 实验二、贪吃蛇游戏开发

    实验要求 实现贪吃蛇游戏基本功能,屏幕上随机出现一个"食物",称为豆子,上下左右控制"蛇"的移动,吃到"豆子"以后"蛇" ...

  4. 实验二 贪吃蛇的游戏开发

    实验目的: 实现贪吃蛇游戏基本功能,屏幕上随机出现一个"食物",称为豆子,上下左右控制"蛇"的移动,吃到"豆子"以后"蛇" ...

  5. 计算机软件实习项目二 —— 贪吃蛇游戏 (实验准备)

    目录 一.实验目的 二.编程语言和平台 三.实验难点: 四.参考资料 一.实验目的 1.实现贪吃蛇游戏基本功能,屏幕上随机出现一个"食物",称为豆子 2.上下左右控制"蛇 ...

  6. c语言设计贪吃蛇实验报告,贪吃蛇游戏程序设计实验报告

    <贪吃蛇游戏程序设计实验报告>由会员分享,可在线阅读,更多相关<贪吃蛇游戏程序设计实验报告(11页珍藏版)>请在人人文库网上搜索. 1.Windows编程大作业贪吃蛇设计与实现 ...

  7. 结对-贪吃蛇游戏-开发环境搭建过程

    结对编程成员:赵建辉,马壮 搭建环境: 会 html,css,以及java开发知识. 会应用sublime,dw等编辑软件 编写程序阶段: 1.利用html搭建前端页面,构建游戏的页面框架 2.利用j ...

  8. 基于C语言的贪吃蛇游戏开发与设计

    文章目录 前言 一.背景知识 二.实验分析和理解 三.头文件 四.设计流程 五.流程图 六.算法设计 (1)相关变量 (2)创建链表 (3)随机出现食物并记录食物出现的坐标 (4)绘制初始界面和游戏地 ...

  9. 实践 贪吃蛇游戏开发

    1.代码实现: GamePanel类 package snakegame; import java.awt.Color; import java.awt.Font; import java.awt.G ...

  10. 计算机软件实习项目二 —— 贪吃蛇游戏 (代码实现) 12-16

    代码实现   不得不说python真是太香了,我感觉写起来比C++快,而且代码量更少,还有非常多十分方便的方法可以使用.在pycharm里有非常多的快捷键十分的方便,相较项目使用的visual stu ...

最新文章

  1. 新创建的Django项目Django administration用户名和密码配置
  2. 5怎么关闭作弊模式_相机5种主要的拍摄模式该怎么用
  3. zTree树形菜单使用实例
  4. oracle追加index,oracle add index
  5. java app的强制更新吗_java – Spring JPA / Hibernate事务强制插入而不是更新
  6. 利用python将图片版PDF转文字版PDF
  7. linux制作flash软件,Linux 下的三款 Flash 独立播放器
  8. js经纬度坐标和度分秒互转
  9. for循环中控制事务单个提交问题
  10. 048、JAVA的Iterator迭代器
  11. 方舟生存进化服务器存档位置,方舟生存进化如何转移存档
  12. CH340G软件识别、usb转串口软件识别、测试
  13. 老男孩上海校区Python面试题
  14. 2D基本图形的Sign Distance Function (SDF)详解(上)
  15. (13)TEBD基态计算+DMRG算法
  16. C++中左移运算符<<、右移运算符>>、以及位与运算符
  17. [论文学习]Mask R-CNN
  18. java-字符串,抽象类与抽象
  19. 计算机虚拟筛选方法,药物发现的虚拟筛选基本方法 .ppt
  20. 串口软件Vofa+,超好用。可用于高速采集数据直观化显示动态

热门文章

  1. 全职专业玩家分享:手动党梦幻五开赚钱心得
  2. 长城汽车召回上万辆欧拉IQ:电池存在安全隐患,曾因自燃被拉黑
  3. Excel使用条件格式
  4. contrastive CAM
  5. XMAN选拔赛官方Writeup
  6. YUV420P像素数据编码为JPEG图片
  7. 吐血总结《Mysql从入门到入魔》,图文并茂
  8. 怎么取消linux ssh互信,[系统-linux] ssh互信操作
  9. 案例:Java用面向对象的思想设计游戏中的角色
  10. 钉钉回放被管理员禁止下载?别急我来帮你