Java实现贪吃蛇游戏【代码】

时间:2021-01-27 15:23:49

花了两个下午写了一个贪吃蛇小游戏,本人想写这游戏很长时间了。作为以前诺基亚手机上的经典游戏,贪吃蛇和俄罗斯方块一样,都曾经在我们的童年给我们带来了很多乐趣。世间万物斗转星移,诺基亚曾经作为手机业的龙头老大,现如今也一步步走向衰落,被收购,再过不久估计就要退出手机业务了,而贪吃蛇这款游戏也基本上没人玩了,甚至在新一代人的印象中都已毫无记忆了。。。但是,这款游戏在它基础上经过改造其实可以弄出很多花样,也确实可以在一定程度上锻炼自己的编程能力。前不久十分火热的贪吃蛇大作战其实就可以看做是在这款游戏的基础上进行的改造。所以,我也希望自己可以尝试以下,做个有意思的版本。

目前这个版本只是为了后期版本的一个测试版本,所以只有一些基本功能,本来是打算这个版本实现了移动,吃食物增长,判断撞墙和撞自己的身体就行了,无奈觉得有点单调,于是在此基础上加上了一个计时器,记分功能,重新开始,开始暂停以及音效。白白又多了几百行代码。原来的基本代码也就300行。

游戏界面图如下:

Java实现贪吃蛇游戏【代码】

Java实现贪吃蛇游戏【代码】

注意运行时请附带以下文件:

 http://files.cnblogs.com/files/journal-of-xjx/SnakeDemo.rar

------------------------------------------------------------以下是代码区--------------------------------------------------------------

(注:转载和使用请务必事先向本人声明)

  1 import java.awt.*;
