花了两个下午写了一个贪吃蛇小游戏,本人想写这游戏很长时间了。作为以前诺基亚手机上的经典游戏,贪吃蛇和俄罗斯方块一样,都曾经在我们的童年给我们带来了很多乐趣。世间万物斗转星移,诺基亚曾经作为手机业的龙头老大,现如今也一步步走向衰落,被收购,再过不久估计就要退出手机业务了,而贪吃蛇这款游戏也基本上没人玩了,甚至在新一代人的印象中都已毫无记忆了。。。但是,这款游戏在它基础上经过改造其实可以弄出很多花样,也确实可以在一定程度上锻炼自己的编程能力。前不久十分火热的贪吃蛇大作战其实就可以看做是在这款游戏的基础上进行的改造。所以,我也希望自己可以尝试以下,做个有意思的版本。
目前这个版本只是为了后期版本的一个测试版本,所以只有一些基本功能,本来是打算这个版本实现了移动,吃食物增长,判断撞墙和撞自己的身体就行了,无奈觉得有点单调,于是在此基础上加上了一个计时器和记分功能以及音效。白白又多了几百行代码。原来的基本代码也就300行。
游戏界面图如下:
注意运行时请附带以下文件:
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行," 42 + "加上一些显示,计时和音效后多了几百行。\n按上下左右键实现移动,按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 suspended = 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 direction = "R"; 108 } 109 if(e.getKeyCode() == KeyEvent.VK_LEFT) 110 { 111 direction = "L"; 112 } 113 if(e.getKeyCode() == KeyEvent.VK_UP) 114 { 115 direction = "U"; 116 } 117 if(e.getKeyCode() == KeyEvent.VK_DOWN) 118 { 119 direction = "D"; 120 } 121 if(e.getKeyCode() == KeyEvent.VK_ESCAPE) 122 { 123 direction = "R";//默认向右走 124 current_direction = "R";//当前方向 125 first_launch = false; 126 iseaten = false; 127 isrun = true; 128 body_length = 5; 129 head = new Tile(227,100); 130 Score.setText("6"); 131 hour =0; 132 min =0; 133 sec =0 ; 134 for(int i = 0; i < MAX_SIZE;i++) 135 { 136 body[i].x = 0; 137 body[i].y = 0; 138 } 139 140 run = new Thread(); 141 run.start(); 142 System.out.println("Start again"); 143 } 144 // if(e.getKeyCode() == KeyEvent.VK_SPACE)//按空格键开始和暂停暂时没做,还在思考中 145 // { 146 // if(!suspended) 147 // { 148 // synchronized(run) 149 // { 150 // try { 151 // run.wait(); 152 // } catch (InterruptedException e1) { 153 // e1.printStackTrace(); 154 // } 155 // } 156 // } 157 // //notify(); 158 // } 159 } 160 }); 161 162 new Timer(); 163 164 setFocusable(true); 165 } 166 167 public void paintComponent(Graphics g1){ 168 super.paintComponent(g1); 169 Graphics2D g = (Graphics2D) g1; 170 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON); 171 g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,RenderingHints.VALUE_STROKE_NORMALIZE); 172 173 //画头部 174 g.setColor(Color.red); 175 g.fillRoundRect(head.x, head.y, 20, 20, 10, 10); 176 177 g.setPaint(new GradientPaint(115,135,Color.CYAN,230,135,Color.MAGENTA,true)); 178 if(!first_launch) 179 { 180 //初始化身体 181 int x = head.x; 182 for(int i = 0;i < body_length;i++) 183 { 184 x -= 22;//相邻两个方块的间距为2个像素,方块宽度都为20像素 185 body[i].x = x; 186 body[i].y = head.y; 187 g.fillRoundRect(body[i].x, body[i].y, 20, 20, 10, 10); 188 } 189 //初始化食物位置 190 ProduceRandom(); 191 g.fillOval(randomx, randomy, 19, 19); 192 } 193 else 194 { 195 //每次刷新身体 196 for(int i = 0;i < body_length;i++) 197 { 198 g.fillRoundRect(body[i].x, body[i].y, 20, 20, 10, 10); 199 } 200 201 if(EatFood())//被吃了重新产生食物 202 { 203 ProduceRandom(); 204 g.fillOval(randomx, randomy, 19, 19); 205 iseaten = false; 206 } 207 else 208 { 209 g.fillOval(randomx, randomy, 19, 19); 210 } 211 } 212 first_launch = true; 213 //墙 214 g.setStroke( new BasicStroke(4,BasicStroke.CAP_BUTT,BasicStroke.JOIN_BEVEL)); 215 g.setBackground(Color.black); 216 g.drawRect(2, 7, 491, 469); 217 218 //网格线 219 for(int i = 1;i < 22;i++) 220 { 221 g.setStroke( new BasicStroke(1,BasicStroke.CAP_BUTT,BasicStroke.JOIN_BEVEL)); 222 g.setColor(Color.black); 223 g.drawLine(5+i*22,9,5+i*22,472); 224 if(i <= 20) 225 { 226 g.drawLine(4,10+i*22,491,10+i*22); 227 } 228 } 229 } 230 231 public void ProduceRandom(){ 232 boolean flag = true; 233 Random rand = new Random(); 234 randomx = (rand.nextInt(21) + 1) * 22 + 7; 235 randomy = (rand.nextInt(20) + 1) *22 + 12; 236 while(flag) 237 { 238 for(int i = 0;i < body_length; i++) 239 { 240 if(body[i].x == randomx && body[i].y == randomy) 241 { 242 randomx = (rand.nextInt(21) + 1) * 22 + 7; 243 randomy = (rand.nextInt(20) + 1) *22 + 12; 244 flag = true; 245 break; 246 } 247 else 248 { 249 if(i == body_length - 1) 250 { 251 flag = false; 252 } 253 } 254 } 255 } 256 } 257 258 public void HitWall(){//判断是否撞墙 259 if(current_direction == "L") 260 { 261 if(head.x < 7) 262 { 263 new AePlayWave("over.wav").start(); 264 isrun = false; 265 int result=JOptionPane.showConfirmDialog(null, "Game over! Try again?", "Information", JOptionPane.YES_NO_OPTION); 266 if(result==JOptionPane.YES_NO_OPTION) 267 { 268 direction = "R";//默认向右走 269 current_direction = "R";//当前方向 270 first_launch = false; 271 iseaten = false; 272 isrun = true; 273 body_length = 5; 274 head = new Tile(227,100); 275 Score.setText("6"); 276 hour =0; 277 min =0; 278 sec =0 ; 279 for(int i = 0; i < MAX_SIZE;i++) 280 { 281 body[i].x = 0; 282 body[i].y = 0; 283 } 284 285 run = new Thread(); 286 run.start(); 287 System.out.println("Start again"); 288 } 289 else 290 { 291 run.stop(); 292 } 293 } 294 } 295 if(current_direction == "R") 296 { 297 if(head.x > 489) 298 { 299 new AePlayWave("over.wav").start(); 300 isrun = false; 301 int result=JOptionPane.showConfirmDialog(null, "Game over! Try again?", "Information", JOptionPane.YES_NO_OPTION); 302 if(result==JOptionPane.YES_NO_OPTION) 303 { 304 direction = "R";//默认向右走 305 current_direction = "R";//当前方向 306 first_launch = false; 307 iseaten = false; 308 isrun = true; 309 body_length = 5; 310 head = new Tile(227,100); 311 Score.setText("6"); 312 hour =0; 313 min =0; 314 sec =0 ; 315 for(int i = 0; i < MAX_SIZE;i++) 316 { 317 body[i].x = 0; 318 body[i].y = 0; 319 } 320 321 run = new Thread(); 322 run.start(); 323 System.out.println("Start again"); 324 } 325 else 326 { 327 run.stop(); 328 } 329 } 330 } 331 if(current_direction == "U") 332 { 333 if(head.y < 12) 334 { 335 new AePlayWave("over.wav").start(); 336 isrun = false; 337 int result=JOptionPane.showConfirmDialog(null, "Game over! Try again?", "Information", JOptionPane.YES_NO_OPTION); 338 if(result==JOptionPane.YES_NO_OPTION) 339 { 340 direction = "R";//默认向右走 341 current_direction = "R";//当前方向 342 first_launch = false; 343 iseaten = false; 344 isrun = true; 345 body_length = 5; 346 head = new Tile(227,100); 347 Score.setText("6"); 348 hour =0; 349 min =0; 350 sec =0 ; 351 for(int i = 0; i < MAX_SIZE;i++) 352 { 353 body[i].x = 0; 354 body[i].y = 0; 355 } 356 357 run = new Thread(); 358 run.start(); 359 System.out.println("Start again"); 360 } 361 else 362 { 363 run.stop(); 364 } 365 } 366 } 367 if(current_direction == "D") 368 { 369 if(head.y > 472) 370 { 371 new AePlayWave("over.wav").start(); 372 isrun = false; 373 int result=JOptionPane.showConfirmDialog(null, "Game over! Try again?", "Information", JOptionPane.YES_NO_OPTION); 374 if(result==JOptionPane.YES_NO_OPTION) 375 { 376 direction = "R";//默认向右走 377 current_direction = "R";//当前方向 378 first_launch = false; 379 iseaten = false; 380 isrun = true; 381 body_length = 5; 382 head = new Tile(227,100); 383 Score.setText("6"); 384 hour =0; 385 min =0; 386 sec =0 ; 387 for(int i = 0; i < MAX_SIZE;i++) 388 { 389 body[i].x = 0; 390 body[i].y = 0; 391 } 392 393 run = new Thread(); 394 run.start(); 395 System.out.println("Start again"); 396 } 397 else 398 { 399 run.stop(); 400 } 401 } 402 } 403 } 404 405 public void HitSelf(){//判断是否撞到自己身上 406 for(int i = 0;i < body_length; i++) 407 { 408 if(body[i].x == head.x && body[i].y == head.y) 409 { 410 new AePlayWave("over.wav").start(); 411 isrun = false; 412 int result=JOptionPane.showConfirmDialog(null, "Game over! Try again?", "Information", JOptionPane.YES_NO_OPTION); 413 if(result==JOptionPane.YES_NO_OPTION) 414 { 415 direction = "R";//默认向右走 416 current_direction = "R";//当前方向 417 first_launch = false; 418 iseaten = false; 419 isrun = true; 420 body_length = 5; 421 head = new Tile(227,100); 422 Score.setText("6"); 423 hour =0; 424 min =0; 425 sec =0 ; 426 for(int j = 0; j < MAX_SIZE;j++) 427 { 428 body[j].x = 0; 429 body[j].y = 0; 430 } 431 432 run = new Thread(); 433 run.start(); 434 System.out.println("Start again"); 435 } 436 else 437 { 438 run.stop(); 439 } 440 break; 441 } 442 } 443 } 444 445 public boolean EatFood(){ 446 if(head.x == randomx && head.y == randomy) 447 { 448 iseaten = true; 449 return true; 450 } 451 else 452 { 453 return false; 454 } 455 } 456 457 public void Thread(){ 458 long millis = 300;//每隔300毫秒刷新一次 459 run = new Thread() { 460 public void run() { 461 while (true) 462 { 463 try { 464 Thread.sleep(millis); 465 } catch (InterruptedException ex) { 466 ex.printStackTrace(); 467 } 468 469 temp.x = head.x; 470 temp.y = head.y; 471 //头部移动 472 if(direction == "L") 473 { 474 head.x -= 22; 475 } 476 if(direction == "R") 477 { 478 head.x += 22; 479 } 480 if(direction == "U") 481 { 482 head.y -= 22; 483 } 484 if(direction == "D") 485 { 486 head.y += 22; 487 } 488 current_direction = direction;//刷新当前前进方向 489 //身体移动 490 for(int i = 0;i < body_length;i++) 491 { 492 temp2.x = body[i].x; 493 temp2.y = body[i].y; 494 body[i].x = temp.x; 495 body[i].y = temp.y; 496 temp.x = temp2.x; 497 temp.y = temp2.y; 498 } 499 500 if(EatFood()) 501 { 502 body_length ++; 503 body[body_length-1].x = temp2.x; 504 body[body_length-1].y = temp2.y; 505 Score.setText("" + (body_length+1) ); 506 new AePlayWave("eat.wav").start(); 507 } 508 509 repaint(); 510 511 HitWall(); 512 HitSelf(); 513 } 514 } 515 }; 516 517 run.start(); 518 } 519 520 public static void main(String[] args) { 521 SnakeDemo t = new SnakeDemo(); 522 t.Thread(); 523 524 JFrame game = new JFrame(); 525 Image img=Toolkit.getDefaultToolkit().getImage("title.png");//窗口图标 526 game.setIconImage(img); 527 game.setTitle("Snake By XJX"); 528 game.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 529 // game.setSize(502, 507); 530 game.setSize(602, 507); 531 game.setResizable(false); 532 game.setLocationRelativeTo(null); 533 534 game.add(t); 535 game.setVisible(true); 536 } 537 538 //计时器类 539 class Timer extends Thread{ 540 public Timer(){ 541 this.start(); 542 } 543 @Override 544 public void run() { 545 // TODO Auto-generated method stub 546 while(true){ 547 if(isrun){ 548 sec +=1 ; 549 if(sec >= 60){ 550 sec = 0; 551 min +=1 ; 552 } 553 if(min>=60){ 554 min=0; 555 hour+=1; 556 } 557 showTime(); 558 } 559 560 try { 561 Thread.sleep(1000); 562 } catch (InterruptedException e) { 563 // TODO Auto-generated catch block 564 e.printStackTrace(); 565 } 566 567 } 568 } 569 570 private void showTime(){ 571 String strTime ="" ; 572 if(hour < 10) 573 strTime = "0"+hour+":"; 574 else 575 strTime = ""+hour+":"; 576 577 if(min < 10) 578 strTime = strTime+"0"+min+":"; 579 else 580 strTime =strTime+ ""+min+":"; 581 582 if(sec < 10) 583 strTime = strTime+"0"+sec; 584 else 585 strTime = strTime+""+sec; 586 587 //在窗体上设置显示时间 588 Time.setText(strTime); 589 } 590 } 591 } 592 593 class AePlayWave extends Thread { 594 private String filename; 595 private final int EXTERNAL_BUFFER_SIZE = 524288; // 128Kb 596 597 public AePlayWave(String wavfile) { 598 filename = wavfile; 599 } 600 601 public void run() { 602 File soundFile = new File(filename); 603 AudioInputStream audioInputStream = null; 604 try { 605 audioInputStream = AudioSystem.getAudioInputStream(soundFile); 606 } catch (UnsupportedAudioFileException e1) { 607 e1.printStackTrace(); 608 return; 609 } catch (IOException e1) { 610 e1.printStackTrace(); 611 return; 612 } 613 614 AudioFormat format = audioInputStream.getFormat(); 615 SourceDataLine auline = null; 616 DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); 617 618 try { 619 auline = (SourceDataLine) AudioSystem.getLine(info); 620 auline.open(format); 621 } catch (LineUnavailableException e) { 622 e.printStackTrace(); 623 return; 624 } catch (Exception e) { 625 e.printStackTrace(); 626 return; 627 } 628 629 auline.start(); 630 int nBytesRead = 0; 631 byte[] abData = new byte[EXTERNAL_BUFFER_SIZE]; 632 633 try { 634 while (nBytesRead != -1) { 635 nBytesRead = audioInputStream.read(abData, 0, abData.length); 636 if (nBytesRead >= 0) 637 auline.write(abData, 0, nBytesRead); 638 } 639 } catch (IOException e) { 640 e.printStackTrace(); 641 return; 642 } finally { 643 auline.drain(); 644 auline.close(); 645 } 646 } 647 }
时间: 2024-12-28 11:41:29