Java Swing實現五子棋程序

首先感謝08年MLDN出的這個培訓視頻,我把代碼和文檔整理了一下,發佈出來給需要學習Swing的朋友。

 

源碼地址:

https://gitee.com/indexman/gobang

 

一、知識點準備:

JFrame:窗體

JOptionPane:對話框

MouseListener:鼠標事件

Graphics:繪製二維圖像

Thread:線程類

 

二、五子棋遊戲的功能:

  1. 在點擊鼠標時,可以在相應的位置顯示棋子。
  2. 可以自動判斷遊戲是否結束,是否黑方或白方已經勝利
  3. 對遊戲時間進行設置,判斷是否超出規定時間

 

三、遊戲開發步驟

 

1.開發遊戲界面

計算棋盤中每一條線的間距:這裏用的是19X19的圍棋棋盤,

總寬度爲360px, 分成18份,每份是20px

 

2.在棋盤上的鼠標點擊位置,顯示一個棋子

黑子:一個實心的黑圓表示

白子:一個空心的黑圓+一個實心的白圓表示

 

repaint() 方法表示重新執行一次paint()方法。

 

3.保存之前下過的棋子

通過一個二維數組來保存之前下過的所有棋子。

 

4.判斷遊戲勝負

依據 五子棋 的基本遊戲規則,判斷是否有同一顏色的棋子連城5個。

 

完成五子棋遊戲的核心算法

這裏可以把核心算法總結成一個靈活的方法。

提示信息的保存

 

5.處理屏幕閃爍問題

使用雙緩衝技術

 

6.實現各個按鈕的功能

開始遊戲:重新開始遊戲

遊戲設置: 設置倒計時時間

遊戲說明:用來說明遊戲規則和操作

認輸:某一方放棄遊戲,投子認負

關於:顯示遊戲製作者

退出:退出程序

-----------------------------------------------------分割線------------------------------------------------------

四、代碼部分

 

1.啓動類

package com.laoxu.game;

import com.laoxu.game.view.GobangFrame;
import com.laoxu.game.view.MyFrame;

/**
 * Hello world!
 *
 */
public class App 
{
    public static void main( String[] args )
    {

        GobangFrame frame = new GobangFrame();
        //MyFrame myFrame = new MyFrame();
        //JOptionPane
        /*JOptionPane.showMessageDialog(myFrame,"我的信息");
        int result = JOptionPane.showConfirmDialog(myFrame,"確定要開始遊戲嗎?","",0);
        if(result==0){
            JOptionPane.showMessageDialog(myFrame,"遊戲開始");
        }
        if(result==1){
            JOptionPane.showMessageDialog(myFrame,"遊戲結束");
        }
        if(result==2){
            JOptionPane.showMessageDialog(myFrame,"重新選擇");
        }

        String username = JOptionPane.showInputDialog("請輸入你的姓名:");
        System.out.println(username);
        JOptionPane.showMessageDialog(myFrame,"輸入的姓名爲:"+username);*/
        //System.out.println(System.getProperty("user.dir")+"/src/image/background.jpg");

    }
}

 

2.五子棋類

 

package com.laoxu.game.view;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

/**
 * @description: 五子棋主界面
 * @author: luohanye
 * @create: 2019-03-21
 **/
public class GobangFrame extends JFrame implements MouseListener,Runnable {
    //獲取當前平面分辨率,例如:1920x1080
    int swidth = Toolkit.getDefaultToolkit().getScreenSize().width;
    int sheight = Toolkit.getDefaultToolkit().getScreenSize().height;

    BufferedImage image = null;
    //保存座標值
    int x = 0;
    int y = 0;
    //保存下過的棋子 0-沒有棋子 1-黑子 2-白子
    int[][] allChess = new int[19][19];
    // 標識當前應該是黑子還是白子
    boolean isBlack = true;
    // 控制遊戲是否可以玩
    boolean canPlay = true;
    // 保存遊戲信息
    String message = "黑方先行";
    // 保存最多擁有多少時間(秒)
    int maxTime = 0;
    // 做倒計時的線程類
    Thread t = new Thread(this);
    // 保存黑方與白方的剩餘時間
    int blackTime = 0;
    int whiteTime = 0;
    // 保存雙方剩餘時間的顯示信息
    String blackMessage = "無限制";
    String whiteMessage = "無限制";

