記憶翻牌JAVA小遊戲

前言

大學時期做的JAVA小遊戲

圖片是從當時喜歡的遊戲抓的

順便推廣不是很讚嗎

遊戲概念

在每場遊戲開始會給予時間讓玩家看清每張圖片的位置
盡可能在最短時間內將對應的圖片湊齊,即可通關

遊戲規則

  1. 全部圖片共有36張圖,遊戲關卡有3關,有分一般和極限模式
  2. 每局遊戲開始前會先讓玩家看「現在關卡 = 觀看秒數」記圖片位置
  3. 翻錯圖片時,錯誤圖片會停留 1 秒讓玩家看
  4. 猜對得 1000分,猜錯扣 100分

遊戲介面

剛打開會像這樣子

之後關卡圖片數量會增加,通關後會出現這個

最後關卡會長這樣子

還有極限模式可以選

程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import sun.audio.*; //import the sun.audio package
import java.io.*;
import java.applet.*;

public class memorycard extends JFrame implements Runnable
{


private ButtonHandler baf = new ButtonHandler(); //功能表單事件
private JMenuBar jmb;

private int row = 4 ;
private int col = 4;
private int LK_SEC = 1; //設定一開始可看幾秒
private int add = 1000, dec = 100; //得分1000 扣分100
private int LimPoint; //極限模式目標分數與秒數
private long LimSec;


private int sec = 1; //設定翻開的牌不相同會蓋回去的秒速
private int imgH = 0,imgW =0,score = 0; //imgH圖高,imgW圖寬,score分數
private int count = 0; //正確的對數
private long startTime =0; //遊戲開始的計時
private int level ; //關卡等級


private JMenu game = new JMenu("遊戲設定"),other = new JMenu("其他資訊");
private JTextField usedtime; //遊戲經過時間
private JTextField stage ; //遊戲關卡數

private JMenuItem [] gm = new JMenuItem[5]; //遊戲設定選項格
private JMenuItem [] oth = new JMenuItem[2]; //其他選項格

private JPanel jpl;
private JLabel jl = new JLabel("分數 : 0");
private int [] m; //存放每次重新玩的圖片順序
private int [] twoImg = {-1,-1}; //記錄目前翻開的兩張圖編號
private int [] btnIndex = {-1,-1}; //記錄被翻開兩張圖的按鈕位置
private JButton [] imgbtn; //圖片按鈕
private ImageIcon []img ; //存放圖物件
private boolean [] imgShow; //記錄已配對成功過的圖
private boolean [] btnDown; //記錄被按過的按鈕
private boolean isChange = false; //用來確認是否切換存放兩張圖順序
private boolean isStart = false; //確認是否開始
private boolean Limplay = false; //確認是否極限模式




public memorycard(int mul,int L)
{
super("記憶翻牌");
level = L;
LK_SEC = level;
if(L==1)
row = col = 2;
else if(L == 2)
row = col = 4;
else if(L == 3)
row = col = 6;

LimPoint = (row*col*500);
LimSec = (row*col/2)+2;
if(mul == 1)
Limplay=true;



imgbtn = new JButton[row * col];
img = new ImageIcon[row * col];
imgShow = new boolean[row*col/2];
btnDown = new boolean [row*col];

jpl = new JPanel(new GridLayout(row,col,0,0));
Container c = getContentPane();
c = this.getContentPane();
jmb = new JMenuBar();
this.setJMenuBar(jmb); //加入工具列
usedtime = new JTextField(); //遊戲時間
usedtime.setEditable(false);
stage = new JTextField("Round "+ level +":"); //關卡名稱
stage.setEditable(false);





setLocation(200,50);
for(int i = 0; i < img.length; i++) //初始化所有按鈕上的圖,預設為不可以按
{
img[i] = new ImageIcon(getClass().getResource("images/p0.jpg"));
imgbtn[i] = new JButton(img[i]);
imgbtn[i].addActionListener(baf);
imgbtn[i].setEnabled(false);
jpl.add(imgbtn[i]);
jpl.add(jl);
}

c.add(jpl,BorderLayout.CENTER);
c.add(jl,BorderLayout.SOUTH); //將分數label放到最下面
c.add(stage,BorderLayout.NORTH);

//遊戲設定的選擇項目
jmb.add(game);
gm[0] = new JMenuItem("開始遊戲");
gm[1] = new JMenuItem("重新遊戲");
gm[1].setEnabled(false);
gm[2] = new JMenuItem("離開遊戲");
if(level == 3)
{
gm[3] = new JMenuItem("前往下關");
gm[3].setEnabled(false);
}
else
gm[3] = new JMenuItem("前往下關");

gm[4] = new JMenuItem("極限模式");

game.add(gm[0]);
game.add(gm[1]);
game.add(gm[3]);
if(mul == 0)
game.add(gm[4]);
game.addSeparator(); //加入分隔線
game.add(gm[2]);

//其他的選擇項目
jmb.add(other);
oth[0] = new JMenuItem("遊戲規則");
oth[1] = new JMenuItem("關於作者");

other.add(oth[0]);
other.add(oth[1]);


//設定視窗
imgH = img[0].getIconHeight() * row; //取得圖片高度
imgW = img[0].getIconWidth() * col; //取得圖片寬度
setSize(imgW,imgH);

setResizable(false); //視窗放大按鈕無效
setVisible(true);
setIconImage(new ImageIcon("images/iconFrame.png").getImage()); //視窗預設圖示更改
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //關閉事件

//註冊功能表單傾聽者
for(int m=0;m<gm.length;m++)
gm[m].addActionListener(baf);
oth[0].addActionListener(baf);
oth[1].addActionListener(baf);
}
//功能表單事件處理
private class ButtonHandler implements ActionListener
{
public void actionPerformed(ActionEvent ae) //按鈕事件
{

for(int i = 0; i < img.length; i++)
{
if(ae.getSource() == imgbtn[i])
{
checkIsRight(i,imgIndex(m[i]));
break;
}
}

if(ae.getSource() == gm[0]) //開始遊戲
{
replay(Limplay,level);
}
else if(ae.getSource() == gm[1]) //重新遊戲
{
replay(Limplay,level);
}
else if(ae.getSource() == gm[2]) //結束遊戲
{
System.exit(0);
}
else if(ae.getSource() == gm[3]) //前往下關
{
if(level == 3)
level = 1;
else if(level < 3)
level++;
new memorycard(0,level);
}
else if(ae.getSource() == gm[4]) //極限模式
{
new memorycard(1,level);

}
else if(ae.getSource() == oth[0]) //規則說明
{
if(Limplay == false)
{
JOptionPane.showMessageDialog(jpl,
"1.圖片為 " + row + " 乘 " + col +" ,本關共有 " + (row * col) + " 個按鈕\n" +
"2.一開始會讓玩家看 " + LK_SEC + " 秒記圖片\n"+
"3.翻錯圖片時,錯誤圖片會停留 " + sec+ " 秒讓玩家記\n"+
"4.猜對得 " + add + " 分,猜錯扣 " + dec +" 分\n" +
"5.關卡名稱顯示在左上方,關卡分數顯示在左下方\n" +
"6.全部共有三關" ,
"遊戲說明",JOptionPane.PLAIN_MESSAGE,new ImageIcon(getClass().getResource("images/BattleIcon.png")));
}
else
{
JOptionPane.showMessageDialog(jpl,
"請努力達成以下條件:\n" +
"1.目標分數為滿分 〔 " + LimPoint + " 〕 分\n"+
"2.目標完成時間為 〔 " + LimSec+ " 〕 秒\n"+
"3.只要猜錯一次就會失敗\n" +
"4.以上兩個目標皆完成才會出現通關視窗\n",
"極限關卡",
JOptionPane.PLAIN_MESSAGE,new ImageIcon(getClass().getResource("images/BatLim.png")));

}
}
else if(ae.getSource() == oth[1]) //作者資訊與素材來源
{
JOptionPane.showMessageDialog(jpl,
"程式設計與介面修改:陳煜仁\n"+
"素材取得來源:https://granbluefantasy.jp/\n"+
"此程式僅用於學術研究,參考許多網路上資料完成\n",
"作者資訊",
JOptionPane.PLAIN_MESSAGE,new ImageIcon(getClass().getResource("images/ProgIcon.png")));
}
}
}

//回傳一個存放1~N數值亂數陣列
private int [] rand(int N)
{
int temp [] = new int[N];

for(int i = 0; i < N; i++)
{
temp[i] = i;
}
for(int i = 0; i < N; i++)
{
int j = (int) (Math.random() * N);
int tmp = temp[i];
temp[i] = temp[j];
temp[j] = tmp;
}
return temp;
}

//將記錄的圖片索引值0~N轉換為1~(N/2+1)
private int imgIndex(int n)
{
return ((n/2)+1);
}

//開始(重玩)遊戲
private void replay(boolean lm,int lev)
{
stage.setText("Round "+ lev+":");
startTime = System.currentTimeMillis();
gm[0].setEnabled(false);
if(lm == true)
gm[4].setEnabled(false);
gm[1].setEnabled(true);
m = rand(row*col); //取得按鈕下次重排的圖案順序


for(int i = 0; i < img.length; i++) //設定所有圖片為可以翻狀態
{
imgbtn[i].setEnabled(true);
imgbtn[i].setIcon(new ImageIcon(getClass().getResource("images/" + imgIndex(m[i]) + ".jpg")));
}
twoImg[0] = twoImg[1] = btnIndex[0] = btnIndex[1] = -1; //清除記錄兩張翻開圖片按鈕與位置
isChange = false; //重設翻牌順序
score = 0; //分數歸零
jl.setText("分數 : " + score); //更新顯示分數
count=0;
isStart = false;

new Thread(new Runnable()
{
public void run()
{
try
{
Thread.sleep(LK_SEC * 1000);
}catch(InterruptedException e){}
//將圖面改為預設圖,並設定無法按按鍵
for(int i = 0; i < img.length; i++)
{
img[i] = new ImageIcon(getClass().getResource("images/p0.jpg"));
imgbtn[i].setIcon(img[i]);
btnDown[i] = false; //將記錄過的按鈕清除
}
isStart = true;
}
}).start();

//清除上局存放配對成功的圖片位置
for(int i = 0; i < imgShow.length; i++)
imgShow[i] = false;
}
//檢查是目前兩張圖是否配對
private void checkIsRight(int btnN, int jpgNum)
{
if(!isStart) return; //判斷是否已讓玩家看完圖片排列,再開始
if(btnDown[btnN]) return; //如果按下的圖片已翻開,就離開function
btnDown[btnN] = true; //表示此按鈕已翻開狀態

imgbtn[btnN].setIcon(new ImageIcon(getClass().getResource("images/" + jpgNum + ".jpg")));

//記錄上張與目前圖片編號、按鈕位置twoImg[1]是上一張,twoImg[0]是目前
int temp = twoImg[0];
int btnTemp = btnIndex[0];

twoImg[0] = jpgNum;
btnIndex[0] = btnN;
twoImg[1] = temp;
btnIndex[1] = btnTemp;

if(isChange)
{
if(imgShow[jpgNum-1])
return; //若已配對成功
if(twoImg[1] == twoImg[0])
{
imgShow[jpgNum-1] = true; //記錄已配對的圖片索引值
twoImg[1] = -1;
btnIndex[1] = -1;
isChange = false;
count++; //正確對數增加
score += add; //配對成功分數增加
jl.setText("分數 : " + score); //更新分數

if(count == row*col/2)
{
Long t =((System.currentTimeMillis()-startTime)/1000);
usedtime.setText(((System.currentTimeMillis()-startTime)/1000)+"");
if(Limplay == false)
{
JOptionPane.showMessageDialog(jpl,
"恭喜通關!\n" +
"你本次遊戲花了【 " + usedtime.getText() + " 】秒\n"+
"在這一關獲得總分數為【 "+score+" 】分!!",
"關卡訊息",
JOptionPane.PLAIN_MESSAGE,new ImageIcon(getClass().getResource("images/icon.png")));

}
else
{
if(LimPoint == score && LimSec >= t)
{
JOptionPane.showMessageDialog(jpl,
"超越極限!!!\n" +
"你的翻牌沒有絲毫猶豫!竟然只花了【 " + usedtime.getText() + " 】秒\n"+
"沒有任何錯誤的通關了! 恭喜你!",
"極限關卡",
JOptionPane.PLAIN_MESSAGE,new ImageIcon(getClass().getResource("images/LimIcon1.png")));
}
else
{
int x =JOptionPane.showConfirmDialog(jpl, "可惜...\n你還沒達成所有條件....\n" +
你本次遊戲花了【 " + usedtime.getText() + " 】秒\n你獲得分數為【 "+score+" 】分\n"+
"你還想要繼續挑戰嗎?",
"極限關卡", JOptionPane.OK_CANCEL_OPTION,JOptionPane.INFORMATION_MESSAGE);

if(x ==JOptionPane.YES_OPTION)
{
replay(Limplay,level);
}
}
}

}
return;
}
//設定翻開兩張圖片時,其他圖片不能翻
for(int i = 0; i < btnDown.length; i++)
if(!btnDown[i]) imgbtn[i].setEnabled(false);
new Thread(this).start();
}
isChange = !isChange;
}
public void run ()
{
try{
Thread.sleep(sec * 1000);
}catch(InterruptedException e){}

//蓋住原本翻開的圖片
btnDown[btnIndex[0]] = false;
btnDown[btnIndex[1]] = false;
imgbtn[btnIndex[0]].setIcon(new ImageIcon(getClass().getResource("images/p0.jpg")));
imgbtn[btnIndex[1]].setIcon(new ImageIcon(getClass().getResource("images/p0.jpg")));

//設定蓋回兩張翻開圖片時,其他圖片可以回復可以翻的狀態
for(int i = 0; i < btnDown.length; i++)
if(!btnDown[i]) imgbtn[i].setEnabled(true);

score -= dec; //猜錯扣分
jl.setText("分數 : " + score);
}

public static void main(String [] args)
{
new memorycard(0,1);
}
}