贪吃蛇java 暂停_Java实现贪吃蛇小游戏
三月份的時候用Java寫了一個貪吃蛇的小游戲,寫完的時候頗有成就感,現在在這里做一下總結。
先把需要用到的圖片資源放在這里,分別為上、下、左、右方向的蛇頭,蛇身,食物,標題,可以通過右擊另存為的方式下載:
? ? ? ? ??
? ? ? ? ?
? ? ? ??
? ? ? ??
? ? ? ? ?
我們想要得到的游戲效果如下:
剛進入游戲的初始界面為圖1,按空格開始游戲,通過上、下、左、右鍵改變蛇的移動方向,蛇可以穿過邊界從另一端出來,吃到食物后多一個蛇身并且食物刷新位置,按空格鍵會暫停游戲,界面如圖2,再按空格重新開始游戲,如果蛇頭碰到自己的身子,那么游戲結束,按p鍵重新開始游戲,界面如圖3,右上角的積分系統可有可無,這里出于篇幅考慮,省去積分系統:
??
個人認為,要想用Java實現這個游戲,首先需要具備一些最基礎的GUI的知識,比如JFrame、JPanel的使用,這里就不再贅述;除此之外,還需要實現畫圖、鍵盤監聽、計時器的功能,這里通過幾個小demo展示一下這幾個功能是怎么實現的。
·畫圖的實現:主要用到JPanel類的paint(Graphics g)方法和ImageIcon類的paintIcon(Component c, Graphics g, int x, int y),代碼如下:
1 import javax.swing.*;2 import java.awt.*;3 class PaintDemo extendsJPanel{4 //得到需要畫的圖片的資源
5 ImageIcon body=new ImageIcon("C:\\Users\\apple\\Desktop\\pic\\body.png");6 //構造方法
7 publicPaintDemo(){8 this.setSize(200,200);9 this.setBackground(Color.white);10 }11 //在new PaintDemo()時會自動調用一次paint方法
12 public voidpaint(Graphics g){13 //ImageIcon類的一個方法,以此就能把對應的圖片畫在指定的位置上
14 body.paintIcon(this,g,100,100);15 }16 }17 public classSimpleTest {18 public static void main(String[] args) throwsException {19 JFrame f=new JFrame("Demo");20 //前兩個參數決定了彈出框的位置,后兩個參數決定了框的寬高
21 f.setBounds(100,150,200,200);22 //關閉窗口
23 f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);24 //只有把JPanel放在JFrame里才能看得到JPanel
25 f.add(newPaintDemo());26 f.setVisible(true);27 }28 }
實現效果如圖:
這樣一來,我們就可以通過畫圖,一步步得到游戲的界面了。
·鍵盤監聽的實現:游戲里我們是要通過鍵盤監聽來實現暫停、蛇的移動和重新開始的功能。在這個demo里,我們實現的是,鍵盤監聽一個JPanel,當我們按下↓鍵時,控制臺輸出“你往下了”,按下↑鍵時,控制臺輸出“你往上了”,代碼如下:
1 import javax.swing.*;2 import java.awt.*;3 import java.awt.event.*;4 class KeyDemo extends JPanel implementsKeyListener {5 publicKeyDemo(){6 this.setSize(200,200);7 this.setBackground(Color.white);8 //讓鍵盤事件監聽這個JPanel
9 this.addKeyListener(this);10 //使焦點保持在這個JPanel上,如果焦點不在這上面,鍵盤事件就不起作用了。
11 this.setFocusable(true);12 }13 public voidkeyPressed(KeyEvent e) {14 //得到我們按下的鍵的對應的數字常量
15 int keyCode=e.getKeyCode();16 //如果是↑鍵
17 if (keyCode==KeyEvent.VK_UP){18 System.out.println("你往上了");19 }else if (keyCode==KeyEvent.VK_DOWN){20 System.out.println("你往下了");21 }22 }23 public voidkeyTyped(KeyEvent e) {}24 public voidkeyReleased(KeyEvent e) {}25 }26 public classSimpleTest {27 public static void main(String[] args) throwsException {28 JFrame f=new JFrame("Demo");29 f.setBounds(100,150,200,200);30 f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);31 f.add(newKeyDemo());32 f.setVisible(true);33 }34 }
實現效果很簡單,就是在控制臺有對應的輸出。
這樣一來,我們就可以通過鍵盤來控制游戲的暫停、重新開始以及蛇的移動了。
·計時器的實現:單說計時器可能讓人很迷糊,計時器跟貪吃蛇有什么關系,難道這個游戲還有時間限制嗎?此計時器非彼計時器,這里的計時器實現了一個重要的功能,就是讓我們的蛇“動”了起來。其實我們平時看的喜羊羊等動畫,它們本身就是一張張的圖片,我們之所以覺得他們是“動”的,是因為這些圖片切換的實在太快了,我們的肉眼根本無法察覺到喜羊羊的一個動作其實就是幾十張圖片的快速切換而已。這也引入了一個叫做“幀”的概念,一幀可以理解為一個畫面。如果大家有玩過王者榮耀,應該會注意到游戲里有一個叫做“幀率”的東西,幀率就是每秒播放的幀數,當幀率很低,比如一秒只放兩張圖片時,就會出現大家口中的“卡成PPT”。而我們的貪吃蛇要想動起來,本質也就是通過高頻率地刷新畫面,產生“動”的感覺。
在這個demo里,我們實現的是在界面上不停的在隨機位置畫圖,主要用的是Timer類和ActionListener接口,具體代碼如下:
1 import javax.swing.*;2 import java.awt.*;3 import java.awt.event.*;4 importjava.util.Random;5 class TimerDemo extends JPanel implementsActionListener {6 ImageIcon food=new ImageIcon("C:\\Users\\apple\\Desktop\\pic\\food.png");7 Random r=newRandom();8 //初始位置
9 int x=r.nextInt(500);10 int y=r.nextInt(500);11 //創建一個Timer計時器,在調用timer.start()方法后,每100毫秒就會調用一次對應的actionPerformed()方法
12 Timer timer=new Timer(100,this);13 publicTimerDemo(){14 this.setSize(500,500);15 //在new這個JPanel的時候直接啟動計時器
16 timer.start();17 }18 public voidpaint(Graphics g){19 food.paintIcon(this,g,x,y);20 }21 public voidactionPerformed(ActionEvent e) {22 x=r.nextInt(500);23 y=r.nextInt(500);24 //重新調用一次paint()方法
25 repaint();26 }27 }28 public classSimpleTest {29 public static void main(String[] args) throwsException {30 JFrame f=new JFrame("Demo");31 f.setBounds(100,150,500,500);32 f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);33 f.add(newTimerDemo());34 f.setVisible(true);35 }36 }
實現效果如圖:
這樣一來,我們就可以想辦法讓蛇動起來了。至于蛇為什么吃到食物可以多一節身體,又為什么穿過邊界可以從另一端出來,就需要好好思考了。
有了以上的預備知識,我們就可以著手寫貪吃蛇的代碼了!
大致可以分為以下幾個步驟:
1.設計游戲圖紙
2.創建窗口JFrame
3.在窗口上添加畫布JPanel
4.在畫布上添加標題
5.在畫布上添加黑色游戲區
6.在游戲區放置靜態的蛇
7.加上開始提示
8.讓蛇動起來
9.實現游戲暫停
10.實現轉向功能
11.添加食物
12.吃掉食物
13.添加死亡條件
14.實現“重新開始”功能
一些要點
①我們需要把貪吃蛇移動的區域想成一個網格,蛇頭其實就是在一個個格子之間移動。
②蛇的方向可以通過設置一個direction變量來控制。
③蛇的部位的坐標可以用兩個數組來表示,X數組儲存部位的橫坐標,Y數組儲存部位的縱坐標,于是X[0]、Y[0]為蛇頭坐標,X[1]、Y[1]為第一節身體的坐標,以此類推。
④蛇的移動其實就是頭部不斷移動,然后每節身體取代前一節部位,所以具體實現時只需要考慮頭的移動,后面身體的移動就是取代前一部位的位置而已。
⑤蛇吃到食物就是蛇頭的坐標與食物的坐標重合,然后蛇的長度加一。
⑥蛇死亡就是蛇頭與任意一節身體的坐標重合。
⑦通過標志位來判斷游戲的各種狀態。
⑧蛇移動的速度是由計時器的第一個參數決定的。如果參數為1000,那么是每秒調用一次,蛇移動的很慢;如果參數為10,那么是每10毫秒調用一次,即每秒調用100次,這樣一來蛇移動的速度將非常快。
我的設計圖紙:
我的代碼實現,具體信息在注釋中:
1 package貪吃蛇;2 import java.awt.*;3 import java.awt.event.*;4 importjava.util.Random;5 import javax.swing.*;6 class GamePanel extends JPanel implementsKeyListener,ActionListener{7 //需要用到的圖片
8 ImageIcon title=new ImageIcon("C:\\Users\\apple\\Desktop\\pic\\title.jpg");9 ImageIcon right=new ImageIcon("C:\\Users\\apple\\Desktop\\pic\\right.png");10 ImageIcon left=new ImageIcon("C:\\Users\\apple\\Desktop\\pic\\left.png");11 ImageIcon up=new ImageIcon("C:\\Users\\apple\\Desktop\\pic\\up.png");12 ImageIcon down=new ImageIcon("C:\\Users\\apple\\Desktop\\pic\\down.png");13 ImageIcon body=new ImageIcon("C:\\Users\\apple\\Desktop\\pic\\body.png");14 ImageIcon food=new ImageIcon("C:\\Users\\apple\\Desktop\\pic\\food.png");15
16 //計時器,調用start()后,每100ms調用一次actionPerformed()方法,以此達到蛇移動的效果
17 Timer timer = new Timer(100,this);18
19 //蛇的一些初始信息20 //count用來讓paint()判斷是否要在初始位置畫蛇
21 intcount;22 //蛇的長度
23 intlength;24 //蛇的部位的坐標數組,數組的長度是蛇的最大長度,不能太小也不用太大,隨意就可以了。
25 int[] snakeX=new int[100];26 int[] snakeY=new int[100];27 //移動的方向
28 String direction;29 //用方法來初始化蛇的信息,當我們第一次進入游戲或者游戲失敗選擇重新開始時會調用這個方法
30 public voidsnakeSetup() {31 count=1;32 //初始長度為3
33 length=3;34 //蛇頭初始坐標
35 snakeX[0]=75;36 snakeY[0]=75;37 //第一節身體的初始坐標
38 snakeX[1]=50;39 snakeY[1]=75;40 //第二節身體的初始坐標
41 snakeX[2]=25;42 snakeY[2]=75;43 //蛇頭默認的方向
44 direction="right";45 }46
47 //游戲狀態
48 boolean isStart=false;49 boolean isFail=false;50
51 //食物狀態,剛進游戲的時候是沒有食物的,就相當于被吃掉了的狀態
52 boolean isEaten=true;53 //食物坐標
54 intfoodX;55 intfoodY;56 Random random=newRandom();57 //每次paint都會調用一次這個方法,如果食物是被吃掉的狀態,則給出新的食物的坐標
58 public voidfoodPoint() {59 if(isEaten) {60 isEaten=!(isEaten);61 foodX=25+25*random.nextInt(34);62 foodY=75+25*random.nextInt(24);63 }64 }65
66 //畫布
67 publicGamePanel() {68 this.setLayout(null);69 this.setBackground(Color.WHITE);70 //初始化蛇的信息
71 this.snakeSetup();72 //鍵盤監聽
73 this.addKeyListener(this);74 //設置焦點
75 this.setFocusable(true);76 //直接啟動timer,蛇之所以不直接移動是因為actionPerformed()中有標志位控制是否做事情。
77 timer.start();78 }79
80 //把需要的組件畫上去
81 public voidpaint(Graphics g) {82 //每次調用paint使count+1,因為游戲初始自動會調用一次,所以游戲初始的時候到這里count就是2了,以此來判斷是否蛇是否是初始化的。
83 count++;84 //畫標題
85 title.paintIcon(this, g, 25, 11);86 //畫游戲面板,一個實心長方形
87 g.fillRect(25, 75, 850, 600);88 //如果沒有食物,給出新的食物的坐標,有的話還是先前的坐標
89 this.foodPoint();90 //把食物畫上去
91 food.paintIcon(this, g, foodX, foodY);92 //判斷游戲狀態93 //如果是失敗狀態,顯示“失敗”
94 if(isFail) {95 g.setColor(Color.RED);96 g.setFont(new Font("微軟雅黑",Font.BOLD,40));97 g.drawString("失敗!按p鍵重新開始!", 300, 200);98 //如果不是失敗也不在游戲中,就是剛進游戲or暫停狀態,顯示提示信息
99 }else if(!(isStart)) {100 g.setColor(Color.WHITE);101 g.setFont(new Font("微軟雅黑",Font.BOLD,40));102 g.drawString("按空格開始游戲", 300, 200);103 }104 //蛇頭的位置和方向,direction是根據鍵盤的輸入改變的,up就畫向上的蛇頭,down就畫向下的蛇頭,至于移動的方向在actionPerformed()中決定
105 if(direction.equals("right")) {106 right.paintIcon(this, g, snakeX[0], snakeY[0]);107 }else if(direction.equals("left")) {108 left.paintIcon(this, g, snakeX[0], snakeY[0]);109 }else if(direction.equals("up")) {110 up.paintIcon(this, g, snakeX[0], snakeY[0]);111 }else if(direction.equals("down")) {112 down.paintIcon(this, g, snakeX[0], snakeY[0]);113 }114 //蛇身的位置115 //如果是初始游戲,即count是2,畫在初始位置
116 if(count==2) {117 body.paintIcon(this, g, snakeX[1], snakeY[1]);118 body.paintIcon(this, g, snakeX[2], snakeY[2]);119 //否則,根據實時的坐標畫,坐標在actionPerformed()中不斷地改變
120 }else{121 for(int i=1;i
126 if(snakeX[0]==foodX && snakeY[0]==foodY) {127 isEaten=true;128 this.length++;129 }130 //失敗判定,改變游戲狀態為失敗,并提示失敗信息
131 for(int i=1;i
143 int keyCode=e.getKeyCode();144 //如果是空格并且游戲不是失敗狀態,說明是要開始or暫停游戲
145 if(keyCode==KeyEvent.VK_SPACE && !(isFail)) {146 isStart=!(isStart);147 repaint();148 //如果是方向鍵,改變direction信息
149 }else if(keyCode==KeyEvent.VK_UP) {150 direction="up";151 }else if(keyCode==KeyEvent.VK_DOWN) {152 direction="down";153 }else if(keyCode==KeyEvent.VK_LEFT) {154 direction="left";155 }else if(keyCode==KeyEvent.VK_RIGHT) {156 direction="right";157 //如果是p并且游戲是失敗的,改變游戲狀態,初始化蛇的信息
158 }else if(keyCode==KeyEvent.VK_P &&isFail) {159 isFail=false;160 this.snakeSetup();161 repaint();162 }163 }164 @Override165 public voidactionPerformed(ActionEvent e) {166 //如果是在游戲中,會不斷地改變坐標,讓后一節身體取代前一節部位的位置。167 //如果不在游戲中或者失敗了,這就是個空方法,蛇的坐標不改變,蛇也就不動了。
168 if(isStart && !(isFail)){169 for(int i=this.length-1;i>0;i--) {170 snakeX[i]=snakeX[i-1];171 snakeY[i]=snakeY[i-1];172 }173 //如果向右,那么頭每次向右移動一格,縱坐標不變,一旦越界,從另一頭出來。
174 if(direction.equals("right")) {175 snakeX[0] +=25;176 if(snakeX[0]>850) {177 snakeX[0]=75;178 }179 }else if(direction.equals("left")) {180 snakeX[0] -=25;181 if(snakeX[0]<25) {182 snakeX[0]=850;183 }184 }else if(direction.equals("up")) {185 snakeY[0] -=25;186 if(snakeY[0]<75) {187 snakeY[0]=650;188 }189 }else if(direction.equals("down")) {190 snakeY[0] +=25;191 if(snakeY[0]>650) {192 snakeY[0]=75;193 }194 }195 repaint();196 }197 }198 @Override199 public voidkeyTyped(KeyEvent e) {}200 @Override201 public voidkeyReleased(KeyEvent e) {}202 }203 public class貪吃蛇 {204 public static voidmain(String[] args) {205 JFrame f=new JFrame("貪吃蛇");206 f.setBounds(100,150,900,720);207 f.setResizable(false);208 f.add(newGamePanel());209 f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);210 f.setVisible(true);211 }212 }
個人認為這個游戲的核心在于要通過標志位來控制游戲的幾種狀態,同時還要通過這幾個標志位來決定這個蛇是否移動;除此之外,蛇的移動一定得注意到其實只需要控制頭的位置,后面的身體只要不斷的取代前一節部位的位置就可以了。
當然這只是貪吃蛇的最基本實現,其實還可以加進去很多功能,除了我這里省略了的積分系統,還可以引入等級系統,lv1的時候蛇移動的速度慢,lv5的時候移動快,這通過改變timer的第一個參數的大小就能實現了。更高級的話,甚至可以聯系到數據庫,搞一個存檔功能,聯系到網絡編程,搞一個聯機功能……如果有朝一日我能深諳各種高端的操作了,或許我會回到這最初的起點,寫一個超豪華版的貪吃蛇。
總結
以上是生活随笔為你收集整理的贪吃蛇java 暂停_Java实现贪吃蛇小游戏的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: POS打印机系列之 = 网口
- 下一篇: java美元兑换,(Java实现) 美元