    public GobangFrame() {
        //設置標題
        this.setTitle("五子棋");
        int width = 500, height = 500;
        this.setSize(width, height);

        //設置窗體出現的位置
        this.setLocation((swidth - width) / 2, (sheight - height) / 2);
        //窗口大小不可變
        this.setResizable(false);
        //定義關閉動作
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //添加監聽器
        this.addMouseListener(this);
        //窗體可見
        this.setVisible(true);

        //加載背景圖片
        try {
            image = ImageIO.read(new File(System.getProperty("user.dir")+"/src/image/background.jpg"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 啓動線程
        t.start();
        t.suspend();

        // 刷新屏幕,防止開始遊戲時出現無法顯示的情況.
        this.repaint();
    }

    public void paint(Graphics g) {
        //雙緩衝技術防止屏幕閃爍
        BufferedImage bi = new BufferedImage(500,500,BufferedImage.TYPE_INT_RGB);
        Graphics g2 = bi.createGraphics();
        g2.setColor(Color.BLACK);
        //繪製背景
        g2.drawImage(image, 0, 20, this);
        g2.setFont(new Font("黑體", Font.BOLD, 20));
        g2.drawString("遊戲信息:"+message, 130, 60);
        //輸出時間信息
        g2.setFont(new Font("宋體", 0, 14));
        g2.drawString("黑方時間:" + blackMessage, 30, 470);
        g2.drawString("白方時間:" + whiteMessage, 260, 470);

        //繪製棋盤
        /**
         *          X=10 Y=70
         *         X=370 Y=430
         *         X=370 Y=70
         *         X=10 Y=430
         */
        for (int i = 0; i < 19; i++) {
            g2.drawLine(10, 70 + 20 * i, 370, 70 + 20 * i);
            g2.drawLine(10 + 20 * i, 70, 10 + 20 * i, 430);
        }
        //標註點位
        g2.fillOval(68, 128, 4, 4);
        g2.fillOval(308, 128, 4, 4);
        g2.fillOval(308, 368, 4, 4);
        g2.fillOval(68, 368, 4, 4);

        g2.fillOval(68, 248, 4, 4);
        g2.fillOval(308, 248, 4, 4);
        g2.fillOval(188, 128, 4, 4);
        g2.fillOval(188, 368, 4, 4);

        g2.fillOval(188, 248, 4, 4);

        //繪製棋子
        for (int i = 0; i < 19; i++) {
            for (int j = 0; j < 19; j++) {
                //黑子
                if (allChess[i][j] == 1) {
                    int tempX = i * 20 + 10;
                    int tempY = j * 20 + 70;
                    g2.fillOval(tempX - 7, tempY - 7, 14, 14);
                }
                //白子
                if (allChess[i][j] == 2) {
                    int tempX = i * 20 + 10;
                    int tempY = j * 20 + 70;
                    g2.setColor(Color.WHITE);
                    g2.fillOval(tempX - 7, tempY - 7, 14, 14);
                    g2.setColor(Color.BLACK);
                    g2.drawOval(tempX - 7, tempY - 7, 14, 14);
                }
            }
        }

        g.drawImage(bi,0,0,this);
    }

    //鼠標按鍵在組件上按下時調用。
    @Override
    public void mousePressed(MouseEvent e) {
        System.out.println("X=" + e.getX() + " Y=" + e.getY());
        if (canPlay) {
            x = e.getX();
            y = e.getY();
            //判斷點擊是否在棋盤內
            if (x >= 10 && x <= 370 && y >= 70 && y <= 430) {
                x = (x - 10) / 20;
                y = (y - 70) / 20;

                if (allChess[x][y] == 0) {
                    if (isBlack) {
                        allChess[x][y] = 1;
                        isBlack = false;
                        message="輪到白方";
                    } else {
                        allChess[x][y] = 2;
                        isBlack = true;
                        message="輪到黑方";
                    }

                    //判斷遊戲是否結束
                    boolean isWin = this.checkWin();
                    if (isWin) {
                        JOptionPane.showMessageDialog(this, "遊戲結束,"
                                + (allChess[x][y] == 1 ? "黑方" : "白方") + "獲勝!");
                        canPlay = false;
                    }
                }

                this.repaint();
            }
        }

        // 點擊 【開始遊戲】 按鈕
        if(e.getX() >=400 && e.getX()<=470 && e.getY()>=70 && e.getY()<=100){
            int result = JOptionPane.showConfirmDialog(this,"是否重新開始遊戲?","",0);
            if(result==0){
                //1.清空棋盤
                allChess = new int[19][19];
                //另一種方式:
                /*for (int i = 0; i < 19; i++) {
                    for (int j = 0; j < 19; j++) {
                        allChess[i][j] = 0;
                    }
                }*/
                //2.重置遊戲信息
                message = "黑方先行";
                //3.將下一步下棋的人改爲黑方
                isBlack = true;
                //4.可以遊戲標誌改爲true
                canPlay = true;
                //5.重置黑白雙方時間限制
                blackTime = maxTime;
                whiteTime = maxTime;
                if (maxTime > 0) {
                    blackMessage = maxTime / 3600 + ":"
                            + (maxTime / 60 - maxTime / 3600 * 60) + ":"
                            + (maxTime - maxTime / 60 * 60);
                    whiteMessage = maxTime / 3600 + ":"
                            + (maxTime / 60 - maxTime / 3600 * 60) + ":"
                            + (maxTime - maxTime / 60 * 60);
                    t.resume();
                } else {
                    blackMessage = "無限制";
                    whiteMessage = "無限制";
                }
                //6.重新繪製窗體
                this.repaint();
            }
        }
        //點擊 【遊戲設置】 按鈕
        if (e.getX() >= 400 && e.getX() <= 470 && e.getY() >= 120
                && e.getY() <= 150) {
            String input = JOptionPane
                    .showInputDialog("請輸入遊戲的最大時間(單位:分鐘),如果輸入0,表示沒有時間限制:");
            try {
                maxTime = Integer.parseInt(input) * 60;
                if (maxTime < 0) {
                    JOptionPane.showMessageDialog(this, "請輸入正確信息,不允許輸入負數!");
                }
                if (maxTime == 0) {
                    int result = JOptionPane.showConfirmDialog(this,
                            "設置完成,是否重新開始遊戲?");
                    if (result == 0) {
                        for (int i = 0; i < 19; i++) {
                            for (int j = 0; j < 19; j++) {
                                allChess[i][j] = 0;
                            }
                        }
                        // 另一種方式 allChess = new int[19][19];
                        message = "黑方先行";
                        isBlack = true;
                        blackTime = maxTime;
                        whiteTime = maxTime;
                        blackMessage = "無限制";
                        whiteMessage = "無限制";
                        this.canPlay = true;
                        this.repaint();
                    }
                }
                if (maxTime > 0) {
                    int result = JOptionPane.showConfirmDialog(this,
                            "設置完成,是否重新開始遊戲?");
                    if (result == 0) {
                        for (int i = 0; i < 19; i++) {
                            for (int j = 0; j < 19; j++) {
                                allChess[i][j] = 0;
                            }
                        }
                        // 另一種方式 allChess = new int[19][19];
                        message = "黑方先行";
                        isBlack = true;
                        blackTime = maxTime;
                        whiteTime = maxTime;
                        blackMessage = maxTime / 3600 + ":"
                                + (maxTime / 60 - maxTime / 3600 * 60) + ":"
                                + (maxTime - maxTime / 60 * 60);
                        whiteMessage = maxTime / 3600 + ":"
                                + (maxTime / 60 - maxTime / 3600 * 60) + ":"
                                + (maxTime - maxTime / 60 * 60);
                        t.resume();
                        this.canPlay = true;
                        this.repaint();
                    }
                }
            } catch (NumberFormatException e1) {
                JOptionPane.showMessageDialog(this, "請正確輸入信息!");
            }
        }
        //點擊 【遊戲說明】 按鈕
        if(e.getX() >=400 && e.getX()<=470 && e.getY()>=170 && e.getY()<=200){
            JOptionPane.showMessageDialog(this,"這是一個五子棋遊戲程序,黑白雙方輪流下棋,當某一方連到五子時遊戲結束。");
        }
        //點擊 【認輸】 按鈕
        if(e.getX() >=400 && e.getX()<=470 && e.getY()>=270 && e.getY()<=300){
            int result = JOptionPane.showConfirmDialog(this,"是否確認認輸?","",0);
            if(result==0){
                if(isBlack){
                    JOptionPane.showMessageDialog(this,"黑方已經認輸,遊戲結束!");
                }else{
                    JOptionPane.showMessageDialog(this,"白方已經認輸,遊戲結束!");
                }
                //停止遊戲
                canPlay = false;
            }
        }
        //點擊 【關於】 按鈕
        if(e.getX() >=400 && e.getX()<=470 && e.getY()>=320 && e.getY()<=350){
            JOptionPane.showMessageDialog(this,"本遊戲由老徐製作,有問題請聯繫老徐。");
        }
        //點擊 【退出】 按鈕
        if(e.getX() >=400 && e.getX()<=470 && e.getY()>=370 && e.getY()<=400){
            JOptionPane.showMessageDialog(this,"遊戲結束!");
            System.exit(0);
        }
    }

    private boolean checkWin() {
        boolean flag = false;
        //統計相連棋子數
        //橫向
        int count = 1;
        int color = allChess[x][y];

        /*int i = 1;
        while (color == allChess[x + i][y]) {
            count++;
            i++;
        }

        i = 1;
        while (color == allChess[x - i][y]) {
            count++;
            i++;
        }

        if (count >= 5) {
            flag = true;
        }

        //豎向
        int count2 = 1;
        int i2 = 1;
        while (color == allChess[x][y+i2]) {
            count2++;
            i2++;
        }

        i2 = 1;
        while (color == allChess[x][y-i2]) {
            count2++;
            i2++;
        }

        if (count2 >= 5) {
            flag = true;
        }
        // 右上+左下
        int count3 = 1;
        int i3 = 1;
        while (color == allChess[x+i3][y-i3]) {
            count3++;
            i3++;
        }

        i3 = 1;
        while (color == allChess[x-i3][y+i3]) {
            count3++;
            i3++;
        }

        if (count3 >= 5) {
            flag = true;
        }
        // 左上+右下
        int count4 = 1;
        int i4 = 1;
        while (color == allChess[x-i4][y-i4]) {
            count4++;
            i4++;
        }

        i4 = 1;
        while (color == allChess[x+i4][y+i4]) {
            count4++;
            i4++;
        }

        if (count4 >= 5) {
            flag = true;
        }
*/      //判斷橫向
        count = this.checkCount(1,0,color);
        if(count>=5){
            flag = true;
        }else {
            //判斷縱向
            count = this.checkCount(0,1,color);
            if(count>=5){
                flag = true;
            }else {
                //判斷右上、左下
                count = this.checkCount(1, -1, color);
                if (count >= 5) {
                    flag = true;
                } else {
                    //判斷右下、左上
                    count = this.checkCount(1, 1, color);
                    if (count >= 5) {
                        flag = true;
                    }
                }
            }
        }
        return flag;

    }

    private int checkCount(int xChange, int yChange, int color){
        int count = 1;
        int tempX = xChange;
        int tempY = yChange;

        while ((x+xChange>=0 && x+xChange <= 18 && y+yChange>=0 && y+yChange <= 18 )&&color == allChess[x+xChange][y+yChange]){
            count++;
            if(xChange != 0){
                xChange++;
            }
            if(yChange!=0){
                if(yChange>0){
                    yChange++;
                }else {
                    yChange--;
                }
            }
        }

        xChange = tempX;
        yChange = tempY;

        while ((x-xChange>=0 && x-xChange <= 18 && y-yChange>=0 && y-yChange <= 18 )&&color == allChess[x-xChange][y-yChange]){
            count++;
            if(xChange != 0){
                xChange++;
            }
            if(yChange!=0){
                if(yChange>0){
                    yChange++;
                }else {
                    yChange--;
                }
            }
        }
        return count;
    }

    @Override
    public void run() {
        // 判斷是否有時間限制
        if (maxTime > 0) {
            while (true) {
                if (isBlack) {
                    blackTime--;
                    if (blackTime == 0) {
                        JOptionPane.showMessageDialog(this, "黑方超時,遊戲結束!");
                    }
                } else {
                    whiteTime--;
                    if (whiteTime == 0) {
                        JOptionPane.showMessageDialog(this, "白方超時,遊戲結束!");
                    }
                }
                blackMessage = blackTime / 3600 + ":"
                        + (blackTime / 60 - blackTime / 3600 * 60) + ":"
                        + (blackTime - blackTime / 60 * 60);
                whiteMessage = whiteTime / 3600 + ":"
                        + (whiteTime / 60 - whiteTime / 3600 * 60) + ":"
                        + (whiteTime - whiteTime / 60 * 60);
                this.repaint();
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(blackTime + " -- " + whiteTime);
            }
        }
    }

    // 鼠標單擊事件
    @Override
    public void mouseClicked(MouseEvent e) {
    }

    @Override
    public void mouseReleased(MouseEvent e) {

    }

    @Override
    public void mouseEntered(MouseEvent e) {

    }

    @Override
    public void mouseExited(MouseEvent e) {

    }
}

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章