Java實(shí)現(xiàn)數(shù)字連連消
本文實(shí)例為大家分享了Java實(shí)現(xiàn)數(shù)字連連消的具體代碼,供大家參考,具體內(nèi)容如下
游戲規(guī)則很簡(jiǎn)單,點(diǎn)擊選中兩個(gè)相同的數(shù)字即可消除這兩個(gè)數(shù)字,沒有做復(fù)雜的判斷。
效果圖


下面開始代碼
首先是MapTool.java,用于產(chǎn)生數(shù)字和判斷選中的兩個(gè)數(shù)字是否相同
package com.feonix;
import java.util.Random;
public class MapTool {
public static int[][] createMap() {
int[][] map = new int[10][10];
Random rand = new Random();
for (int i = 0; i < map.length; i++) {
for (int j = 0; j < map[i].length; j++) {
map[i][j] = rand.nextInt(9) + 1;
}
}
return map;
}
public static int[][] removed(int[][] map, int pi, int pj, int ci, int cj) {
if (map[pi][pj] == map[ci][cj] && (pj != cj || pi != ci)) {
System.out.println("消除:map[" + ci + "][" + cj + "],map[" + pi + "][" + pj + "]");
map[pi][pj] = 0;
map[ci][cj] = 0;
}
return map;
}
}
然后是GamePanel.java,游戲布局,游戲核心邏輯代碼
package com.feonix;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashSet;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.Timer;
public class GamePanel extends JPanel {
private static final long serialVersionUID = 2L;
private static final int sx = 50;// 左邊距
private static final int sy = 50;// 上邊距
private static final int w = 40; // 小方格寬高
private static final int rw = 400; // 網(wǎng)格總寬高
private int pj = 0, pi = 0; // 記錄兩個(gè)點(diǎn)擊選中的按鈕,第一個(gè)被點(diǎn)擊的按鈕坐標(biāo)
private int cc = 0;// 被點(diǎn)擊選中的按鈕個(gè)數(shù)
private int[][] map;// 存放游戲數(shù)據(jù)的二維數(shù)組
private boolean isEnd = false; // 游戲結(jié)束標(biāo)志
private JButton[][] btnMap; // 存放按鈕的二維數(shù)組,與map對(duì)應(yīng)
private int score; // 記錄分?jǐn)?shù)
private JButton restart; // 重新開始按鈕
private Timer timer; // 定時(shí)器
private int timestamp; // 時(shí)間戳
public GamePanel() {
// 設(shè)置布局為不使用預(yù)設(shè)的布局
setLayout(null);
}
/**
* 開始游戲
*/
public void start() {
// 創(chuàng)建游戲數(shù)據(jù)地圖
map = MapTool.createMap();
btnMap = new JButton[10][10];
score = 0;
timestamp = 0;
isEnd = false;
// 創(chuàng)建按鈕,設(shè)置按鈕屬性,監(jiān)聽事件,并添加到按鈕數(shù)組和窗體中
for (int i = 0; i < map.length; i++) {
for (int j = 0; j < map[i].length; j++) {
JButton btn = new JButton(map[i][j] + "");
btn.setBounds(sx + (j * w) + 2, sy + (i * w) + 2, w - 2, w - 2);
btn.setForeground(Color.RED);
btn.setFont(new Font("Arial", 0, 30));
btn.setBackground(Color.WHITE);
btn.setBorder(BorderFactory.createRaisedBevelBorder());
btn.setFocusPainted(false);
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 如果游戲結(jié)束,返回,不執(zhí)行后面的代碼
if (isEnd) {
return;
}
for (int i = 0; i < btnMap.length; i++) {
for (int j = 0; j < btnMap[i].length; j++) {
if (e.getSource().equals(btnMap[i][j])) {
// 被選中的方格個(gè)數(shù)增加一個(gè)
cc++;
compare(j, i);
}
}
}
}
});
btnMap[i][j] = btn;
this.add(btn);
}
}
if (restart != null) {
restart.setVisible(false);
this.remove(restart);
restart = null;
}
repaint();
// 定時(shí)器,用來刷新時(shí)間
timer = new Timer(1000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
timestamp++;
repaint();
}
});
timer.start();
}
/**
* 判斷是否游戲結(jié)束
* 1、判斷二維數(shù)組map中的所有元素是否均為0, 全部為0返回true表示游戲結(jié)束
* 2、有不為0的,判斷二維數(shù)組map中是否還有重復(fù)值,沒有重復(fù)值返回true表示游戲結(jié)束
* 否則返回false游戲繼續(xù)
*
* @param map 二維數(shù)組,元素為int類型
* @return
*/
public boolean isEnd(int[][] map) {
int count_0 = 0;
int count = 0;
HashSet<Integer> hashSet = new HashSet<Integer>();
for (int[] ms : map) {
for (int m : ms) {
count++;
if (m != 0) {
hashSet.add(m);
} else {
count_0++;
}
}
}
for (int[] ms : map) {
for (int m : ms) {
if (m != 0) {
if (hashSet.size() + count_0 == count) {
return true;
}
return false;
}
}
}
return true;
}
/**
* 重載JPanel父類的paintComponent方法,用來繪制網(wǎng)格,以及Game Over等
*/
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
try {
// 獲取分鐘
int min = timestamp / 60;
// 獲取秒數(shù)
int sec = timestamp % 60;
// 判斷是否結(jié)束游戲
if (isEnd) {
// 設(shè)置畫筆顏色為紅色
g.setColor(Color.RED);
// 設(shè)置字體 微軟雅黑 加粗 62號(hào)
g.setFont(new Font("微軟雅黑", 0, 62));
// 繪制GAME OVER字樣
g.drawString("GAME OVER", 60, 150);
// 設(shè)置字體 微軟雅黑 加粗 40號(hào)
g.setFont(new Font("微軟雅黑", 0, 40));
// 繪制得分
g.drawString("得分:" + score, 80, 230);
// 繪制用時(shí)
g.drawString("用時(shí):" + String.format("%02d", min) + ":" + String.format("%02d", sec), 80, 280);
} else {
// 設(shè)置字體 微軟雅黑 加粗 20號(hào)
g.setFont(new Font("微軟雅黑", Font.BOLD, 20));
// 設(shè)置畫筆顏色為黑色
g.setColor(Color.BLACK);
// 繪制時(shí)間顯示框
g.fillRect(100, 8, 80, 30);
// 繪制分?jǐn)?shù)顯示框
g.fillRect(400, 8, 50, 30);
// 設(shè)置畫筆顏色為紅色
g.setColor(Color.RED);
// 繪制時(shí)間提示標(biāo)簽
g.drawString("時(shí)間:", 50, 30);
// 繪制時(shí)間
g.drawString(String.format("%02d", min) + ":" + String.format("%02d", sec), 110, 30);
// 繪制分?jǐn)?shù)提示標(biāo)簽
g.drawString("分?jǐn)?shù):", 350, 30);
// 繪制分?jǐn)?shù)
g.drawString(String.format("%03d", score) + "", 405, 30);
// 繪制外層矩形框
g.drawRect(sx, sy, rw, rw);
// 繪制水平10個(gè),垂直10個(gè)方格。 即水平方向9條線,垂直方向9條線, 外圍四周4條線已經(jīng)畫過了,不需要再畫。 同時(shí)內(nèi)部64個(gè)方格填寫數(shù)字。
for (int i = 1; i < 10; i++) {
// 繪制第i條豎直線
g.drawLine(sx + (i * w), sy, sx + (i * w), sy + rw);
// 繪制第i條水平線
g.drawLine(sx, sy + (i * w), sx + rw, sy + (i * w));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 繪制按鈕顯示和隱藏
*
* @param i
* @param j
*/
private void drawButton(int i, int j) {
if (map[i][j] != 0) {
btnMap[i][j].setVisible(true);
} else {
btnMap[i][j].setVisible(false);
}
}
/**
* 比較兩次點(diǎn)擊的按鈕對(duì)應(yīng)的數(shù)字
*
* @param cj
* @param ci
*/
private void compare(int cj, int ci) {
/**
* 如果cc是1,表示當(dāng)前一共選中了一個(gè)方格,用px,py來記住這個(gè)方格的位置; 否則,表示現(xiàn)在選中的這個(gè)方格要與之前選中的方案比較,決定是否要?jiǎng)h除
*/
if (cc == 1) {
pj = cj;
pi = ci;
printMap(ci, cj);
// 將所點(diǎn)擊的方格背景設(shè)置為灰色
btnMap[ci][cj].setBackground(Color.LIGHT_GRAY);
drawButton(ci, cj);
} else {// 此時(shí),cc肯定是大于1的,表示要比較兩個(gè)方格的值是否相同
printMap(ci, cj);
map = MapTool.removed(map, pi, pj, ci, cj);// 讓MapTool類的remove方法去判斷上一次所選的(px,py)處的方格值與本次選擇的(cx,cy)處的方格值是否可以消掉
// 處理第一個(gè)方格
btnMap[ci][cj].setBackground(Color.WHITE);
drawButton(ci, cj);
// 處理第二個(gè)方格
btnMap[pi][pj].setBackground(Color.WHITE);
drawButton(pi, pj);
cc = 0;// 將cc的值復(fù)位
if (map[pi][pj] == map[ci][cj]) {
score += 10;
}
isEnd = isEnd(map);
// 游戲結(jié)束
if (isEnd) {
// 關(guān)閉定時(shí)器
timer.stop();
// 隱藏剩余的按鈕
for (int i = 0; i < map.length; i++) {
for (int j = 0; j < map[i].length; j++) {
if (map[i][j] != 0) {
btnMap[i][j].setVisible(false);
}
}
}
// 創(chuàng)建添加重新開始按鈕
restart = new JButton("重新開始");
restart.setBackground(Color.WHITE);
restart.setBounds(180, 350, 120, 40);
restart.setBorder(BorderFactory.createRaisedBevelBorder());
restart.setFocusPainted(false);
restart.setForeground(Color.RED);
restart.setFont(new Font("微軟雅黑", 0, 20));
restart.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
start();
}
});
this.add(restart);
repaint();
}
}
repaint();
}
/**
* 打印網(wǎng)格數(shù)據(jù)
*
* @param ci
* @param cj
*/
private void printMap(int ci, int cj) {
if (ci == pi && cj == pj) {
System.out.println("ci:" + ci + ", cj:" + cj);
} else {
System.out.println("ci:" + ci + ", cj:" + cj + ", pi:" + pi + ", pj:" + pj);
}
for (int i = 0; i < map.length; i++) {
for (int j = 0; j < map[i].length; j++) {
if (ci == pi && cj == pj) {
System.out.print(((ci == i && cj == j) ? "[" + map[i][j] + "]" : " " + map[i][j] + " ") + " ");
} else {
System.out.print(
((ci == i && cj == j || pi == i && pj == j) ? "[" + map[i][j] + "]" : " " + map[i][j] + " ")
+ " ");
}
}
System.out.println();
}
}
}
下面是GameFrame.java,定義游戲窗體
package com.feonix;
import javax.swing.JFrame;
/**
*
* 程序入口
*
*/
public class GameFrame extends JFrame {
private static final long serialVersionUID = 1L;
GamePanel panel;
/**
* DrawSee構(gòu)造方法
*/
public GameFrame() {
// 設(shè)置窗體標(biāo)題
setTitle("數(shù)字連連消");
// 設(shè)置窗體位置和大小
setBounds(100, 100, 515, 520);
// 設(shè)置窗體不能改變大小
setResizable(false);
// 設(shè)置窗體居中顯示
setLocationRelativeTo(null);
// 設(shè)置窗體關(guān)閉即退出
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new GamePanel();
add(panel);
// 最后顯示窗體
setVisible(true);
}
/**
* 啟動(dòng)游戲
*/
public void start() {
panel.start();
}
}
最后是Main.java,游戲程序的入口
package com.feonix;
public class Main {
public static void main(String[] args) {
new GameFrame().start();
}
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
MyBatis參數(shù)處理實(shí)現(xiàn)方法匯總
這篇文章主要介紹了MyBatis參數(shù)處理實(shí)現(xiàn)方法匯總,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08
Springboot連接數(shù)據(jù)庫及查詢數(shù)據(jù)完整流程
今天給大家?guī)淼氖顷P(guān)于Springboot的相關(guān)知識(shí),文章圍繞著Springboot連接數(shù)據(jù)庫及查詢數(shù)據(jù)完整流程展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下2021-06-06
Mybatis的Mapper代理對(duì)象生成及調(diào)用過程示例詳解
這篇文章主要為大家介紹了Mybatis的Mapper代理對(duì)象生成及調(diào)用過程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09
spring+mybatis 通過@ResponseBody返回結(jié)果中文亂碼的解決方法
下面小編就為大家分享一篇spring+mybatis 通過@ResponseBody返回結(jié)果中文亂碼的解決方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2017-12-12
使用Java接收和處理OpenTelemetry數(shù)據(jù)的完整指南
在現(xiàn)代分布式系統(tǒng)中,OpenTelemetry 成為了一種常見的標(biāo)準(zhǔn),用于跟蹤和監(jiān)控應(yīng)用程序的性能和行為,OTLP是 OpenTelemetry 社區(qū)定義的一種數(shù)據(jù)傳輸協(xié)議,文將介紹如何使用 Java 編寫代碼來接收和處理 OTLP 數(shù)據(jù),需要的朋友可以參考下2024-04-04
如何讓W(xué)in10實(shí)現(xiàn)Java文件的開機(jī)自啟動(dòng)
這篇文章主要介紹了如何讓W(xué)in10實(shí)現(xiàn)Java文件的開機(jī)自啟動(dòng),對(duì)于一些想要一直運(yùn)行的Java文件,就會(huì)造成每次系統(tǒng)更新之后的重啟導(dǎo)致Java文件無法繼續(xù)運(yùn)行。,需要的朋友可以參考下2019-06-06
Spring Boot 實(shí)現(xiàn)Restful webservice服務(wù)端示例代碼
這篇文章主要介紹了Spring Boot 實(shí)現(xiàn)Restful webservice服務(wù)端示例代碼,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-11-11

