前段時間用Android編寫了一個貪喫蛇的小遊戲,感覺還不錯,就想着能不能用java編寫有個貪喫蛇的遊戲,在電腦上面運行。於是就開始動手寫了。
編寫貪喫蛇遊戲的博客或文檔特別多,有些寫的挺好的,都是一個共同的思想。都是通過沒喫到食物時,頭加尾減。喫到食物時頭加尾不減。
我們看看通過java寫這個遊戲,要使用到哪些知識點,有可能寫的不全面或不是最好的方法,希望在下面留言,指正下。
1:java裏面關於swing的知識需要了解。圖形化界面編程會用到裏面的一些控件,例如 JFram,JPanel,JButton,JSpinner等。所以想學的同學,餘姚瞭解swing。
2:java裏面畫布的知識瞭解下,類似於Canvas的。在java裏面是通過Graphics 進行繪圖的,以爲我們需要將蛇體的當前狀態和食物的當前位置繪製在面板上面。
3:瞭解下java裏面關於鍵盤事件的監聽,以爲我們是通過鍵盤操作遊戲的。
好了基本需要的知識就這些,剩下的就需要自己去實現邏輯代碼,把整個遊戲完成。來看看怎麼寫。
我在定義了三個類,主類 MyClass ,JFramDemo,Snake。
主類就不講,java代碼是從主類裏面的main方法開始運行的。在這我把主要代碼放在JFramDemo與Snake裏面。主類比較少,知識讓整個代碼運行起來的。
public class MyClass { public static void main(String[] strings) { JFarmDemo mJFarmDemo = new JFarmDemo(); } }
這上面就是我的主類,是不是比較少。所以重點在JFarmDemo 類裏面。
JFarmDemo 類:
package com.example.lib.java; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Cursor; import java.awt.FlowLayout; import java.awt.Image; import java.awt.Point; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSpinner; import javax.swing.JTabbedPane; import javax.swing.SpinnerListModel; import javax.swing.SpinnerModel; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; public class JFarmDemo { /** * mJFrame第一次顯示的窗體,遊戲開始前選擇遊戲難度的窗體 * jFrame 點擊開始按鈕後顯示的窗體,遊戲正在運行的窗體 * */ private static JFrame mJFrame, jFrame; private static JLabel mJLabel, mJLabel1; private static JPanel mJPanel, mJPanel2; private static JButton mJButton, mJButton2; private static JSpinner mJSpinner; private static String[] strings; private static int number = 20; public JFarmDemo() { init_J(); mJFrame.setBounds(500, 200, 300, 450); mJFrame.setBackground(Color.BLUE); mJFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); mJFrame.setLayout(new BorderLayout(10, 10)); mJPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 10)); mJPanel.add(mJButton); mJPanel.add(mJLabel1); SpinnerModel model = new SpinnerListModel(strings); mJSpinner = new JSpinner(model); mJSpinner.setSize(50, 50); mJPanel.add(mJSpinner); mJPanel.add(mJButton2); ImageIcon mIcon = new ImageIcon("image/snakeback.png"); mJLabel = new JLabel(mIcon); mJPanel2.add(mJLabel); mJFrame.add(mJPanel, BorderLayout.SOUTH); mJFrame.add(mJPanel2, BorderLayout.CENTER); mJFrame.setResizable(false); mJFrame.setVisible(true); Listen(); } private void init_J() { mJFrame = new JFrame("貪喫蛇"); jFrame = new JFrame("遊戲界面"); mJPanel = new JPanel(); mJPanel2 = new JPanel(); mJButton = new JButton("開始"); mJLabel1 = new JLabel("選擇難度"); mJButton2 = new JButton("退出"); strings = new String[]{"簡單", "一般", "困難"}; } private void Listen() { mJButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { mJFrame.setVisible(false); jFrame.getContentPane().setBackground(Color.CYAN); Snake snake = new Snake(number, 300, 440); snake.setBackground(Color.BLUE); jFrame.add(snake); jFrame.setBounds(500, 200, 320, 480); jFrame.setResizable(false); jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); jFrame.setVisible(true); } }); mJSpinner.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent changeEvent) { switch (mJSpinner.getValue().toString()) { case "簡單": number = 20; break; case "一般": number = 15; break; case "困難": number = 10; break; default: break; } } }); mJButton2.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { mJFrame.dispose(); } }); } }
Snake類:
package com.example.lib.java; import java.awt.Color; import java.awt.Graphics; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.ArrayList; import java.util.List; import java.util.Random; import javax.swing.JComponent; public class Snake extends JComponent implements KeyListener { private static List<Head> headList = new ArrayList<>(); private static int mSecretion; private static boolean isRuning = true; private static boolean iseating = true; private static boolean isChange = false; private static int a, b, space ; private static int weight, high; public Snake(final int number, int weight, int high) { Snake.weight = weight; Snake.high = high; space = number; this.setFocusable(true); // 獲取焦點 this.addKeyListener(this); // 監聽鍵盤事件 headList.add(new Head()); a = 4; b = 5; new Thread(new Runnable() { @Override public void run() { while (isRuning) { try { Thread.sleep(100); repaint(); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } @Override protected void paintComponent(Graphics graphics) { super.paintComponent(graphics); for (int i = 1; i <= weight / space; i++) { graphics.drawLine(i * space, 0, i * space, high); } for (int i = 1; i <= high / space; i++) { graphics.drawLine(0, i * space, weight, i * space); } graphics.setColor(Color.BLUE); if (isChange) { isChange = false; a = new Random().nextInt(14) + 1; b = new Random().nextInt(21) + 1; } graphics.fillRect(a * space, b * space, space, space); graphics.setColor(Color.BLACK); for (int i = 0; i < headList.size(); i++) { if (i==0){ graphics.setColor(Color.RED); }else { graphics.setColor(Color.BLACK); } graphics.fillRect(headList.get(i).x, headList.get(i).y, space, space); } snakeMove(headList, mSecretion); if (iseating) { headList.remove(headList.size() - 1); } iseating = true; } public void snakeMove(List<Head> heads, int mSnakedirection) { Head mOldHead = heads.get(0); Head mNewheads = new Head(); switch (mSnakedirection) { //上 case 1: mNewheads.x = mOldHead.x; mNewheads.y = mOldHead.y - space; break; //下 case 2: mNewheads.x = mOldHead.x; mNewheads.y = mOldHead.y + space; break; //左 case 3: mNewheads.x = mOldHead.x + space; mNewheads.y = mOldHead.y; break; //右 case 4: mNewheads.x = mOldHead.x - space; mNewheads.y = mOldHead.y; break; } Crossing(mNewheads.x, mNewheads.y); EatMyself(heads); EatFood(mNewheads.x, mNewheads.y); Sanme(heads); heads.add(0, mNewheads); } /** * 越界 * * @param x * @param y */ private void Crossing(int x, int y) { if ((x < 0 || x > 280) || (y < 0 || y > 420)) { isRuning = false; } } /** * 碰到自己 */ private void EatMyself(List<Head> heads) { for (int i = 1; i < heads.size(); i++) { if (heads.get(0).x == heads.get(i).x && heads.get(0).y == heads.get(i).y) { isRuning = false; } } } /** * 喫到食物 */ private void EatFood(int x, int y) { if (x == a * space && y == b * space) { iseating = false; isChange = true; } } /** * 避免食物與蛇體重合 */ private void Sanme(List<Head> heads) { for (int i = 0; i < heads.size(); i++) { if (a == heads.get(i).x && b == heads.get(i).y) { a = new Random().nextInt(14) + 1; b = new Random().nextInt(21) + 1; } } } @Override public void keyTyped(KeyEvent keyEvent) { } @Override public void keyPressed(KeyEvent keyEvent) { int keyCode = keyEvent.getKeyCode(); // System.out.print("鍵盤值:" + keyCode + "\n"); //上 if ((keyCode == 87 || keyCode == 38) && mSecretion != 2) { mSecretion = 1; } //下 else if ((keyCode == 83 || keyCode == 40) && mSecretion != 1) { mSecretion = 2; }//左 else if ((keyCode == 68 || keyCode == 39 )&& mSecretion != 4) { mSecretion = 3; }//右 else if ((keyCode == 65 || keyCode == 37 )&& mSecretion != 3) { mSecretion = 4; } } @Override public void keyReleased(KeyEvent keyEvent) { } }
運行效果:
遊戲開始界面:
遊戲運行界面:
有問題歡迎在下方留言,相互討論一下。