java 編寫貪吃蛇小遊戲

前段時間用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) {

    }
}

運行效果:

遊戲開始界面:

遊戲運行界面:

有問題歡迎在下方留言,相互討論一下。