花了兩個下午寫了一個貪吃蛇小遊戲,本人想寫這遊戲很長時間了。做爲之前諾基亞手機上的經典遊戲,貪吃蛇和俄羅斯方塊同樣,都曾經在咱們的童年給咱們帶來了不少樂趣。世間萬物斗轉星移,諾基亞曾經做爲手機業的龍頭老大,現現在也一步步走向衰落,被收購,再過不久估計就要退出手機業務了,而貪吃蛇這款遊戲也基本上沒人玩了,甚至在新一代人的印象中都已毫無記憶了。。。可是,這款遊戲在它基礎上通過改造其實能夠弄出不少花樣,也確實能夠在必定程度上鍛鍊本身的編程能力。前不久十分火熱的貪吃蛇大做戰其實就能夠看作是在這款遊戲的基礎上進行的改造。因此,我也但願本身能夠嘗試如下,作個有意思的版本。html
目前這個版本只是爲了後期版本的一個測試版本,因此只有一些基本功能,原本是打算這個版本實現了移動,吃食物增加,判斷撞牆和撞本身的身體就好了,無奈以爲有點單調,因而在此基礎上加上了一個計時器,記分功能,從新開始,開始暫停以及音效。白白又多了幾百行代碼。原來的基本代碼也就300行。java
遊戲界面圖以下:git
注意運行時請附帶如下文件:github
http://files.cnblogs.com/files/journal-of-xjx/SnakeDemo.rar編程
之後版本更新都將放到 Github: dom
https://github.com/JiaxinTse/Snakeide
另外,第四版的遊戲截圖請看下一篇文章,比此處的Demo版豐富了不少:佈局
http://www.cnblogs.com/journal-of-xjx/p/7217799.html測試
(注:轉載和使用請務必事先向本人聲明)this
------------------------------------------------------------如下是代碼區-----------------------------------------------------------------
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 }
(注:轉載和使用請務必事先向本人聲明!)