2 import java.awt.event.*;
3 import java.io.File;
4 import java.io.IOException;
5 import java.util.Random;
6 import javax.sound.sampled.*;
7 import javax.swing.*;
8
9 class Tile{
10 int x;
11 int y;
12
13 public Tile(int x0,int y0){
14 x = x0;
15 y = y0;
16 }
17 }
18
19 public class SnakeDemo extends JComponent{
20 /**
21 *
22 */
23 private static final long serialVersionUID = 3794762291171148906L;
24 private final int MAX_SIZE = 400;//蛇身体最长为400节
25 private Tile temp = new Tile(0,0);
26 private Tile temp2 = new Tile(0,0);
27 private Tile head = new Tile(227,100);//头部的位置初始化为(227,100)
28 private Tile[] body = new Tile[MAX_SIZE];
29 private String direction = "R";//默认向右走
30 private String current_direction = "R";//当前方向
31 private boolean first_launch = false;
32 private boolean iseaten = false;
33 private boolean isrun = true;
34 private int randomx,randomy;
35 private int body_length = 5;//身体长度初始化为5
36 private Thread run;
37 private JLabel label = new JLabel("当前长度:");
38 private JLabel label2 = new JLabel("所花时间:");
39 private JLabel label3 = new JLabel("说 明:");
40 private JTextArea explain = new JTextArea("此游戏是一个贪吃蛇Demo版本,实现简单地移动,得分,判断撞墙和撞自己的功能,"
41 + "初始长度为6,头部为红色,身体的颜色渐变。游戏本身代码只有300行,加上一些显示,计时和音效后多了几百行。\n"
42 + "游戏界面按上下左右键实现移动,按ESC重新开始,按空格键可以实现暂停和开始");
43 private JLabel Score = new JLabel("6");
44 private JLabel Time = new JLabel("");
45 private Font f = new Font("微软雅黑",Font.PLAIN,15);
46 private Font f2 = new Font("微软雅黑",Font.PLAIN,13);
47 private JPanel p = new JPanel();
48 private int hour =0;
49 private int min =0;
50 private int sec =0 ;
51 private boolean pause = false;
52
53 public SnakeDemo(){
54 String lookAndFeel =UIManager.getSystemLookAndFeelClassName();
55 try {
56 UIManager.setLookAndFeel(lookAndFeel);
57 } catch (ClassNotFoundException e1) {
58 // TODO 自动生成的 catch 块
59 e1.printStackTrace();
60 } catch (InstantiationException e1) {
61 // TODO 自动生成的 catch 块
62 e1.printStackTrace();
63 } catch (IllegalAccessException e1) {
64 // TODO 自动生成的 catch 块
65 e1.printStackTrace();
66 } catch (UnsupportedLookAndFeelException e1) {
67 // TODO 自动生成的 catch 块
68 e1.printStackTrace();
69 }
70
71 //布局
72 add(label);
73 label.setBounds(500, 10, 80, 20);
74 label.setFont(f);
75 add(Score);
76 Score.setBounds(500, 35, 80, 20);
77 Score.setFont(f);
78 add(label2);
79 label2.setBounds(500, 60, 80, 20);
80 label2.setFont(f);
81 add(Time);
82 Time.setBounds(500, 85, 80, 20);
83 Time.setFont(f);
84 add(p);
85 p.setBounds(498, 110, 93, 1);
86 p.setBorder(BorderFactory.createLineBorder(Color.black));
87
88 add(label3);
89 label3.setBounds(500, 115, 80, 20);
90 label3.setFont(f);
91 add(explain);
92 explain.setBounds(498, 138, 100, 350);
93 explain.setFont(f2);
94 explain.setLineWrap(true);
95 explain.setOpaque(false);
96
97 for(int i = 0; i < MAX_SIZE;i++)
98 {
99 body[i] = new Tile(0,0);
100 }
101
102 addKeyListener(new KeyAdapter() {
103 public void keyPressed(KeyEvent e) {
104 super.keyPressed(e);
105 if(e.getKeyCode() == KeyEvent.VK_RIGHT)
106 {
107 if(isrun && current_direction != "L")
108 {
109 direction = "R";
110 }
111 }
112 if(e.getKeyCode() == KeyEvent.VK_LEFT)
113 {
114 if(isrun && current_direction != "R")
115 {
116 direction = "L";
117 }
118 }
119 if(e.getKeyCode() == KeyEvent.VK_UP)
120 {
121 if(isrun && current_direction != "D")
122 {
123 direction = "U";
124 }
125 }
126 if(e.getKeyCode() == KeyEvent.VK_DOWN)
127 {
128 if(isrun && current_direction != "U")
129 {
130 direction = "D";
131 }
132 }
133 if(e.getKeyCode() == KeyEvent.VK_ESCAPE)
134 {
135 direction = "R";//默认向右走
136 current_direction = "R";//当前方向
137 first_launch = false;
138 iseaten = false;
139 isrun = true;
140 body_length = 5;
141 head = new Tile(227,100);
142 Score.setText("6");
143 hour =0;
144 min =0;
145 sec =0 ;
146 for(int i = 0; i < MAX_SIZE;i++)
147 {
148 body[i].x = 0;
149 body[i].y = 0;
150 }
151
152 run = new Thread();
153 run.start();
154 System.out.println("Start again");
155 }
156 if(e.getKeyCode() == KeyEvent.VK_SPACE)//按空格键开始和暂停暂时没做,还在思考中
157 {
158 if(!pause)//暂停
159 {
160 pause = true;
161 isrun = false;
162 }
163 else//开始
164 {
165 pause = false;
166 isrun = true;
167 }
168 }
169 }
170 });
171
172 new Timer();
173
174 setFocusable(true);
175 }
176
177 public void paintComponent(Graphics g1){
178 super.paintComponent(g1);
179 Graphics2D g = (Graphics2D) g1;
180 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
181 g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,RenderingHints.VALUE_STROKE_NORMALIZE);
182
183 //画头部
184 g.setColor(Color.red);
185 g.fillRoundRect(head.x, head.y, 20, 20, 10, 10);
186
187 g.setPaint(new GradientPaint(115,135,Color.CYAN,230,135,Color.MAGENTA,true));
188 if(!first_launch)
189 {
190 //初始化身体
191 int x = head.x;
192 for(int i = 0;i < body_length;i++)
193 {
194 x -= 22;//相邻两个方块的间距为2个像素,方块宽度都为20像素
195 body[i].x = x;
196 body[i].y = head.y;
197 g.fillRoundRect(body[i].x, body[i].y, 20, 20, 10, 10);
198 }
199 //初始化食物位置
200 ProduceRandom();
201 g.fillOval(randomx, randomy, 19, 19);
202 }
203 else
204 {
205 //每次刷新身体
206 for(int i = 0;i < body_length;i++)
207 {
208 g.fillRoundRect(body[i].x, body[i].y, 20, 20, 10, 10);
209 }
210
211 if(EatFood())//被吃了重新产生食物
212 {
213 ProduceRandom();
214 g.fillOval(randomx, randomy, 19, 19);
215 iseaten = false;
216 }
217 else
218 {
219 g.fillOval(randomx, randomy, 19, 19);
220 }
221 }
222 first_launch = true;
223 //
224 g.setStroke( new BasicStroke(4,BasicStroke.CAP_BUTT,BasicStroke.JOIN_BEVEL));
225 g.setBackground(Color.black);
226 g.drawRect(2, 7, 491, 469);
227
228 //网格线
229 for(int i = 1;i < 22;i++)
230 {
231 g.setStroke( new BasicStroke(1,BasicStroke.CAP_BUTT,BasicStroke.JOIN_BEVEL));
232 g.setColor(Color.black);
233 g.drawLine(5+i*22,9,5+i*22,472);
234 if(i <= 20)
235 {
236 g.drawLine(4,10+i*22,491,10+i*22);
237 }
238 }
239 }
240
241 public void ProduceRandom(){
242 boolean flag = true;
243 Random rand = new Random();
244 randomx = (rand.nextInt(21) + 1) * 22 + 7;
245 randomy = (rand.nextInt(20) + 1) *22 + 12;
246 while(flag)
247 {
248 for(int i = 0;i < body_length; i++)
249 {
250 if(body[i].x == randomx && body[i].y == randomy)
251 {
252 randomx = (rand.nextInt(21) + 1) * 22 + 7;
253 randomy = (rand.nextInt(20) + 1) *22 + 12;
254 flag = true;
255 break;
256 }
257 else
258 {
259 if(i == body_length - 1)
260 {
261 flag = false;
262 }
263 }
264 }
265 }
266 }
267
268 public void HitWall(){//判断是否撞墙
269 if(current_direction == "L")
270 {
271 if(head.x < 7)
272 {
273 new AePlayWave("over.wav").start();
274 isrun = false;
275 int result=JOptionPane.showConfirmDialog(null, "Game over! Try again?", "Information", JOptionPane.YES_NO_OPTION);
276 if(result==JOptionPane.YES_NO_OPTION)
277 {
278 direction = "R";//默认向右走
279 current_direction = "R";//当前方向
280 first_launch = false;
281 iseaten = false;
282 isrun = true;
283 body_length = 5;
284 head = new Tile(227,100);
285 Score.setText("6");
286 hour =0;
287 min =0;
288 sec =0 ;
289 for(int i = 0; i < MAX_SIZE;i++)
290 {
291 body[i].x = 0;
292 body[i].y = 0;
293 }
294
295 run = new Thread();
296 run.start();
297 System.out.println("Start again");
298 }
299 else
300 {
301 run.stop();
302 }
303 }
304 }
305 if(current_direction == "R")
306 {
307 if(head.x > 489)
308 {
309 new AePlayWave("over.wav").start();
310 isrun = false;
311 int result=JOptionPane.showConfirmDialog(null, "Game over! Try again?", "Information", JOptionPane.YES_NO_OPTION);
312 if(result==JOptionPane.YES_NO_OPTION)
313 {
314 direction = "R";//默认向右走
315 current_direction = "R";//当前方向
316 first_launch = false;
317 iseaten = false;
318 isrun = true;
319 body_length = 5;
320 head = new Tile(227,100);
321 Score.setText("6");
322 hour =0;
323 min =0;
324 sec =0 ;
325 for(int i = 0; i < MAX_SIZE;i++)
326 {
327 body[i].x = 0;
328 body[i].y = 0;
329 }
330
331 run = new Thread();
332 run.start();
333 System.out.println("Start again");
334 }
335 else
336 {
337 run.stop();
338 }
339 }
340 }
341 if(current_direction == "U")
342 {
343 if(head.y < 12)
344 {
345 new AePlayWave("over.wav").start();
346 isrun = false;
347 int result=JOptionPane.showConfirmDialog(null, "Game over! Try again?", "Information", JOptionPane.YES_NO_OPTION);
348 if(result==JOptionPane.YES_NO_OPTION)
349 {
350 direction = "R";//默认向右走
351 current_direction = "R";//当前方向
352 first_launch = false;
353 iseaten = false;
354 isrun = true;
355 body_length = 5;
356 head = new Tile(227,100);
357 Score.setText("6");
358 hour =0;
359 min =0;
360 sec =0 ;
361 for(int i = 0; i < MAX_SIZE;i++)
362 {
363 body[i].x = 0;
364 body[i].y = 0;
365 }
366
367 run = new Thread();
368 run.start();
369 System.out.println("Start again");
370 }
371 else
372 {
373 run.stop();
374 }
375 }
376 }
377 if(current_direction == "D")
378 {
379 if(head.y > 472)
380 {
381 new AePlayWave("over.wav").start();
382 isrun = false;
383 int result=JOptionPane.showConfirmDialog(null, "Game over! Try again?", "Information", JOptionPane.YES_NO_OPTION);
384 if(result==JOptionPane.YES_NO_OPTION)
385 {
386 direction = "R";//默认向右走
387 current_direction = "R";//当前方向
388 first_launch = false;
389 iseaten = false;
390 isrun = true;
391 body_length = 5;
392 head = new Tile(227,100);
393 Score.setText("6");
394 hour =0;
395 min =0;
396 sec =0 ;
397 for(int i = 0; i < MAX_SIZE;i++)
398 {
399 body[i].x = 0;
400 body[i].y = 0;
401 }
402
403 run = new Thread();
404 run.start();
405 System.out.println("Start again");
406 }
407 else
408 {
409 run.stop();
410 }
411 }
412 }
413 }
414
415 public void HitSelf(){//判断是否撞到自己身上
416 for(int i = 0;i < body_length; i++)
417 {
418 if(body[i].x == head.x && body[i].y == head.y)
419 {
420 new AePlayWave("over.wav").start();
421 isrun = false;
422 int result=JOptionPane.showConfirmDialog(null, "Game over! Try again?", "Information", JOptionPane.YES_NO_OPTION);
423 if(result==JOptionPane.YES_NO_OPTION)
424 {
425 direction = "R";//默认向右走
426 current_direction = "R";//当前方向
427 first_launch = false;
428 iseaten = false;
429 isrun = true;
430 body_length = 5;
431 head = new Tile(227,100);
432 Score.setText("6");
433 hour =0;
434 min =0;
435 sec =0 ;
436 for(int j = 0; j < MAX_SIZE;j++)
437 {
438 body[j].x = 0;
439 body[j].y = 0;
440 }
441
442 run = new Thread();
443 run.start();
444 System.out.println("Start again");
445 }
446 else
447 {
448 run.stop();
449 }
450 break;
451 }
452 }
453 }
454
455 public boolean EatFood(){
456 if(head.x == randomx && head.y == randomy)
457 {
458 iseaten = true;
459 return true;
460 }
461 else
462 {
463 return false;
464 }
465 }
466
467 public void Thread(){
468 long millis = 300;//每隔300毫秒刷新一次
469 run = new Thread() {
470 public void run() {
471 while (true)
472 {
473 try {
474 Thread.sleep(millis);
475 } catch (InterruptedException ex) {
476 ex.printStackTrace();
477 }
478
479 if(!pause)
480 {
481 temp.x = head.x;
482 temp.y = head.y;
483 //头部移动
484 if(direction == "L")
485 {
486 head.x -= 22;
487 }
488 if(direction == "R")
489 {
490 head.x += 22;
491 }
492 if(direction == "U")
493 {
494 head.y -= 22;
495 }
496 if(direction == "D")
497 {
498 head.y += 22;
499 }
500 current_direction = direction;//刷新当前前进方向
501 //身体移动
502 for(int i = 0;i < body_length;i++)
503 {
504 temp2.x = body[i].x;
505 temp2.y = body[i].y;
506 body[i].x = temp.x;
507 body[i].y = temp.y;
508 temp.x = temp2.x;
509 temp.y = temp2.y;
510 }
511
512 if(EatFood())
513 {
514 body_length ++;
515 body[body_length-1].x = temp2.x;
516 body[body_length-1].y = temp2.y;
517 Score.setText("" + (body_length+1) );
518 new AePlayWave("eat.wav").start();
519 }
520
521 repaint();
522
523 HitWall();
524 HitSelf();
525 }
526 }
527 }
528 };
529
530 run.start();
531 }
532
533 public static void main(String[] args) {
534 SnakeDemo t = new SnakeDemo();
535 t.Thread();
536
537 JFrame game = new JFrame();
538 Image img=Toolkit.getDefaultToolkit().getImage("title.png");//窗口图标
539 game.setIconImage(img);
540 game.setTitle("Snake By XJX");
541 game.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
542 // game.setSize(502, 507);
543 game.setSize(602, 507);
544 game.setResizable(false);
545 game.setLocationRelativeTo(null);
546
547 game.add(t);
548 game.setVisible(true);
549 }
550
551 //计时器类
552 class Timer extends Thread{
553 public Timer(){
554 this.start();
555 }
556 @Override
557 public void run() {
558 // TODO Auto-generated method stub
559 while(true){
560 if(isrun){
561 sec +=1 ;
562 if(sec >= 60){
563 sec = 0;
564 min +=1 ;
565 }
566 if(min>=60){
567 min=0;
568 hour+=1;
569 }
570 showTime();
571 }
572
573 try {
574 Thread.sleep(1000);
575 } catch (InterruptedException e) {
576 // TODO Auto-generated catch block
577 e.printStackTrace();
578 }
579
580 }
581 }
582
583 private void showTime(){
584 String strTime ="" ;
585 if(hour < 10)
586 strTime = "0"+hour+":";
587 else
588 strTime = ""+hour+":";
589
590 if(min < 10)
591 strTime = strTime+"0"+min+":";
592 else
593 strTime =strTime+ ""+min+":";
594
595 if(sec < 10)
596 strTime = strTime+"0"+sec;
597 else
598 strTime = strTime+""+sec;
599
600 //在窗体上设置显示时间
601 Time.setText(strTime);
602 }
603 }
604 }
605
606 class AePlayWave extends Thread {
607 private String filename;
608 private final int EXTERNAL_BUFFER_SIZE = 524288; // 128Kb
609
610 public AePlayWave(String wavfile) {
611 filename = wavfile;
612 }
613
614 public void run() {
615 File soundFile = new File(filename);
616 AudioInputStream audioInputStream = null;
617 try {
618 audioInputStream = AudioSystem.getAudioInputStream(soundFile);
619 } catch (UnsupportedAudioFileException e1) {
620 e1.printStackTrace();
621 return;
622 } catch (IOException e1) {
623 e1.printStackTrace();
624 return;
625 }
626
627 AudioFormat format = audioInputStream.getFormat();
628 SourceDataLine auline = null;
629 DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
630
631 try {
632 auline = (SourceDataLine) AudioSystem.getLine(info);
633 auline.open(format);
634 } catch (LineUnavailableException e) {
635 e.printStackTrace();
636 return;
637 } catch (Exception e) {
638 e.printStackTrace();
639 return;
640 }
641
642 auline.start();
643 int nBytesRead = 0;
644 byte[] abData = new byte[EXTERNAL_BUFFER_SIZE];
645
646 try {
647 while (nBytesRead != -1) {
648 nBytesRead = audioInputStream.read(abData, 0, abData.length);
649 if (nBytesRead >= 0)
650 auline.write(abData, 0, nBytesRead);
651 }
652 } catch (IOException e) {
653 e.printStackTrace();
654 return;
655 } finally {
656 auline.drain();
657 auline.close();
658 }
659 }
660 }

 (注:转载和使用请务必事先向本人声明!)