java gui詳解貪吃蛇小游戲?qū)崿F(xiàn)流程
根據(jù)狂神的視頻做的,然后自己優(yōu)化了一些bug,比如新生成食物的時(shí)候不會(huì)生成在蛇的身體上,再新增長身體的時(shí)候不會(huì)在左上角出現(xiàn)一個(gè)綠色的方塊以及增加了難度控制功能,以及可以使用WASD進(jìn)行控制,而不僅僅限于上下左右方向鍵
最后的游戲界面是這樣的:
可以在上方的菜單欄里選擇不同的難度進(jìn)行游戲.難度對應(yīng)的是不同的蛇移動(dòng)的速度,點(diǎn)擊退出游戲和點(diǎn)擊右上角的X是一樣的功能,都是退出游戲.然后點(diǎn)擊重新開始就會(huì)回到最初的時(shí)候重新開始游戲.
按下空格開始游戲,隨時(shí)可以再次按下空格進(jìn)行暫停游戲.同時(shí)每吃到一個(gè)食物就會(huì)在右上角加10分.
游戲代碼一共分成了三個(gè)類
一個(gè)是GameStart類,用來創(chuàng)建JFrame繪制游戲主體.
一個(gè)是GamePanel類,用來添加在JFrame中,里面加入了菜單欄以及一些鍵盤監(jiān)聽器,用來根據(jù)讀入的信息操縱蛇移動(dòng).
另一個(gè)是Data類,用來讀取statics文件夾中的圖片素材,代碼更簡潔.
GameStart類代碼如下:(具體代碼后面都有注釋)
import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; /** * @author Laurie */ public class GameStart { public static void main(String[] args) { JFrame jframe = new JFrame("貪吃蛇"); jframe.setBounds(10, 10, 900, 720);//繪制游戲主界面的范圍 jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); jframe.setResizable(false);//不可擴(kuò)大縮小窗口 GamePanel gamePanel = new GamePanel(); jframe.add(gamePanel); jframe.setVisible(true);//顯形 gamePanel.setLayout(new BorderLayout()); } }
GamePanel類代碼是:
import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.Random; /** * @author Laurie */ public class GamePanel extends JPanel implements ActionListener, KeyListener { int length;//蛇的長度 int[] snakeX = new int[500];//隨便定義長度,反之不出意外是不會(huì)超過的 int[] snakeY = new int[500]; String direction;//蛇的方向,來根據(jù)這個(gè)改變蛇頭的圖片 Timer timer = new Timer(60, this);//計(jì)時(shí)器,來觸發(fā)蛇移動(dòng)的事件 int score;//分?jǐn)?shù) Boolean isFail = false;//是否失敗判斷 Boolean isStart = false;//是否啟動(dòng)判斷 int foodX;//食物坐標(biāo) int foodY; Random random = new Random();//用來產(chǎn)生隨機(jī)數(shù)的Random類的實(shí)例化 public void init(){ length = 3;//一開始蛇的三節(jié) snakeX[0] = 100;//蛇頭為下標(biāo)0 snakeY[0] = 100; snakeX[1] = 75; snakeY[1] = 100; snakeX[2] = 50; snakeY[2] = 100; direction = "R";//初始化方向朝右邊 score = 0; foodX = getFoodX();//通過方法獲取食物的坐標(biāo) foodY = getFoodY(); } public GamePanel(){ //構(gòu)造函數(shù) init();//進(jìn)行初始化 this.setFocusable(true);//設(shè)置可以被賦予焦點(diǎn) this.setForeground(Color.pink);//設(shè)置為粉色 this.addKeyListener(this);//添加鍵盤的監(jiān)聽 timer.start();//開始計(jì)時(shí)器 JMenuBar menuBar = new JMenuBar();//選項(xiàng)欄 JButton jb1 = new JButton("退出游戲"); JButton jb3 = new JButton("新手難度"); JButton jb4 = new JButton("高手難度"); JButton jb5 = new JButton("地獄難度"); menuBar.add(jb1); menuBar.add(jb3); menuBar.add(jb4); menuBar.add(jb5); jb1.addActionListener(e -> {//添加jb1的監(jiān)聽 System.exit(0);//退出 }); jb3.addActionListener(e -> { this.requestFocus();//不獲取焦點(diǎn)后面操作鍵盤都會(huì)在菜單欄里,就無法操作蛇了 timer.stop();//把原來的timer停止 timer = new Timer(80, this);//使蛇的速度變慢 timer.start();//重新開始timer }); jb4.addActionListener(e -> { this.requestFocus(); timer.stop(); timer = new Timer(40, this); timer.start(); }); jb5.addActionListener(e -> { this.requestFocus(); timer.stop(); timer = new Timer(20, this); timer.start(); }); this.add(menuBar); JButton jb2 = new JButton("重新開始"); jb2.addActionListener(e -> { init();//重新開始所以重新初始化一下 repaint();//重畫 this.requestFocus(); }); this.add(jb2); } public int getFoodX(){ //如果沒有判斷的話會(huì)出現(xiàn)bug,也就是食物可能出現(xiàn)在蛇的身體里,所以要進(jìn)行判斷優(yōu)化 boolean flag = true; int x = 25 + 25 * random.nextInt(34);//因?yàn)橐桓駷?5,所以要乘一個(gè)25 while(flag){ for(int i = 0; i < length; i++){ if(snakeX[i] == x) { x = 25 + 25 * random.nextInt(34);//如果和身體重合就重新隨機(jī)一個(gè)數(shù) }else{ flag = false; } } } return x; } public int getFoodY(){ boolean flag = true; int y = 75 + 25 * random.nextInt(24);//24是計(jì)算出來的,總panel的大小除以25 while(flag){ for(int i = 0; i < length; i++){ if(snakeY[i] == y) { y = 75 + 25 * random.nextInt(34); }else{ flag = false; } } } return y; } @Override protected void paintComponent(Graphics g) { super.paintComponents(g);//這個(gè)不加可能會(huì)出問題 this.setBackground(Color.white); g.fillRect(0,0,90,30); g.setColor(Color.black); g.drawString("貪吃蛇大挑戰(zhàn)",10,20); g.setColor(Color.LIGHT_GRAY);//分?jǐn)?shù)提示框 g.fillRect( 25, 36, 850, 40); g.setColor(Color.pink);//游戲主界面 g.fillRect(25,75, 850, 600); if ("R".equals(direction)) {//判斷是什么蛇頭朝向,選擇不同的蛇頭圖片 Data.right.paintIcon(this, g, snakeX[0], snakeY[0]); } else if ("L".equals(direction)) { Data.left.paintIcon(this, g, snakeX[0], snakeY[0]); } else if ("U".equals(direction)) { Data.up.paintIcon(this, g, snakeX[0], snakeY[0]); } else if ("D".equals(direction)) { Data.down.paintIcon(this, g, snakeX[0], snakeY[0]); } for (int i = 1; i < length; i++) {//通過for循環(huán)繪制蛇的身體 Data.body.paintIcon(this, g, snakeX[i], snakeY[i]); } g.setColor(Color.WHITE); g.setFont(new Font("微軟雅黑", Font.BOLD, 18)); g.drawString("長度:"+length,650,54); g.drawString("分?jǐn)?shù):"+score,750,54);//分?jǐn)?shù)長度等的繪制 Data.food.paintIcon(this, g, foodX, foodY);//繪制食物 if (!isStart) {//如果還沒開始就提示按下空格開始 g.setColor(Color.WHITE); g.setFont(new Font("微軟雅黑", Font.BOLD, 40)); g.drawString("按下空格來開始游戲", 300, 300); } if (isFail) {//如果失敗了就提示按下空格重新開始 g.setColor(Color.red); g.setFont(new Font("微軟雅黑", Font.BOLD, 40)); g.drawString("蛇死了哦,按下空格重新開始吧", 200, 300); } } @Override public void actionPerformed(ActionEvent e) { if (isStart && !isFail) {//如果已經(jīng)開始并且沒有失敗 for (int i = length - 1; i > 0; i--) { snakeX[i] = snakeX[i - 1]; //就把每節(jié)身體的位置都變成上一個(gè)身體的位置來模擬移動(dòng) snakeY[i] = snakeY[i - 1]; } if ("R".equals(direction)) { //動(dòng)完了身體,這里動(dòng)蛇頭,根據(jù)不同的方向來動(dòng)到位置 snakeX[0] = snakeX[0] + 25; if (snakeX[0] > 850) { snakeX[0] = 25; } } else if ("L".equals(direction)) { snakeX[0] = snakeX[0] - 25; if (snakeX[0] < 25) { snakeX[0] = 850; } } else if ("U".equals(direction)) { snakeY[0] = snakeY[0] - 25; if (snakeY[0] < 75) { snakeY[0] = 650; } } else if ("D".equals(direction)) { snakeY[0] = snakeY[0] + 25; if (snakeY[0] > 650) { snakeY[0] = 75; } } if (snakeX[0] == foodX && snakeY[0] == foodY) {//判斷是否吃到食物 //如果兩者的xy坐標(biāo)重合了就說明吃到了 length++;//吃到了長度加一 snakeX[length - 1] = foodX - 1;//這里是避免出現(xiàn)一個(gè)bug,沒有這兩行就會(huì)在吃吃到以后左上角出現(xiàn)一個(gè)綠方塊 //這是因?yàn)樾略黾拥纳眢w沒有賦值坐標(biāo),所以就默認(rèn)在00的位置 snakeY[length - 1] = foodY - 1; score = score + 10; foodX = getFoodX();//重新生成新的食物 foodY = getFoodY(); } for(int i = 1; i < length; i++){//進(jìn)行判斷是否死亡,當(dāng)蛇頭和身體重合就是死亡 if (snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]) { isFail = true; break; } } repaint();//蛇移動(dòng)了所以需要重新畫一遍 } timer.start();//計(jì)時(shí)器重新開始,蛇再進(jìn)行下一步移動(dòng) } @Override public void keyPressed(KeyEvent e) { int keyCode = e.getKeyCode();//這個(gè)為接受的鍵盤的按鍵對應(yīng)的代碼 if(keyCode == KeyEvent.VK_SPACE){//如果是空格的話激素hi進(jìn)行判斷 if(!isFail){//如果沒有失敗就進(jìn)行暫停與重新游戲的功能實(shí)現(xiàn) isStart = !isStart; }else{//如果已經(jīng)死了就重新開始 isFail = false; init(); } repaint();//重新繪制 } if (keyCode == KeyEvent.VK_LEFT && !"R".equals(direction)) {//檢查獲取的是上下左右的哪個(gè)進(jìn)行蛇頭轉(zhuǎn)向 direction = "L"; } else if (keyCode == KeyEvent.VK_RIGHT && !"L".equals(direction)) { direction = "R"; } else if (keyCode == KeyEvent.VK_UP && !"D".equals(direction)) { direction = "U"; } else if (keyCode == KeyEvent.VK_DOWN && !"U".equals(direction)) { direction = "D"; } if (keyCode == KeyEvent.VK_A && !"R".equals(direction)) {//檢查獲取的是wasd的哪個(gè)進(jìn)行蛇頭轉(zhuǎn)向 //注意當(dāng)是與蛇頭反方向的不可以進(jìn)行轉(zhuǎn)動(dòng),畢竟也不能180度轉(zhuǎn)脖子把 direction = "L"; } else if (keyCode == KeyEvent.VK_D && !"L".equals(direction)) { direction = "R"; } else if (keyCode == KeyEvent.VK_W && !"D".equals(direction)) { direction = "U"; } else if (keyCode == KeyEvent.VK_S && !"U".equals(direction)) { direction = "D"; } } //這兩個(gè)沒有用,所以不用寫了 @Override public void keyTyped(KeyEvent e) { } @Override public void keyReleased(KeyEvent e) { } }
Data類代碼是:
import javax.swing.*; import java.awt.*; import java.net.URL; /** * @author Laurie */ public class Data { //讀取statics文件夾里的圖片,加載成圖片 public static URL bodyURL = Data.class.getResource("/statics/body.png"); public static URL foodURL = Data.class.getResource("/statics/food.png"); public static URL downURL = Data.class.getResource("/statics/down.png"); public static URL upURL = Data.class.getResource("/statics/up.png"); public static URL rightURL = Data.class.getResource("/statics/right.png"); public static URL leftURL = Data.class.getResource("/statics/left.png"); public static ImageIcon body = new ImageIcon(bodyURL); public static ImageIcon food = new ImageIcon(foodURL); public static ImageIcon down = new ImageIcon(downURL); public static ImageIcon up = new ImageIcon(upURL); public static ImageIcon right = new ImageIcon(rightURL); public static ImageIcon left = new ImageIcon(leftURL); }
整個(gè)項(xiàng)目文件可以在github上自取,點(diǎn)擊藍(lán)字
github
上不去的也可以在gitee上自取,點(diǎn)擊藍(lán)字
gitee
💕
真的不下一個(gè)自己玩一玩嗎[手動(dòng)滑稽]
到此這篇關(guān)于java gui詳解貪吃蛇小游戲?qū)崿F(xiàn)流程的文章就介紹到這了,更多相關(guān)java 貪吃蛇內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Springboot內(nèi)置的工具類之CollectionUtils示例講解
這篇文章主要介紹了Springboot內(nèi)置的工具類之CollectionUtils,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-12-12Java中I/O流讀取數(shù)據(jù)不完整的問題解決
本文主要介紹了ava中I/O流讀取數(shù)據(jù)不完整的問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05java隨機(jī)驗(yàn)證碼生成實(shí)現(xiàn)實(shí)例代碼
這篇文章主要介紹了java隨機(jī)驗(yàn)證碼生成實(shí)現(xiàn)實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下2017-05-05深入淺析Java中普通代碼塊、構(gòu)造代碼塊與靜態(tài)代碼塊
這篇文章主要介紹了Java中普通代碼塊、構(gòu)造代碼塊與靜態(tài)代碼塊的相關(guān)資料,靜態(tài)代碼塊>Main()>構(gòu)造代碼塊 。非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-08-08Java純代碼實(shí)現(xiàn)導(dǎo)出PDF功能
在項(xiàng)目開發(fā)中,產(chǎn)品的需求越來越奇葩啦,開始文件下載都是下載為excel的,做著做著需求竟然變了,要求能導(dǎo)出pdf,本文就來和大家分享一下Java實(shí)現(xiàn)導(dǎo)出PDF的常用方法吧2023-07-07JavaWEB項(xiàng)目之如何配置動(dòng)態(tài)數(shù)據(jù)源
這篇文章主要介紹了JavaWEB項(xiàng)目之如何配置動(dòng)態(tài)數(shù)據(jù)源問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06Spring源碼剖析之Spring處理循環(huán)依賴的問題
大家都知道循環(huán)依賴依賴指的是Bean與Bean之間的依賴關(guān)系,循環(huán)依賴指的是兩個(gè)或者多個(gè)Bean相互依賴,本文通過代碼示例給大家講解Spring處理循環(huán)依賴的問題,感興趣的朋友一起看看吧2021-06-06