现在先把代码折叠起来,会发现一个惊人的一个相似之处。无论加什么人功能,都是做四件事情。
添加食物:设置一个食物坐标,把它画到面板上,监听食物
画蛇:蛇的初始坐标,把蛇画上去,监听蛇
第和键盘相关的放在键盘监听里面,和游戏相关的放在事件监听里面。
一、按照步骤加一个游戏失败的判断:
- 首先得有一个游戏失败的判定

- 画数据到面板上

- 键盘监听事件,就是获得键盘的时候,空格有双重作用,isStart 肯定就不行了,先判断如果是 isFail 就重新开始,否则的话,就让他去开始或者停止。isFail 时,需要取 false ,又重新开始,需要重新初始化 init();

- 键盘监听搞定,它还有事件,我们需要去搞定事件监听



1 package com.gui.snake;
2
3 import javax.swing.*;
4 import java.awt.*;
5 import java.awt.event.ActionEvent;
6 import java.awt.event.ActionListener;
7 import java.awt.event.KeyEvent;
8 import java.awt.event.KeyListener;
9 import java.util.Random;
10
11 //游戏的面板
12 public class GamePanel extends JPanel implements KeyListener, ActionListener {
13
14 //定义蛇的数据结构
15 int length; //蛇的长度
16 int[] snakeX = new int[600]; //蛇的x坐标 25*25
17 int[] snakeY = new int[500]; //蛇的Y坐标 25*25
18 String fx;
19
20 //食物的坐标
21 int foodx;
22 int foody;
23 Random random = new Random();
24
25 //游戏当前的状态:开始、停止
26 boolean isStart = false; //默认是不开始
27
28 boolean isFail = false;//游戏失败状态
29
30 //定时器 以毫秒为单位 1000ms = 1s
31 Timer timer = new Timer(100, this);//100ms执行一次
32
33 //构造器
34 public GamePanel() {
35 init();
36 //获得焦点和键盘事件
37 this.setFocusable(true);//获得焦点事件
38 this.addKeyListener(this);//获得键盘监听事件:写的当前这个类,所以是this如果是其他类的话,去new一个监听器
39 timer.start();//游戏一开始,就让定时器启动
40 }
41
42 //初始化方法
43 public void init() {
44 length = 3;
45 snakeX[0] = 100;snakeY[0] = 100;//脑袋的坐标
46 snakeX[1] = 75 ;snakeY[1] = 100;//第一个身体的坐标
47 snakeX[2] = 50 ;snakeY[2] = 100;//第二个身体的坐标
48 fx = "R";//初始方向向右
49
50 //把食物随机分配在界面上
51 foodx = 25 + 25 * random.nextInt(34);
52 foody = 75 + 25 * random.nextInt(24);
53 }
54
55 //绘制面板,我们游戏中的所有东西,都是用这个画笔来画。 Ctrl+O,画组件
56 @Override
57 protected void paintComponent(Graphics g) {
58 super.paintComponent(g);//清屏的作用,不用会闪烁
59 //绘制静态的面板
60 this.setBackground(Color.WHITE);
61 Data.header.paintIcon(this, g, 25, 11);//头部广告栏画上去
62 g.fillRect(25, 75, 850, 600);//默认游戏界面
63
64 //把小蛇画上去
65 if (fx.equals("R")) {
66 Data.right.paintIcon(this, g, snakeX[0], snakeY[0]);//蛇头初始化向右,需要通过方向来判断
67 } else if (fx.equals("L")) {
68 Data.left.paintIcon(this, g, snakeX[0], snakeY[0]);
69 } else if (fx.equals("U")) {
70 Data.up.paintIcon(this, g, snakeX[0], snakeY[0]);
71 } else if (fx.equals("D")) {
72 Data.down.paintIcon(this, g, snakeX[0], snakeY[0]);
73 }
74
75 for (int i = 1; i < length; i++) {
76 Data.body.paintIcon(this, g, snakeX[i], snakeY[i]);//蛇的身体
77 }
78
79 //画食物
80 Data.food.paintIcon(this,g,foodx,foody);
81
82
83 //游戏状态
84 if (isStart == false) {
85 g.setColor(Color.white);
86 g.setFont(new Font("楷体", Font.BOLD, 40));
87 g.drawString("按下空格开始游戏", 300, 300);
88 }
89
90 if(isFail == true){
91 g.setColor(Color.red);
92 g.setFont(new Font("楷体", Font.BOLD, 40));
93 g.drawString("失败,按下空格重新开始", 300, 300);
94 }
95 }
96
97
98 //键盘监听事件
99 @Override
100 public void keyPressed(KeyEvent e) {
101 int keyCode = e.getKeyCode();//获得键盘按键是哪一个
102 if (keyCode == KeyEvent.VK_SPACE) {//如果按下的是空格键
103 if (isFail){
104 //重新开始
105 isFail = false;
106 init();
107 }else {
108 isStart = !isStart;//取反
109 }
110 repaint();//重新绘制,因为值已经变化了
111 }
112 //小蛇移动
113 if (keyCode == KeyEvent.VK_UP) {
114 fx = "U";
115 } else if (keyCode == KeyEvent.VK_DOWN) {
116 fx = "D";
117 } else if (keyCode == KeyEvent.VK_LEFT) {
118 fx = "L";
119 } else if (keyCode == KeyEvent.VK_RIGHT) {
120 fx = "R";
121 }
122 }
123
124 //事件监听---需要通过固定的时间来刷新,1s=10次
125 @Override
126 public void actionPerformed(ActionEvent e) {
127 if (isStart && isFail == false) {//如果游戏不处于失败状态,并且是开始状态,就让小蛇动起来!
128
129 //吃食物
130 if(snakeX[0] == foodx && snakeY[0] == foody){
131 length++;//长度 + 1
132 //再次随机食物
133 foodx = 25 + 25 * random.nextInt(34);
134 foody = 75 + 25 * random.nextInt(24);
135 }
136
137 //移动
138 for (int i = length - 1; i > 0; i--) {//后一节移到前一节的位置 snake[1] = snake [0];
139 snakeX[i] = snakeX[i - 1];
140 snakeY[i] = snakeY[i - 1];
141 }
142
143 //走向
144 if (fx.equals("R")) {
145 snakeX[0] = snakeX[0] + 25;
146 if (snakeX[0] > 850) { snakeX[0] = 25; }//边界判断
147 } else if (fx.equals("L")) {
148 snakeX[0] = snakeX[0] - 25;
149 if (snakeX[0] < 25) { snakeX[0] = 850; }//边界判断
150 } else if (fx.equals("U")) {
151 snakeY[0] = snakeY[0] - 25;
152 if (snakeY[0] < 75) { snakeY[0] = 650; }//边界判断
153 } else if (fx.equals("D")) {
154 snakeY[0] = snakeY[0] + 25;
155 if (snakeY[0] > 650) { snakeY[0] = 75; }//边界判断
156 }
157
158 //失败判定,撞到自己就算失败
159 for (int i = 1; i <length ; i++) {
160 if(snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]){
161 isFail = true;
162 }
163 }
164
165 repaint();//重画页面
166 }
167 timer.start();
168 }
169
170 @Override
171 public void keyReleased(KeyEvent e) {
172 }
173
174 @Override
175 public void keyTyped(KeyEvent e) {
176 }
177 }
测试游戏失败:

解决问题:

食物在身体上边的原因:代码顺序,把画食物的代码,放在在画小蛇前面,小蛇把食物吃掉就没了。
二、积分展示:
- 定义数据,放到初始化方法里面

- 画到面板上

- 吃食物的时候,每吃一个食物,分数加10

测试分数系统:
